11

Мне нужно рассчитать проценты различных размеров в таблице. Я хотел бы упростить вещи, используя функции окна для вычисления знаменателя, однако у меня проблема, потому что числитель также должен быть агрегатом.Как использовать функцию окна SQL для вычисления процента от агрегата

В качестве простого примера рассмотрим следующую таблицу:

create temp table test (d1 text, d2 text, v numeric); 
insert into test values ('a','x',5), ('a','y',5), ('a','y',10), ('b','x',20); 

Если я просто хочу, чтобы вычислить долю каждого отдельного ряда из d1, то с окнами функции работают отлично:

select d1, d2, v/sum(v) over (partition by d1) 
from test; 

"b";"x";1.00 
"a";"x";0.25 
"a";"y";0.25 
"a";"y";0.50 

Однако мне нужно вычислить общую долю для суммы d2 из d1. Выход я ищу, это:

"b";"x";1.00 
"a";"x";0.25 
"a";"y";0.75 

Так что я стараюсь это:

select d1, d2, sum(v)/sum(v) over (partition by d1) 
from test 
group by d1, d2; 

Однако, теперь я получаю сообщение об ошибке:

ERROR: column "test.v" must appear in the GROUP BY clause or be used in an aggregate function 

Я предполагаю, что это происходит потому, он жалуется, что функция window не учитывается в предложении группировки, однако в любом случае функции группировки не могут быть помещены в предложение группировки.

Это использование Greenplum 4.1, которое является вилкой Postgresql 8.4 и имеет те же функции окон. Обратите внимание, что Greenplum не может выполнять коррелированные подзапросы.

ответ

16

Я думаю, что вы на самом деле ищет это :

SELECT d1, d2, sum(v)/sum(sum(v)) OVER (PARTITION BY d1) AS share 
FROM test 
GROUP BY d1, d2; 

Производит запрашиваемый результат.

Функции окна применяются после совокупные функции. Внешний sum() в sum(sum(v)) является оконной функцией в этом примере и прикреплен к оговорке OVER ..., тогда как внутренний sum() является совокупностью.

Эффективно же, как:

WITH x AS (
    SELECT d1, d2, sum(v) AS sv 
    FROM test 
    GROUP BY d1, d2 
    ) 
SELECT d1, d2, sv/sum(sv) OVER (PARTITION BY d1) AS share 
FROM x; 

Или (без КТР):

SELECT d1, d2, sv/sum(sv) OVER (PARTITION BY d1) AS share 
FROM (
    SELECT d1, d2, sum(v) AS sv 
    FROM test 
    GROUP BY d1, d2 
    ) x; 

Или @ вариант Му.

Кроме того, Greenplum представил коррелированные подзапросы с версией 4.2. See release notes.

+0

Ах, отлично! Это то, чем я был. Имеет смысл. Документы не так уж ясны. – EvilPuppetMaster

+0

@erwinBrandsletter Сохранял мою жизнь! Спасибо – isJustMe

1

Вам нужно сделать все это с помощью функций окна? Похоже, вы просто нужно сгруппировать результат у вас есть по d1 и d2, а затем суммировать суммы:

select d1, d2, sum(p) 
from (
    select d1, d2, v/sum(v) over (partition by d1) as p 
    from test 
) as dt 
group by d1, d2 

Это дает мне это:

d1 | d2 |   sum   
----+----+------------------------ 
a | x | 0.25000000000000000000 
a | y | 0.75000000000000000000 
b | x | 1.00000000000000000000 
+1

Ах, правда, это действительно работает. Причина, по которой я хочу сделать это без суб-запроса, заключается в том, что на самом деле это необходимо для входа в инструмент BI (Tableau), а подзапросы вызывают проблемы. – EvilPuppetMaster

Смежные вопросы