суммировать даты из списка дат - PullRequest
2 голосов
/ 09 мая 2019

У меня есть таблица, содержащая столбец идентификатора и столбцы даты начала и окончания действия.Для каждого идентификатора доступно несколько диапазонов дат действия.

Я хочу свести к минимуму записи и сделать одну строку для каждого набора последовательных дат, где это возможно.

    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 ]

2 голосов
/ 09 мая 2019

Это проблема пробелов и островков.Но это касается (потенциально) перекрывающихся интервалов.Для общего решения я рекомендую:

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;

Здесь - это дБ <> скрипка.

Это надежное решение для таких ситуаций, как:

  • Перекрываются более одного дня.
  • Полное включение одного интервала в другой.
0 голосов
/ 09 мая 2019

Я не нашел другой возможности, кроме как использовать CURSOR. Теперь вы можете проверить новый вывод, указанный ниже, с вашими новыми предоставленными данными. Мне вывод кажется правильным.

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

Новый вывод -

cid st_date     end_date
1   20190110    20190123
2   20190101    20190117
2   20190119    20190127
2   20190201    20190210
0 голосов
/ 09 мая 2019

Для каждого cid вы генерируете самую раннюю дату начала и самую позднюю дату окончания.

SELECT cid, MIN(st_date) as st_date, MAX(end_date) as end_date
FROM @tbl
GROUP BY cid
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...