从日期列表中总结日期

时间:2019-05-09 16:30:49

标签: sql sql-server tsql

我有一个表,其中包含一个id列以及有效期开始和结束日期列。 每个ID有多个有效日期范围。

我想最小化记录,并在可能的情况下为每组顺序日期排成一行。

    declare @tbl table (cid int, st_date int, end_date int )


    insert into @tbl  (cid, st_date,end_date)  
    values (1,20190110,20190111),  
    (1,20190111,20190117), 
    (1,20190117,20190123), 
    (2,20190101,20190117), 
    (2,20190119,20190123),
    (2,20190123,20190127)

必需的输出:

cid    st_date      end_date

  1    20190110     20190123

  2    20190101     20190117

  2    20190119     20190127

3 个答案:

答案 0 :(得分:2)

这是一个孤岛问题。但是它正在处理(可能)重叠的间隔。对于一般的解决方案,我建议:

select cid, min(st_date) as st_date, max(end_date) as end_date
from (select t.*,
             sum(case when max_prev_ed >= st_date then 0 else 1 end) over (partition by cid order by st_date) as grp
      from (select t.*, max(end_date) over (partition by cid order by st_date rows between unbounded preceding and 1 preceding) as max_prev_ed
            from @tbl t
           ) t
     ) t
group by cid, grp;

Here是db <>小提琴。

这是针对以下情况的可靠解决方案:

  • 重叠超过一天。
  • 将一个间隔完全包含在另一个间隔中。

答案 1 :(得分:0)

您将为每个cid生成最早的开始日期和最晚的结束日期。

SELECT cid, MIN(st_date) as st_date, MAX(end_date) as end_date
FROM @tbl
GROUP BY cid

答案 2 :(得分:0)

除了使用CURSOR,我没有其他选择。现在,您可以使用提供的新数据检查下面列出的新输出。对我来说,输出似乎是正确的。

UserPost

新输出为-

DECLARE @tbl TABLE (cid INT, st_date INT, end_date INT )
DECLARE @tmp TABLE (cid INT, st_date INT, end_date INT, gid INT )

DECLARE @gid INT
SET @gid = 1

INSERT INTO @tbl (cid, st_date,end_date) 
VALUES 
(1,20190110,20190111), 
(1,20190111,20190117), 
(1,20190117,20190123), 
(2,20190101,20190117), 
(2,20190119,20190123), 
(2,20190123,20190127), 
(2,20190201,20190205), 
(2,20190205,20190210)

DECLARE @cid INT, @st_date INT, @end_date INT,@B_cid INT,@B_st_date INT

DECLARE vendor_cursor CURSOR FOR   
SELECT A.cid,A.st_date,A.end_date,B.cid B_cid,B.st_date B_st_date
FROM
(
    SELECT ROW_NUMBER() OVER (ORDER BY CID,st_date,end_date) RN,* 
    FROM 
    (
        SELECT CID,CONVERT(varchar, st_date, 23) st_date,CONVERT(varchar, end_date, 23) end_date FROM @tbl
    )X
)A
LEFT JOIN (
    SELECT ROW_NUMBER() OVER (ORDER BY CID,st_date,end_date)-1 RN,* 
    FROM 
    (
        SELECT CID,CONVERT(varchar, st_date, 23) st_date,CONVERT(varchar, end_date, 23) end_date FROM @tbl
    )Y
)B
ON A.RN = B.RN
ORDER BY 1,2

OPEN vendor_cursor  
FETCH NEXT FROM vendor_cursor   
INTO @cid, @st_date,@end_date,@B_cid,@B_st_date  

WHILE @@FETCH_STATUS = 0  
BEGIN

    IF  (@cid = @B_cid) AND (@end_date = @B_st_date)
    BEGIN

        INSERT INTO @tmp (cid, st_date,end_date,gid) 
        VALUES 
        (@cid,@st_date,@end_date,@gid)

    END

    ELSE
    BEGIN
        INSERT INTO @tmp (cid, st_date,end_date,gid) 
        VALUES 
        (@cid,@st_date,@end_date,@gid)

        SET @gid = @gid +1
    END

    FETCH NEXT FROM vendor_cursor   
    INTO @cid, @st_date,@end_date,@B_cid,@B_st_date   
END   
CLOSE vendor_cursor;  
DEALLOCATE vendor_cursor

SELECT cid,
MIN(st_date) st_date,
MAX(end_date) end_date
FROM @tmp
GROUP BY cid,gid