SQL Оконная функция для разделения столбца на 4 группы - PullRequest
0 голосов
/ 14 марта 2020

Я хочу разделить строки таким образом, чтобы сумма выручки каждой группы была приблизительно равна (в данном случае 50)

См. Группы здесь:

See groups here

Ответы [ 2 ]

0 голосов
/ 15 марта 2020

Для решения подобных проблем вам понадобится рекурсивный cte. Здесь у меня есть таблица с равными значениями 5 для 5 записей. поэтому на одну группировку вы должны ожидать 1, так как это будет 25/4> 5

create table data_tbl
as 
select * from (values
        (1, 5), 
        (2, 5),
        (3, 5),
        (4, 5),
        (5, 5)
          ) as t(user1, revenue)

 with recursive data
      as (select user1
                 ,revenue
                 ,(sum(revenue) over())/4 as qtr_revenue
                 ,cast(1 as int) as grp
            from data_tbl
           where user1=1 /* start with the first user*/
         union all
          select b.user1
                 ,case when b.revenue+a.revenue<=a.qtr_revenue then
                                  b.revenue+a.revenue
                             else b.revenue
                   end as revenue
                 ,a.qtr_revenue
                 ,case when b.revenue+a.revenue<=a.qtr_revenue then
                                  a.grp
                             else a.grp+1
                   end as grp
            from data a
            join data_tbl b
              on b.user1=a.user1+1
          )
    select *
      from data
    order by user1

См. дБ ссылка на скрипку https://dbfiddle.uk/?rdbms=postgres_12&fiddle=d8d0d85e4d825af63c09f311302e3510

0 голосов
/ 14 марта 2020

Вот подход с использованием оконных функций:

select
    usr,
    revenue, 
    r_revenue running_revenue,
    sum(case 
        when lag_r_revenue is null or r_revenue / divisor <> lag_r_revenue / divisor 
        then 1 else 0 
    end) over(order by revenue, usr) grp
from (
    select t.*, lag(r_revenue) over(order by revenue, usr) lag_r_revenue
    from (
        select 
            t.*, 
            sum(revenue) over(order by revenue, usr) r_revenue, 
            sum(revenue) over() / 4 divisor
        from mytable t
    ) t
) t
order by running_revenue

Самый внутренний подзапрос вычисляет текущую сумму revenue (псевдоним r_revenue); он также вычисляет целевой доход на группу путем деления общего дохода на 4.

Следующий уровень добавляет предыдущий текущий доход к каждой строке (lag_r_revenue).

Наконец, внешний запрос создает суммы окон, которые увеличиваются каждый раз, когда (целочисленное) соотношение между текущей суммой и целевым значением для каждой группы изменяется.

Демонстрация в БД Скрипка :

usr | revenue | running_revenue | grp
--: | ------: | --------------: | --:
  1 |       5 |               5 |   1
  2 |       5 |              10 |   1
  3 |      10 |              20 |   1
  4 |      15 |              35 |   1
  5 |      15 |              50 |   2
  6 |      20 |              70 |   2
  7 |      20 |              90 |   2
  8 |      25 |             115 |   3
  9 |      30 |             145 |   3
 10 |      55 |             200 |   4
...