Необходимо сгруппировать записи по последовательной дате SQL - PullRequest
1 голос
/ 07 февраля 2020

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

create table #consecutivedates (
    sgid nvarchar(max), 
    metric nvarchar(max), 
    targetvalue nvarchar(max), 
    startdate datetime, 
    enddate datetime
)

insert into #consecutivedates values 
    ('2177', '515818', '18', '2019-09-01',  '2019-09-30'),
    ('2177', '515818', '125', '2019-08-01',  '2019-08-31'),
    ('2177', '515818', '15', '2019-07-01',  '2019-07-31')

SELECT  sgid,metric, CAST(startdate AS DATE) startdate, CAST(enddate AS DATE) enddate,
        ROW_NUMBER() OVER ( ORDER BY sgid, metric, startdate ) rn
INTO    #temp
FROM    #consecutivedates

-- GroupingColumn in cte used to identify and group consecutive dates
;WITH    cte
          AS ( SELECT   sgid ,
          metric , 
                        startdate ,
                        enddate ,
                        1 AS GroupingColumn ,
                        rn
               FROM     #temp
               WHERE    rn = 1
               UNION ALL
               SELECT   t2.sgid ,
               t2.metric,
                        t2.startdate,
                        t2.enddate ,
                        CASE WHEN t2.startdate = DATEADD(day, 1, cte.enddate) 
                                  AND cte.sgid = t2.sgid AND cte.metric=t2.metric
                             THEN cte.GroupingColumn
                             ELSE cte.GroupingColumn + 1
                        END AS GroupingColumn ,
                        t2.rn
               FROM     #temp t2
                        INNER JOIN cte ON t2.rn = cte.rn + 1
             )
    SELECT  sgid,metric, MIN(startdate) AS startdate, MAX(enddate) AS enddate
    FROM    cte
    GROUP BY sgid,metric, GroupingColumn

DROP TABLE #temp
DROP TABLE #consecutivedates

, но я столкнулся с проблемой с двумя вещами.

  1. запрос слишком большие, когда файлы большие.

  2. , если даты имеют вид, подобный

    startdate enddate '2019-08-01' '2019-09-30' '2019 -10-01 '' 2019-10-31 '

Тогда запрос не будет группировать даты, и мне нужно, чтобы он был достаточно умен, чтобы решать подобные случаи.

Любая помощь будет хорошей,

Спасибо.

Ответы [ 2 ]

1 голос
/ 07 февраля 2020

Я понимаю, что вы хотите сгруппировать записи, которые имеют одинаковые sgid и metric и являются смежными (ie следующая запись начинается через день после окончания текущей записи).

Вот решение с пробелами и островами, которое использует сумму окон для определения групп:

select sgid, metric, min(startdate) startdate, max(enddate) enddate
from (
    select
        t.*,
        sum(case when startdate = dateadd(day, 1, lag_enddate) then 0 else 1 end)
            over(partition by sgid, metric order by startdate) grp
    from (
        select 
            t.*, 
            lag(enddate) over(partition by sgid, metric order by startdate) lag_enddate
        from  #consecutivedates t
    ) t
) t
group by sgid, metric, grp

Для ваших выборочных данных, где все три записи являются смежными, получается:

sgid | metric | startdate               | enddate                
:--- | :----- | :---------------------- | :----------------------
2177 | 515818 | 2019-07-01 00:00:00.000 | 2019-09-30 00:00:00.000

Демонстрация по БД Fiddle

Обратите внимание, что в запросе используются SQL Функции даты сервера (которые, я подозреваю, вы используете): альтернативы существуют в других базах данных.

0 голосов
/ 07 февраля 2020

Оконные рамы могут быть более производительными, но вам нужно будет их протестировать. Вот альтернативное решение:

select sgid, metric, min(startdate) as mindate, max(enddate) as maxdate
from (
  select *,
    sum(case when startdate > dateadd(day, 1, prev_enddate) then 1 else 0 end)
      over(partition by sgid, metric order by startdate) as grp
  from (
    select 
      sgid, metric, startdate, enddate,
      max(enddate)
        over(partition by sgid, metric order by startdate 
             rows between unbounded preceding and 1 preceding) as prev_enddate
    from #consecutivedates
  ) x
) y  
group by sgid, metric, grp

Результат (с более полным сценарием данных):

sgid  metric  mindate                maxdate              
----  ------  ---------------------  ---------------------
2177  515818  2019-03-01 00:00:00.0  2019-03-31 00:00:00.0
2177  515818  2019-07-01 00:00:00.0  2019-09-30 00:00:00.0
2177  515818  2019-11-01 00:00:00.0  2019-11-30 00:00:00.0
2177  515820  2019-10-01 00:00:00.0  2019-10-31 00:00:00.0

Вот сценарий данных, который я использовал:

create table #consecutivedates (sgid nvarchar(max), metric nvarchar(max), 
  targetvalue nvarchar(max), startdate datetime, enddate datetime);

insert into #consecutivedates values
  ('2177', '515818', '18', '2019-09-01',  '2019-09-30'),
  ('2177', '515818', '125', '2019-08-01',  '2019-08-31'),
  ('2177', '515818', '15', '2019-07-01',  '2019-07-31'),
  ('2177', '515820', '15', '2019-10-01',  '2019-10-31'),
  ('2177', '515818', '15', '2019-03-01',  '2019-03-31'),
  ('2177', '515818', '15', '2019-11-01',  '2019-11-30')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...