根据列总和值对行进行分组

问题描述 投票:0回答:2

我有一个包含3列的表,如下所示:

id   | num_rows                         id   | num_rows | group_id
-----|---------                         -----|----------|--------
2502 | 330                              2502 | 330      | 9
3972 | 150                              3972 | 150      | 9
3988 | 200          =============>      3988 | 200      | 8
4228 | 280          Desired output      4228 | 280      | 8
3971 | 510          =============>      3971 | 510      | 1
52   | 1990                             52   | 1990     | 2
895  | 2000                             895  | 2000     | 3
812  | 5596                             812  | 5596     | 4
1600 | 7462                             1600 | 7462     | 5
910  | 7526                             910  | 7526     | 6
638  | 11569                            638  | 11569    | 7

id是某种东西的唯一标识符,而num_rows对应于每个id在另一个表中的行数。

我想对行(即id列)进行分组,使得num_rows的总和永远不会高于指定值(在这种情况下可以说是500)。

简单地说:我想把桶中的id分组,没有桶的行比500多。如果id大于限制,那么它将获得自己独立的组/桶。

到目前为止,我已经能够使用以下查询分离出更大的id,但我无法为id的剩余子集创建组。

SELECT id, 
        num_rows,
        SUM(CASE WHEN num_rows > 500 THEN 1 ELSE 0 END) OVER(ORDER BY num_rows) AS group_id
FROM myTable;

id   | num_rows | group_id
-----|----------|--------
2502 | 330      | 0
3972 | 150      | 0
3988 | 200      | 0
4228 | 280      | 0
3971 | 510      | 1
52   | 1990     | 2
895  | 2000     | 3
812  | 5596     | 4
1600 | 7462     | 5
910  | 7526     | 6
638  | 11569    | 7

谢谢。

sql oracle group-by grouping rows
2个回答
1
投票

我个人更喜欢这个任务的pl / sql函数,但如果你想在纯sql中这样做,你可以使用以下查询:

WITH ord AS (SELECT id, num_rows, ROWNUM ord FROM myTable)
   , rek(ord, id, num_rows, sum_rows, groupId) AS 
         (SELECT ord, id, num_rows, num_rows, 1 FROM ord WHERE ord = 1
          UNION ALL
          SELECT rek.ord +1
               , ord.id
               , ord.num_rows
               , CASE WHEN rek.sum_rows + ord.num_rows > 500
                      THEN ord.num_rows
                      ELSE rek.num_rows + ord.num_rows
                END
               , CASE WHEN rek.sum_rows + ord.num_rows > 500
                      THEN rek.groupID + 1
                      ELSE rek.groupID
                 END
            FROM rek
            JOIN ORD
              ON ord.ord = rek.ord+1)
SELECT id, num_rows, groupid
  FROM rek
/

请注意,此查询不会搜索匹配条目以构建组,使得总和<500,因为这与所谓的背包问题(s.https://en.wikipedia.org/wiki/Knapsack_problem)密切相关,这很容易解决...


-1
投票

如果您不按顺序进行,则可以按如下方式使用no行创建组

SELECT id, 
        num_rows,
        ceil(num_rows/500) AS group_id
FROM myTable;

这应该是每500行块的新id。

© www.soinside.com 2019 - 2024. All rights reserved.