2015-09-01 2 views
1

У меня есть таблица событий, которая имеет начальный и конечные столбцы даты (события не перекрываются), данные образцыЗаполнение пробелов с диапазонами дат в SQL

if object_id('tempdb..#SourceTable') is not null 
begin 
    drop table #SourceTable 
end 

create table #SourceTable 
(
    Id int identity(1,1) not null, 
    WindowRange varchar(15) not null, 
    StartDatetime datetime null, 
    EndDatetime datetime null 
) 


insert into #SourceTable 
(
    WindowRange, 
    StartDatetime, 
    EndDatetime 
) 
values 
    ('04:20 - 05:36', '2015-08-31 04:20:01.890', '2015-08-31 05:36:14.290'), 
    ('00:20 - 01:24', '2015-08-31 00:20:01.487', '2015-08-31 01:24:52.983'), 
    ('20:20 - 21:27', '2015-08-30 20:20:01.177', '2015-08-30 21:27:53.317'), 
    ('16:20 - 17:28', '2015-08-30 16:20:01.133', '2015-08-30 17:28:24.173'), 
    ('12:20 - 13:30', '2015-08-30 12:20:01.273', '2015-08-30 13:30:38.370') 

Пример вывод

Id WindowRange  StartDatetime   EndDatetime 
1 04:20 - 05:36 2015-08-31 04:20:01.890 2015-08-31 05:36:14.290 
2 00:20 - 01:24 2015-08-31 00:20:01.487 2015-08-31 01:24:52.983 
3 20:20 - 21:27 2015-08-30 20:20:01.177 2015-08-30 21:27:53.317 
4 16:20 - 17:28 2015-08-30 16:20:01.133 2015-08-30 17:28:24.173 
5 12:20 - 13:30 2015-08-30 12:20:01.273 2015-08-30 13:30:38.370 

Я хотел бы иметь дополнительные строки, заполняющие пробелы в диапазонах, для примера выше

Ожидаемый результат

Id WindowRange  StartDatetime   EndDatetime 
1 04:20 - 05:36 2015-08-31 04:20:01.890 2015-08-31 05:36:14.290 
2 01:24 - 04:20 2015-08-31 01:24:52.983 2015-08-31 04:20:01.890 
3 00:20 - 01:24 2015-08-31 00:20:01.487 2015-08-31 01:24:52.983 
4 00:00 - 00:20 2015-08-31 00:00:00.000 2015-08-31 00:20:01.487 
5 21:27 - 23:59 2015-08-30 21:27:53.317 2015-08-30 23:59:59.999 
6 20:20 - 21:27 2015-08-30 20:20:01.177 2015-08-30 21:27:53.317 
7 17:28 - 20:20 2015-08-30 17:28:24.173 2015-08-30 20:20:01.177 
8 16:20 - 17:28 2015-08-30 16:20:01.133 2015-08-30 17:28:24.173 
9 13:30 - 16:20 2015-08-30 13:30:38.370 2015-08-30 16:20:01.133 
10 12:20 - 13:30 2015-08-30 12:20:01.273 2015-08-30 13:30:38.370 

Я попытался с помощью общего табличного выражения с функцией окна, но не могу показаться, чтобы получить это право

;with myCTE as 
(
    select 
     row_number() over (order by EndDatetime desc) as SeqNo, 
     StartDatetime, 
     EndDatetime 
    from #SourceTable 
) 


select 
    t1.SeqNo as [T1SeqNo], 
    t2.SeqNo as [T2SeqNo], 
    t1.StartDatetime as [T1Start], 
    t1.EndDatetime as [T1End], 
    t2.StartDatetime as [T2Start], 
    t2.EndDatetime as [T2End] 
from myCTE t1 
left join myCTE t2 
    on t1.SeqNo = t2.SeqNo - 1 

Любое предложение/помощь будет высоко оценена.

+0

возможно дубликат [SQL Query, чтобы показать промежутки между несколькими диапазонами дат] (http://stackoverflow.com/questions/9604400/sql-query-to-show-gaps-between-multiple- диапазоны дат) – Bulat

ответ

2
DECLARE @WindowRange varchar(15), 
     @StartDatetime datetime, 
     @EndDatetime datetime, 
     @StartDate date, 
     @EndDate date, 
     @NextStartDatetime datetime, 
     @NextEndDatetime datetime 

DECLARE yourCursor CURSOR FORWARD_ONLY READ_ONLY FOR 
    SELECT StartDatetime, EndDatetime FROM #SourceTable order by StartDatetime 
OPEN yourCursor 

FETCH NEXT FROM yourCursor INTO @StartDatetime, @EndDatetime 
IF @@FETCH_STATUS = 0 
    BEGIN 
     FETCH NEXT FROM yourCursor INTO @NextStartDatetime, @NextEndDatetime 
     WHILE @@FETCH_STATUS = 0 
      BEGIN 
       SET @StartDate = @StartDatetime 
       SET @EndDate = @EndDatetime 
       IF @EndDate > @StartDate 
        BEGIN 
         SET @WindowRange = LEFT(CONVERT(varchar, @StartDatetime, 108), 5) + ' - ' + LEFT(CONVERT(varchar, @EndDate, 108), 5) 
         INSERT INTO #SourceTable (WindowRange, StartDatetime, EndDatetime) VALUES (@WindowRange, @StartDatetime, @EndDate) 


         SET @WindowRange = LEFT(CONVERT(varchar, @StartDatetime, 108), 5) + ' - ' + LEFT(CONVERT(varchar, @EndDate, 108), 5) 
         INSERT INTO #SourceTable (WindowRange, StartDatetime, EndDatetime) VALUES (@WindowRange, @EndDate, @EndDatetime) 
        END 

        SET @StartDate = @EndDatetime 
        SET @EndDate = @NextStartDatetime 

        IF @EndDate > @StartDate 
        BEGIN 
         SET @WindowRange = LEFT(CONVERT(varchar, @EndDatetime, 108), 5) + ' - ' + '00:00' [email protected] 
         INSERT INTO #SourceTable (WindowRange, StartDatetime, EndDatetime) VALUES (@WindowRange, @EndDatetime, @StartDate) 


         SET @WindowRange = '00:00' + ' - ' + LEFT(CONVERT(varchar, @NextStartDatetime, 108), 5) [email protected] 
         INSERT INTO #SourceTable (WindowRange, StartDatetime, EndDatetime) VALUES (@WindowRange, @EndDate, @NextStartDatetime) 
        END 



       SET @WindowRange = LEFT(CONVERT(varchar, @EndDatetime, 108), 5) + ' - ' + LEFT(CONVERT(varchar, @NextStartDatetime, 108), 5) 
       INSERT INTO #SourceTable (WindowRange, StartDatetime, EndDatetime) VALUES (@WindowRange, @EndDatetime, @NextStartDatetime) 
       SET @StartDatetime = @NextStartDatetime 
       SET @EndDatetime = @NextEndDatetime 
       FETCH NEXT FROM yourCursor INTO @NextStartDatetime, @NextEndDatetime 
      END 
     END 
CLOSE yourCursor; 
DEALLOCATE yourCursor; 

select * from #SourceTable order by StartDatetime 
+0

Приветствия за этот разный подход с использованием курсора, очень полезный, поскольку он дает мне представление о том, как решить проблему, хотя в нем не рассматривается проблема ограничения интервалов/пробелов в течение дня, т.е. '2015-08-30 21 : 27: 53.317 2015-08-31 00: 20: 01.487' должно быть «2015-08-30 21: 27: 53.317 \t 2015-08-30 23: 59: 59.999» и т. Д. Тем не менее +1 за помощь и усилие ! – chridam

+1

Обратите внимание на использование типа даты для удаления временной части и, таким образом, ее установку в 00:00. – user2955677

1
;with myCTE as 
(
    select 
     row_number() over (order by EndDatetime desc) as SeqNo, 
     StartDatetime, 
     EndDatetime 
    from #SourceTable 
) 

select ROW_NUMBER() over (order by T1Start DESC), * 
from (
select 
    t1.StartDatetime as [T1Start], 
    t1.EndDatetime as [T1End] 
from myCTE t1 
UNION ALL 
select 
    t1.EndDatetime as [T1Start], 
    t2.StartDatetime as [T1SEnd] 
from myCTE t1 
inner join myCTE t2 
    on t1.SeqNo = t2.SeqNo + 1 

) as t 
order by T1Start DESC 
+0

Ницца! Хотя ваше решение не дает точного ожидаемого результата, так как окна должны быть разбиты на разделы в день, поэтому не должно быть перекрывающихся диапазонов для пробелов, т.е. '2015-08-30 21: 27: 53.317 \t 2015-08-31 00:20 : 01.487' должно быть «2015-08-30 21: 27: 53.317 \t 2015-08-30 23: 59: 59.999» и т. Д. Тем не менее, я ценю помощь! +1 для усилий и идеи. – chridam

1

Я сделал код курсора SQL Server, что почти приближенный к ожидаемому результату. Разные здесь находятся на пятой записи, которую вы ожидаете «2015-08-30 23: 59: 59.999», но в SQL Server «2015-08-30 23: 59: 59.999» будет считаться «2015-09-01 00 : 00: 00,000" . Надеюсь, что эта помощь

DECLARE @temp TABLE(
    Id int identity(1,1) not null, 
    WindowRange varchar(15) not null, 
    StartDatetime datetime null, 
    EndDatetime datetime null 
) 

INSERT INTO @temp 
SELECT TOP 1 WindowRange, StartDatetime, EndDatetime 
FROM #SourceTable ORDER BY StartDateTime 

DECLARE @curStartDateTime DATETIME 
DECLARE @curEndDateTime DATETIME 

DECLARE @prevStartDateTime DATETIME 
DECLARE @prevEndDateTime DATETIME 

DECLARE @iteration INT 
SET @iteration = 0 

DECLARE @timeRange CURSOR 

SET @timeRange = CURSOR FOR 
SELECT StartDatetime, EndDatetime FROM #SourceTable ORDER BY StartDateTime 

OPEN @timeRange 

FETCH NEXT FROM @timeRange INTO @curStartDateTime, @curEndDateTime 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    IF @iteration <> 0 
    BEGIN 
     IF CONVERT(VARCHAR(8), @curStartDateTime, 112) = CONVERT(VARCHAR(8), @prevEndDateTime, 112) 
     BEGIN 
      IF CONVERT(VARCHAR(23), @curStartDateTime, 121) <> CONVERT(VARCHAR(23), @prevEndDateTime, 121) 
      BEGIN 
       INSERT INTO @temp 
       SELECT 
        CONVERT(VARCHAR(5), @prevEndDateTime, 108) + ' - ' + CONVERT(VARCHAR(5), @curStartDateTime, 108) 
        , @prevEndDateTime 
        , @curStartDateTime 
      END 
     END 
     ELSE 
     BEGIN 
      INSERT INTO @temp 
       SELECT 
        CONVERT(VARCHAR(5), @prevEndDateTime, 108) + ' - 23:59' 
        , @prevEndDateTime 
        , CONVERT(VARCHAR(8), @curStartDateTime, 112) + ' 23:59:59.999' 

      INSERT INTO @temp 
       SELECT 
        '00:00 - ' + CONVERT(VARCHAR(5), @curStartDateTime, 108) 
        , CONVERT(VARCHAR(8), DATEADD(day, 1, @prevEndDateTime), 112) + ' 00:00:00.000' 
        , @curStartDateTime 
     END 

     INSERT INTO @temp 
     SELECT 
      CONVERT(VARCHAR(5), @curStartDateTime, 108) + ' - ' + CONVERT(VARCHAR(5), @curEndDateTime, 108) 
      , @curStartDateTime 
      , @curEndDateTime 
    END 

    SET @prevStartDateTime = @curStartDateTime 
    SET @prevEndDateTime = @curEndDateTime 

    SET @iteration = @iteration + 1 
    FETCH NEXT FROM @timeRange INTO @curStartDateTime, @curEndDateTime 
END 

CLOSE @timeRange 
DEALLOCATE @timeRange 

SELECT * FROM @temp ORDER BY StartDatetime DESC 
+0

Cheers @FathirMohamad, ваш ответ был весьма полезен :-) – chridam

Смежные вопросы