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

时间:2018-09-07 08:57:28

标签: sql oracle group-by grouping rows

我有一个包含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)。 / p>

简而言之:我想将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

谢谢。

2 个答案:

答案 0 :(得分: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 :(得分:-1)

如果您不希望按顺序进行操作,则可以按如下所示不使用任何行来进行分组

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

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