简体   繁体   English

SQL 查询 - 基于多列组合行

[英]SQL Query - Combine rows based on multiple columns

在此处输入图像描述

On the image above, I'd like to combine rows with the same value on consecutive days.在上图中,我想连续几天合并具有相同值的行。 Combined rows will have the earliest date on From column and the latest date on To column.合并的行将在From列上具有最早的日期,在To列上具有最晚的日期。 Looking at the example, even if Rows 3 and 4 have the same value, they were not combined because of the date gap.查看示例,即使第 3 行和第 4 行具有相同的值,它们也不会因为日期间隔而合并。

I've tried using LAG and LEAD functions but no luck.我试过使用 LAG 和 LEAD 函数,但没有运气。

You can try below way -您可以尝试以下方式 -

DEMO 演示

    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

OUTPUT: OUTPUT:

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

I am going to recommend the following approach:我将推荐以下方法:

  1. Find where each new group begins.找出每个新组的起点。 You can do this by comparing the previous maximum todate with the fromdate in this row.您可以通过将之前的最大todate与该行中的fromdate进行比较来做到这一点。
  2. Do a cumulative sum of the starts to define a group.对开始次数进行累积总和以定义一个组。
  3. Aggregate the results.汇总结果。

This can be handled using window functions and aggregation:这可以使用 window 函数和聚合来处理:

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);

Here is a db<>fiddle. 是一个 db<>fiddle。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM