Группировать строки на основе значения суммы столбца - PullRequest
0 голосов
/ 07 сентября 2018

У меня есть таблица с 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

Спасибо.

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

Если вы не хотите, чтобы это происходило по порядку, вы можете просто создать группу, не используя ни одной строки следующим образом

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

Это должен новый идентификатор для каждых 500 строк блоков.

0 голосов
/ 07 сентября 2018

Лично я бы предпочел функцию 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, так как это тесно связано с так называемой проблемой ранца (с. <a href="https://en.wikipedia.org/wiki/Knapsack_problem" rel="nofollow noreferrer">https://en.wikipedia.org/wiki/Knapsack_problem),, которую почти легко решить ...

...