使用postgres的over分区求和动态行

时间:2018-08-14 19:54:43

标签: sql postgresql

在postgres 9.2上

| payer| effective_status | 1     |    2   | 3   | 4+
+------+ -----------------+-------+--------+-----+-----
|  p1  | foo              |     8 |   6000 |    4|  1
|  p1  | bar              |    10 |   5200 |    9|  2
|  p1  | baz              |    11 |   5200 |   11|  2
|  p1  | zip              |     9 |   4500 |   14|  4
|  p1  | zap              |     7 |   4200 |   45|  5
|  p1  | status_n         |     2 |   3900 |   71|  1

假设上面的查询输出(减去?? s)。我试图按付款人和有效状态对第1、2、3和4+列求和。因此,对于p1,将有一个包括所有有效状态的列总计,然后p2将有一组总计。

    | p1   | effective_status | 1     |    2   | 3   | 4+| 1 total | 2 total|3 total| 4+ total
    +------+ -----------------+-------+--------+-----+---+---------+--------+-------+----------
    |      | foo              |     8 |   6000 |    4|  1|    94   |  6230  |  154  | 15
    |      | bar              |    10 |   5200 |    9|  2|    94   |  6230  |  154  | 15
    |      | baz              |    11 |   5200 |   11|  2|    94   |  6230  |  154  | 15
    |      | zip              |     9 |   4500 |   14|  4|    94   |  6230  |  154  | 15
    |      | zap              |     7 |   4200 |   45|  5|    94   |  6230  |  154  | 15
    |      | status_n         |     2 |   3900 |   71|  1|    94   |  6230  |  154  | 15

我将如何计算?我尝试过的:

payer
,effective_status
,status_check1
,SUM(status_check1) OVER (PARTITION BY payer) AS status_check1_total
,status_check2
,SUM(status_check2) OVER (PARTITION BY payer) AS status_check2_total
,status_check3
,SUM(status_check3) OVER (PARTITION BY payer) AS status_check3_total
,status_check4
,SUM(status_check4) OVER (PARTITION BY payer) AS status_check4_total

这似乎在大多数时候都有效。有时会有错误的总计。这是正确的方法吗?

3 个答案:

答案 0 :(得分:1)

如果我理解正确,则可以使用UNION ALL来组合总结果集和原始表。然后按order by的顺序使用grp

CREATE TABLE T(
  payer varchar(50),
  effective_status varchar(50),
  status_check1 int,
  status_check2 int,
  status_check3 int,  
  status_check4 int
);


INSERT INTO T VALUES ('p1', 'foo',8 ,6000,4,1);
INSERT INTO T VALUES ('p1', 'bar',10,5200,9,2);
INSERT INTO T VALUES ('p1', 'baz',11,5200,11,2);
INSERT INTO T VALUES ('p1', 'zip',9 ,4500,14,4);
INSERT INTO T VALUES ('p1', 'zap',7 ,4200,45,5);
INSERT INTO T VALUES ('p1', 'status_n',2 ,3900,71,1);
INSERT INTO T VALUES ('p2', 'foo',5 ,3500,12,2);
INSERT INTO T VALUES ('p2', 'zip',1 ,5000,1,1);

查询1

SELECT * 
FROM (
  SELECT t1.payer
    ,effective_status
    ,status_check1
    ,status_check2
    ,status_check3
    ,status_check4
    ,1 grp
  FROM T t1 
  UNION ALL
  SELECT payer,
         '',
         SUM(status_check1),
         SUM(status_check2),
         SUM(status_check3),
         SUM(status_check4),
         2
  FROM T
  GROUP BY payer 
) t1
ORDER BY payer,grp

Results

| payer | effective_status | status_check1 | status_check2 | status_check3 | status_check4 | grp |
|-------|------------------|---------------|---------------|---------------|---------------|-----|
|    p1 |              foo |             8 |          6000 |             4 |             1 |   1 |
|    p1 |              bar |            10 |          5200 |             9 |             2 |   1 |
|    p1 |              baz |            11 |          5200 |            11 |             2 |   1 |
|    p1 |              zip |             9 |          4500 |            14 |             4 |   1 |
|    p1 |              zap |             7 |          4200 |            45 |             5 |   1 |
|    p1 |         status_n |             2 |          3900 |            71 |             1 |   1 |
|    p1 |                  |            47 |         29000 |           154 |            15 |   2 |
|    p2 |              foo |             5 |          3500 |            12 |             2 |   1 |
|    p2 |              zip |             1 |          5000 |             1 |             1 |   1 |
|    p2 |                  |             6 |          8500 |            13 |             3 |   2 |

答案 1 :(得分:1)

我不确定为什么要使用窗口功能。这似乎是union all

select payer, effective_status, status_check1, status_check2, status_check3, status_check4
from t
union all
select payer, null, sum(status_check1), sum(status_check2), sum(status_check3), sum(status_check4)
order by payer, effective_status nulls last;

Postgres 9.5支持grouping sets,简化了这种逻辑。

答案 2 :(得分:0)

实际上,我不清楚您要做什么,但是如果您想按付款人和有效状态将结果分组,则可能看起来像这样

select 
   payer as p, 
   effective_status as es,
   (sum(col1) + sum(col2) + sum(col3) + sum(col4)) as sum
from table_name
group by p, es

所以,希望对您有帮助