SQL中的重叠时间范围

时间:2019-08-20 13:25:11

标签: sql sql-server tsql

我的表格中有以下行:

Customer  Start       End
1A        2019-01-01  2019-01-04
1A        2019-01-03  2019-01-06
1A        2019-01-06  2019-01-10
1A        2019-02-01  2019-02-07
2A        2019-03-01  2019-04-05

我需要合并表格,使其看起来像这样:

Customer  Start       End
1A        2019-01-01  2019-01-10
1A        2019-02-01  2019-02-07
2A        2019-03-01  2019-04-05

我可以在SQL中采取哪些步骤来实现这一目标?

3 个答案:

答案 0 :(得分:0)

使用DATEPART(MONTH, DATE)MIN()MAX()聚合窗口函数可以达到预期的效果:

SELECT DISTINCT Customer, 
       MIN(Start) OVER (PARTITION BY Customer, StartMonth) AS Start,
       MAX([End]) OVER (PARTITION BY Customer, EndMonth) AS [End]
FROM (
    SELECT *, DATEPART(MONTH, Start) AS StartMonth, DATEPART(MONTH, [End]) AS EndMonth
    FROM TestTable
) Q

请在db<>fiddle上找到有效的演示。

使用给定的样本数据执行样本:

DECLARE @TestTable TABLE (Customer VARCHAR(2), Start DATE, [End] DATE);

INSERT INTO @TestTable (Customer, Start, [End]) VALUES
('1A', '2019-01-01', '2019-01-04'),
('1A', '2019-01-03', '2019-01-06'),
('1A', '2019-01-06', '2019-01-10'),
('1A', '2019-02-01', '2019-02-07'),
('2A', '2019-03-01', '2019-04-05');

SELECT DISTINCT Customer, 
       MIN(Start) OVER (PARTITION BY Customer, StartMonth) AS Start,
       MAX([End]) OVER (PARTITION BY Customer, EndMonth) AS [End]
FROM (
    SELECT *, DATEPART(MONTH, Start) AS StartMonth, DATEPART(MONTH, [End]) AS EndMonth
    FROM @TestTable
) Q

答案 1 :(得分:0)

这很棘手。您正在尝试合并期间。查找重叠的一种方法是使用累积max()。然后使用它来识别组。最后使用聚合:

select customer, min(start), max(end)
from (select t.*,
             sum(case when prev_max >= start then 0 else 1 end) over  -- beginning of a new period
                  (partition by customer order by start) as grp
      from (select t.*,
                   max(end) over (partition by customer
                                  order by start
                                  rows between unbounded preceding and 1 preceding
                                 ) as prev_max_end
            from t
           ) t
     ) t
group by customer, grp;

请注意,startend都是SQL Server的保留字,因此它们对于列来说都是很不好的名字。假设您的实际列具有更合适的名称,我没有重命名或转义过它们。

答案 2 :(得分:0)

您也可以使用分组依据。如果您要存储一年以上,那么您也必须考虑这一点。试试这个

 DECLARE @TestTable TABLE (Customer VARCHAR(2), Start DATE, [End] DATE);

 INSERT INTO @TestTable (Customer, Start, [End]) VALUES
 ('1A', '2019-01-01', '2019-01-04'),
 ('1A', '2019-01-03', '2019-01-06'),
 ('1A', '2019-01-06', '2019-01-10'),
 ('1A', '2019-02-01', '2019-02-07'),
 ('2A', '2019-03-01', '2019-04-05'),
 ('1A', '2020-02-01', '2020-02-07'),
 ('2A', '2020-03-01', '2020-04-05');

 SELECT Customer, MIN(Start), MAX([End]) FROM @TestTable
 GROUP By Customer, DATEADD(MONTH, DATEDIFF(MONTH, 0, Start), 0) , 
 DATEADD(MONTH, DATEDIFF(MONTH, 0, [End]), 0)