【问题标题】:How to group by continuous records in SQLSQL中如何按连续记录分组
【发布时间】:2020-09-15 05:05:05
【问题描述】:

我的表有这些记录

ID  Colour
------------
 1   Red
 2   Red
 3   Red
 4   Red
 5   Red
 6   Green
 7   Green
 8   Green
 9   Green
10   Red
11   Red
12   Red
13   Red
14   Green
15   Green
16   Green
17   Blue
18   Blue
19   Red
20   Blue

我可以像这样轻松按颜色分组

SELECT Colour, MIN(ID) AS iMin, MAX(ID) AS iMax
FROM MyTable
GROUP BY Colour

这会返回这个结果

Colour     iMin     iMax
-------------------------
Red        1        19
Green      6        16
Blue       17       20

但这不是我想要的,因为红色不会从 1 一直到 19,绿色会破坏序列。

结果应该是这样的

Colour     iMin     iMax
------------------------
Red        1        5
Green      6        9
Red        10       13
Green      14       16
Blue       17       18
Red        19       19
Blue       20       20

我设法通过光标来做到这一点,但想知道是否有更有效的方法来做到这一点

【问题讨论】:

    标签: sql sql-server date window-functions gaps-and-islands


    【解决方案1】:

    这是一个孤岛问题。假设id 不断增加,您可以使用row_number() 之间的差异来定义具有相同colour 的“相邻”记录组:

    select 
        colour, 
        min(id) iMin,
        max(id) iMax
    from (
        select t.*, row_number() over(partition by colour order by id) rn
        from mytable t
    ) t
    group by colour, id - rn
    order by min(id)
    

    Demo on DB Fiddle

    颜色 | iMin | iMax :----- | ---: | ---: 红色 | 1 | 5 绿色 | 6 | 9 红色 | 10 | 13 绿色 | 14 | 16 蓝色 | 17 | 18 红色 | 19 | 19 蓝色 | 20 | 20

    【讨论】:

      【解决方案2】:

      这是一个间隙和孤岛问题。你可以通过行号的不同来解决这个问题:

      select colour, min(id), max(id)
      from (select t.*,
                   row_number() over (order by id) as seqnum,
                   row_number() over (partition by colour order by id) as seqnum_c
            from t
           ) t
      group by colour, (seqnum - seqnum_c);
      

      Here 是一个 dbfiddle。

      很难解释这是如何工作的。但是,如果您查看子查询的结果,您将看到行号的差异如何识别相邻的颜色。

      【讨论】:

        【解决方案3】:

        无论id列是否为整数且id列的值是否连续,查询都有效。

        ;with c0 as(
        select id, color,
               ROW_NUMBER() over(order by id)*
               (case when color <> LAG(color, 1, '') over(order by id) then 1 else 0 end) as color_id
        from #temp
        ), c1 as(
        select id, color, color_id, SUM(color_id) over(order by id) as color_gid
        from c0
        )
        select color, MIN(id) as idMin, MAX(id) as idMax
        from c1
        group by color, color_gid
        

        它可以扩展为按a列排序,按b列的连续值分组,并找到c列的聚合值,如下所示:

        ;with c0 as(
        select C, B,
               ROW_NUMBER() over(order by A)*
               (case when B <> LAG(B, 1, '') over(order by A) then 1 else 0 end) as B_id
        from TableName
        ), c1 as(
        select C, B, B_id, SUM(B_id) over(order by A) as B_gid
        from c0
        )
        select B, MIN(C) as CMin, MAX(C) as CMax
        from c1
        group by B, B_gid
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-05-23
          • 1970-01-01
          • 2018-04-09
          • 1970-01-01
          • 2020-06-18
          • 1970-01-01
          • 2017-05-20
          相关资源
          最近更新 更多