【问题标题】:How to use a SQL window function to calculate a percentage of an aggregate如何使用 SQL 窗口函数计算聚合的百分比
【发布时间】:2012-01-20 20:34:43
【问题描述】:

我需要计算表格中各个维度的百分比。我想通过使用窗口函数来计算分母来简化事情,但是我遇到了一个问题,因为分子也必须是一个聚合。

举个简单的例子,如下表:

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 中 d2 总和的总份额。我正在寻找的输出是这样的:

"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 不能进行相关子查询。

【问题讨论】:

    标签: sql postgresql aggregate-functions window-functions greenplum


    【解决方案1】:

    我想你正在寻找这个:

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

    产生请求的结果。

    窗口函数在聚合函数之后应用sum(sum(v)) OVER ... 中的外部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;
    

    或者@Mu的变种。

    旁白:Greenplum 在 4.2 版中引入了相关子查询。 See release notes.

    【讨论】:

    • 啊太棒了!这就是我所追求的。说得通。文档对这些内容并不是很清楚。
    【解决方案2】:

    你需要用窗口函数来做这一切吗?听起来您只需将结果按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
    

    【讨论】:

    • 嗯,确实有效。我想在没有子查询的情况下这样做的原因是因为这实际上需要进入 BI 工具(Tableau),而子查询会导致问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-29
    • 2020-03-19
    • 1970-01-01
    • 2014-12-24
    • 2021-03-24
    • 2019-07-19
    • 1970-01-01
    相关资源
    最近更新 更多