在别名上使用聚合函数?

时间:2013-08-17 16:21:14

标签: postgresql aggregate-functions

我想查询一下我在计算两列之间的差异。类似的东西:

 SELECT a,
        b,
        a - b as "diff"
  FROM ...

现在我想使用postgresql内置的stddev聚合函数来计算“diff”列的stddev。我怎样才能做到这一点?

感谢。

编辑:

实际的查询是:

SELECT tr.date_start,
       tr.date_end,       
       (((CASE when(tourney_summary.val_curr_conv != 0) THEN tourney_summary.val_curr_conv * (tr.amt_won + tr.cnt_bounty * tourney_summary.amt_bounty) ELSE 0.0 END))) AS "amt_won_curr_conv",
          (((CASE when(tourney_summary.val_curr_conv != 0) THEN tourney_summary.val_curr_conv * (tourney_summary.amt_buyin + tourney_summary.amt_fee + tourney_summary.amt_rebuy * tr.cnt_rebuy + tourney_summary.amt_addon * tr.cnt_addon + tourney_summary.amt_bounty) ELSE 0.0 END))) AS "amt_buyin_ttl_curr_conv",
       ((((CASE when(tourney_summary.val_curr_conv != 0) THEN tourney_summary.val_curr_conv * (tr.amt_won + tr.cnt_bounty * tourney_summary.amt_bounty) ELSE 0.0 END))) - (((CASE when(tourney_summary.val_curr_conv != 0) THEN tourney_summary.val_curr_conv * (tourney_summary.amt_buyin + tourney_summary.amt_fee + tourney_summary.amt_rebuy * tr.cnt_rebuy + tourney_summary.amt_addon * tr.cnt_addon + tourney_summary.amt_bounty) ELSE 0.0 END)))) as net_amt_won,
       stddev((((CASE when(tourney_summary.val_curr_conv != 0) THEN tourney_summary.val_curr_conv * (tr.amt_won + tr.cnt_bounty * tourney_summary.amt_bounty) ELSE 0.0 END))) - (((CASE when(tourney_summary.val_curr_conv != 0) THEN tourney_summary.val_curr_conv * (tourney_summary.amt_buyin + tourney_summary.amt_fee + tourney_summary.amt_rebuy * tr.cnt_rebuy + tourney_summary.amt_addon * tr.cnt_addon + tourney_summary.amt_bounty) ELSE 0.0 END)))) as diff_std_dev

FROM tourney_summary,
     tourney_results tr
WHERE 
  tr.id_player=1
  AND tourney_summary.id_tourney = tr.id_tourney
  AND ((tourney_summary.id_gametype = 1)
       AND (((((((tourney_summary.id_table_type IN
                    (SELECT lttt.id_table_type
                     FROM tourney_table_type lttt
                     WHERE lttt.val_seats = 2))))))
             AND (((((tourney_summary.id_table_type IN
                        (SELECT lttt.id_table_type
                         FROM tourney_table_type lttt
                         WHERE position('S' IN lttt.val_speed) > 0))
                     OR (tourney_summary.id_table_type IN
                           (SELECT lttt.id_table_type
                            FROM tourney_table_type lttt
                            WHERE position('H' IN lttt.val_speed) > 0))))))))
       AND ((tourney_summary.date_start >= '2013/08/15 23:00:00')))
GROUP BY tr.date_start,
         tr.date_end,
         tourney_summary.val_curr_conv,
         tr.amt_won,
         tr.cnt_bounty,
         tourney_summary.amt_bounty,
         tourney_summary.amt_buyin,
         tourney_summary.amt_fee,
         tourney_summary.amt_rebuy,
         tr.cnt_rebuy,
         tourney_summary.amt_addon,
         tr.cnt_addon
ORDER BY tr.date_end DESC;

“a”和“b”表达式(带CASE的表达式)很大。我不知道如何避免复制/粘贴。在任何情况下,在a-b表达式上使用stddev都会返回一个空白列。我究竟做错了什么?

感谢。

2 个答案:

答案 0 :(得分:2)

你几乎自己回答。计算差异的标准差:

 SELECT a,
        b,
        a - b as "diff",
        stddev(a - b) AS "diff_stddev"
  FROM ...

如果a - b是一个计算成本高昂的操作,或者实际上是一个更复杂的表达,你可以将它包装在一个子查询中:

 SELECT a, b, "diff", stddev("diff") AS diff_stddev
 FROM (
   SELECT a, b, a - b
   FROM ...
 ) x (a, b, "diff")

x只是子查询表的丢弃别名。

答案 1 :(得分:1)

也可以用cte

来做到这一点
with cte1 as (
   select a, b, a - b as diff
   from ...
)
select
    a, b, diff, stddev(diff) as diff_stddev
from cte1