sql - 如何合并窗口内的重叠时间?

标签 sql sql-server sql-server-2008 tsql

我有一张这样的表:

CREATE TABLE #TEMP (Name VARCHAR(255), START_TIME datetime, END_TIME datetime);

INSERT INTO #TEMP VALUES('John', '2012-01-01 09:00:01', '2012-01-01 12:00:02')
INSERT INTO #TEMP VALUES('John', '2012-01-01 09:40:01', '2012-01-01 11:00:02')
INSERT INTO #TEMP VALUES('John', '2012-01-02 05:00:01', '2012-01-02 05:15:02')
INSERT INTO #TEMP VALUES('David', '2012-01-04 05:00:01', '2012-01-04 05:15:02')
INSERT INTO #TEMP VALUES('David', '2012-01-05 07:01:01', '2012-01-05 15:15:02')

SELECT *
FROM #TEMP

DROP TABLE #TEMP

数据是:
     Name   START_TIME                 END_TIME
1    John   2012-01-01 09:00:01.000    2012-01-01 12:00:02.000
2    John   2012-01-01 09:40:01.000    2012-01-01 11:00:02.000
3    John   2012-01-02 05:00:01.000    2012-01-02 05:15:02.000
4    David  2012-01-04 05:00:01.000    2012-01-04 05:15:02.000
5    David  2012-01-05 07:01:01.000    2012-01-05 08:15:02.000

给定一个数字,比如 6,我正在尝试做一个 GROUP BY在此表上并合并时间在前后 6 小时的窗口内重叠。因此,在上表中,行 12将合并为一行,因为它们包含重叠的时间范围:
John 2012-01-01 06:00:01.000 2012-01-01 18:00:02.000

45将被合并,因为从 07:01:01.000 中减去 6 小时落入行窗口4 .

在包含大约一百万行的大表上是否有这样做的好方法?

最佳答案

我认为最好的方法是创建一个 windows table 并将#temp 表与这个新的窗口表连接起来:

1)步骤1,准备窗口表,所有可能的窗口间隙(包含重叠窗口):

   SELECT 
      Name,
      dateadd(hour, -6, start_time) as start_w, 
      dateadd(hour, +6, start_time) as end_w
   into #possible_windows
   FROM #TEMP 

2)在临时表上创建索引以提高性能
   create index pw_idx on #possible_windows ( Name, start_w)

3) 消除自连接选择中的重叠窗口。这是创建索引的原因:
   select p2.* 
   into #myWindows
   from #possible_windows p1
   right outer join #possible_windows p2
     on p1.name = p2.name and 
        p2.start_w > p1.start_W and p2.start_w <= p1.end_w
   where p1.name is null

4) 使用#myWindows 加入您的表或直接使用它。

工作:
SELECT 
  Name,
  dateadd(hour, -6, start_time) as start_w, 
  dateadd(hour, +6, start_time) as end_w,
  ROW_NUMBER() over(partition by Name order by Name, 
                    dateadd(hour, -6, start_time) ) as rn
into #possible_windows
FROM #TEMP 

create index pw_idx on #possible_windows ( Name, start_w)

select p2.* 
from #possible_windows p1
right outer join #possible_windows p2
  on p1.name = p2.name and 
     p2.start_w > p1.start_W and p2.start_w <= p1.end_w
where p1.name is null

结果:
Name  start_w       end_w         rn 
----- ------------- ------------- -- 
David 2012-01-03 23:00:012012-01-04 11:00:011  
David 2012-01-05 01:01:012012-01-05 13:01:012  
John  2012-01-01 03:00:012012-01-01 15:00:011  
John  2012-01-01 23:00:012012-01-02 11:00:013 

PE:请返回进行性能测试!

关于sql - 如何合并窗口内的重叠时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10562321/

相关文章:

sql - 如何在 SQL Server 中使用存储过程合并第三个表中的两个数据表?

sql - 查询一个二进制 (1) 字段或 8 位字段更快?

SQL:根据不同的 WHERE 条件两次选择相同的表列

sql-server-2008 - SSIS API : How does one know what Interface to cast a __COMObject to?

sql - sys.dm_exec_procedure_stats - 我解释正确吗

sql - MySQL SELECT n条记录基于GROUP BY

mysql - 哪些索引应该有一个表来快速执行大型 SQL 查询?

c# - 添加页码参数时,Report Services 在本地报告的 visual studio 调试器中崩溃

sql-server-2008 - T-SQL : CTE with identity columns

sql - 为什么 SQL 成本会因为简单的 "or"而爆炸?