Преобразовать перекрывающиеся диапазоны дат в ряды дат - PullRequest
0 голосов
/ 12 ноября 2018

У меня есть список диапазонов дат в таблице, которая может быть открыта и завершена (enddate = null):

Index   startdate   enddate
1       2018-07-13  NULL
2       2018-11-14  2018-11-16
3       2018-11-15  2018-11-15

Запрос данных теста:

DECLARE @ScheduleTable Table([Index] int not null, StartDate DateTime not null, EndDate DateTime null)
insert into @ScheduleTable ([Index], StartDate, EndDate)
values
(1,'2018-07-13',null)
, (2,'2018-11-14','2018-11-16')
, (3,'2018-11-15','2018-11-15')
select*from @ScheduleTable

Как я могунапишите запрос, который «заполнит дыры» и вернет следующие результаты:

Index   startdate   enddate
1       2018-07-13  2018-11-13
2       2018-11-14  2018-11-14
3       2018-11-15  2018-11-15
2       2018-11-16  2018-11-16
1       2018-11-17  NULL

Запрос отображения ожидаемых результатов:

select 
1 as [Index], '2018-07-13' as StartDate, '2018-11-13' as EndDate
UNION ALL
select 
2 as [Index], '2018-11-14', '2018-11-14'
UNION ALL
select 
3 as [Index], '2018-11-15', '2018-11-15'
UNION ALL
select 
2 as [Index], '2018-11-16', '2018-11-16'
UNION ALL
select 
1 as [Index], '2018-11-17', null

Я бы предпочел ответ, который не включает параметры / временную таблицу и т. Д. У меня есть таблица Date Dimension, если это поможет.

В приведенном выше примере запись с Index = 1 является открытой иначинается 7.13.Прервано Index = 2 11.14.Index = 2 затем прерывается Index = 3 11.15.Index = 2, затем начинается снова 11.16.Затем следует индекс = 1, снова запускаемый 11,17Индекс определяет порядок предпочтений, поэтому Индекс = 2 переопределит Индекс = 1 11,14 - 11,16, а Индекс = 3 переопределит Индекс = 2 11,15.Вот мой текущий запрос с использованием lead ():

DECLARE @MinDate DateTime = '2015-01-01'
DECLARE @MaxDate DateTime = '2020-01-01'

select
row_number() over(partition by dealid order by ss.StartDate, ss.id) as [Index]
, ss.startdate
, ss.enddate
, case when ss.enddate is null then
    dateadd(d,-1,lead(ss.startdate,1,@MaxDate) over(partition by dealid order by ss.startdate, ss.id)) 
    else ss.enddate end
    as EndDate
from
[dbo].[Schedule]ss
where ss.enabled = 1

1 Ответ

0 голосов
/ 13 ноября 2018

Я смог решить проблему, используя следующее:

Шаги:

  • Получить таблицу дат из таблицы DateDimension
  • Присоединение расписаний к таблице DateDimension
  • row_number графиков, чтобы определить, какой из них имеет приоритет для данной даты
  • результаты ранжирования, упорядочены по дате
  • плотных результатов, разделение по идентификатору расписания, упорядочение по дате
  • вычтите результаты density_rank из результатов ранга, чтобы создать уникальный идентификатор для каждой группы непрерывных дат
  • Получение минимальной и максимальной даты для каждого диапазона дат

Запрос на заполнение тестовых данных:

DECLARE @ScheduleTable Table([Index] int not null, StartDate DateTime not null, EndDate DateTime null)
insert into @ScheduleTable ([Index], StartDate, EndDate)
values
(1,'2018-07-13',null)
, (2,'2018-11-14','2018-11-16')
, (3,'2018-11-15','2018-11-15')

Решение:

DECLARE @MinDate Date = dateadd(year,-2,getdate())
DECLARE @MaxDate DateTime = dateadd(year,2,getdate())

select 
min(dt) as StartDate
, max(dt) as EndDate
, dense_rank() over(Order by [Index]) [Index]
from
(
select
--Create "groups" using a raw Rank minus dense_rank, partitioned by [Index]
rank() over(order by dt) - dense_rank() over(partition by [Index] order by dt) qlt,
[Index], dt
from
(
select
--Apply row_number to identify which schedule takes precedence on a given day
--Index=2 takes precedence over Index=1
row_number() over(partition by inr.[date] order by ss.[Index] desc) rm,
[date] dt
, ss.*
from
(
    --Obtain Table of Dates from DateDimension table
    select
    [date]
    from
    [dbo].[DateDimension]dd
    where dd.[date] >= @MinDate
    and dd.[date] <= @MaxDate
)inr
    --join schedules to DateDimension table
    left join 
    (
        select *
        from
        @ScheduleTable
    )ss
        on ss.StartDate <= inr.[date]
        and (ss.enddate >= inr.[date]
            or ss.enddate is null)

)inr2
--Exclude any Schedule that is not row_number=1
where inr2.rm = 1
and inr2.[Index] is not null
)inr3
--Group on Index first then Rank minus dense_rank, partitioned by [Index]
group by [Index], qlt
order by StartDate
, [Index]

Результаты:

StartDate   EndDate     Index
2018-07-13  2018-11-13  1
2018-11-14  2018-11-14  2
2018-11-15  2018-11-15  3
2018-11-16  2018-11-16  2
2018-11-17  2020-11-12  1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...