在DB2中对连续行进行分组

时间:2014-08-03 00:23:15

标签: sql database group-by db2

我在DB2中有一个表如下所示: -

ID        DESCRIPTION        TYPE    AMOUNT
--        -----------        ----    ------
1         Item 1             ONE     100
2         Item 2             ONE     50    
3         Item 3             TWO     100
4         Item 4             TWO     50
5         Item 5             ONE     100
6         Item 6             TWO     50
7         Item 7             ONE     100
8         Item 8             TWO     50
9         Item 9             TWO     100
10        Item 10            ONE     50

我想将具有相同类型的连续行分组,如下所示: -

TYPE    AMOUNT
----    ------
ONE        150            -- (ID 1,2)
TWO        150            -- (ID 3,4)
ONE        100            -- (ID 5)
TWO        50             -- (ID 6)
ONE        100            -- (ID 7)
TWO        150            -- (ID 8,9)
ONE        50             -- (ID 10)

请注意,最后一列只是表示汇总中的哪些ID。

我宁愿使用查询而不是存储过程来执行此操作。

2 个答案:

答案 0 :(得分:2)

除非我错过了我的猜测,否则可以通过双重ROW_NUMBER()常量表达式轻松完成:

SELECT type, SUM(amount) AS amount
FROM (SELECT type, amount, id,
             ROW_NUMBER() OVER(ORDER BY id) 
                          - ROW_NUMBER() OVER(PARTITION BY type ORDER BY id) AS groupId
      FROM tbl) grouped
GROUP BY groupId, type
ORDER BY groupId, MIN(id)

SQL Fiddle Example
(感谢Brian为最初的小提琴设置)

......产生了预期的结果。请注意,MIN(id)是确保一致排序顺序所必需的 - groupId并非普遍唯一,因此否则某些ONETWO行最终会被翻转。

作为旁注,我不喜欢在id列上进行排序,因为唯一真正有用的内容是 uniqueness 。在行可能被更新或以其他方式重新解释的情况下尤其如此 - 您是否有类似insertedAt时间戳的内容可用于订购?

答案 1 :(得分:0)

想想我明白了:

Fiddle:

with sub1 as
 (select x.*,
         case when chk is not null
              then row_number() over(order by id)
              else null
              end as rn
    from (select id,
                 description,
                 type,
                 amount,
                 case when lag(type, 1) over(order by id) <> type
                      then 'X'
                      else null
                      end as chk
            from tbl
           order by id) x)
select min(type),
       sum(amount) as amount,
       listagg(id, ', ') within group(order by id) as ids
  from (select z.id, z.description, z.type, z.amount, y.rn
          from sub1 z
         cross join sub1 y
         where z.rn is null
           and y.rn = (select max(x.rn)
                         from sub1 x
                        where x.id < z.id
                          and x.rn is not null)
        union all
        select id, description, type, amount, rn
          from sub1
         where rn is not null
        union all
        select id, description, type, amount, 1
          from sub1
         where id < (select min(id) from sub1 where rn is not null)
         order by id) x
 group by rn
 order by rn

我在Oracle中对它进行了测试,但它只依赖于我认为DB2具有的with子句和窗口函数,所以它应该可以工作,如果有任何修改的话。