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 

但是,我需要做的就是計算出d1和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 

我假設這是因爲它抱怨窗口函數沒有在分組子句中說明,但窗口函數無論如何都不能放在分組子句中。

這是使用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(v))中的外部sum()是本示例中的一個窗口函數,附加到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; 

或(無CTE):

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 2011-12-21 09:16:08

1

您是否需要使用窗口函數完成所有操作?聽起來像你只需要對結果進行分組你必須d1d2再總結的款項:

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

啊真的,那確實有效。我希望沒有子查詢的原因是因爲這實際上需要進入商務智能工具(Tableau),子查詢會導致問題。 – EvilPuppetMaster 2011-12-21 09:14:27