SQL-запрос - объединить строки на основе нескольких столбцов - PullRequest
1 голос
/ 27 сентября 2019

enter image description here

На изображении выше я хотел бы объединить строки с одним и тем же значением в последовательные дни.Объединенные строки будут иметь самую раннюю дату в столбце С и самую позднюю дату в столбце До .Глядя на пример, даже если строки 3 и 4 имеют одинаковое значение, они не были объединены из-за пробела в дате.

Я пытался использовать функции LAG и LEAD, но не повезло.

Ответы [ 2 ]

2 голосов
/ 27 сентября 2019

Вы можете попробовать следующим образом -

ДЕМО

    with c as
    (
    select *, datediff(dd,todate,laedval) as leaddiff,
    datediff(dd,todate,lagval) as lagdiff
    from
    (
    select *,lead(todate) over(partition by value order by todate) laedval,
    lag(todate) over(partition by value order by todate) lagval
    from t1
    )A
    ) 



select * from
(
select value,min(todate) as fromdate,max(todate) as todate from c
    where coalesce(leaddiff,0)+coalesce(lagdiff,0) in (1,-1)
    group by value
    union all
    select value,fromdate,todate from c
    where coalesce(leaddiff,0)+coalesce(lagdiff,0)>1 or coalesce(leaddiff,0)+coalesce(lagdiff,0)<-1
)A order by value

ВЫХОД:

value   fromdate            todate
1       16/07/2019 00:00:00 17/07/2019 00:00:00
3       21/07/2019 00:00:00 26/07/2019 00:00:00
2       18/07/2019 00:00:00 18/07/2019 00:00:00
2       20/07/2019 00:00:00 20/07/2019 00:00:00
1 голос
/ 27 сентября 2019

Я собираюсь рекомендовать следующий подход:

  1. Найти, где начинается каждая новая группа.Вы можете сделать это, сравнив предыдущий максимум todate с fromdate в этой строке.
  2. Сделайте кумулятивную сумму стартов, чтобы определить группу.
  3. Объедините результаты.

Это может быть выполнено с использованием оконных функций и агрегации:

select value, min(fromdate) as fromdate, max(todate) as todate
from (select t.*,
             sum(case when prev_todate >= dateadd(day, -1, fromdate)
                      then 0   -- overlap, so this does not begin a new group
                      else 1   -- no overlap, so this does begin a new group
                 end) over
                 (partition by value order by fromdate) as grp
      from (select t.*,
                   max(todate) over (partition by value
                                     order by fromdate
                                     rows between unbounded preceding and 1 preceding
                                    ) as prev_todate
            from t
           ) t
     ) t
 group by value, grp
 order by value, min(fromdate);

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...