将多个“group by”组合成单个查询?

时间:2017-05-10 19:29:38

标签: sql postgresql

我正在尝试根据不同的“分组依据”对值进行求和/计算,但我无法弄清楚如何在单个查询中执行此操作。

CREATE TABLE test(
col1    text,
col2    text,
col3    int
);

INSERT INTO test VALUES('A',  '',  10);
INSERT INTO test VALUES('A', 'A',  15);
INSERT INTO test VALUES( '', 'A', 100);
INSERT INTO test VALUES('B', 'C',   1);
INSERT INTO test VALUES('C',  '',  33);

我已经想出如何部分得到我正在寻找的东西:

--(this might not be the "correct" way, just my experiments)
SELECT col1 AS name, sum(col3) as col1_sum FROM test GROUP BY col1;
SELECT col2 AS name, sum(col3) as col2_sum FROM test GROUP BY col2;

除了上述内容,我想计算差异b_sum - a_sum,所以完整的查询结果将是:

name     col1_sum     col2_sum     difference
----     --------     --------     ----------
A          25             115          90
B           1         (empty)          -1
C          33               1         -32
(empty)   100              43         -57

如何获得上述输出的任何想法..?谢谢!

6 个答案:

答案 0 :(得分:2)

我在聚合后想full outer join

select coalesce(t1.name, t2.name) as name, t1.col1_num, t2.col2_sum,
       coalesce(t2.col2_sum, 0) - coalesce(t1.col1_sum, 0) as diff
from (select col1 as name, sum(col3) as col1_sum
      from ttest
      group by col1
     ) t1 full outer join
     (select col2 as name, sum(col3) as col2_sum
      from ttest
      group by col2
     ) t2
     on t1.name = t2.name;

答案 1 :(得分:1)

使用UNION ALL合并结果,然后减去这些值。

select name,max(col1_sum),max(col2_sum),coalesce(max(col2_sum),0)-coalesce(max(col1_sum),0)
from (
SELECT col1 AS name, sum(col3) as col1_sum,null col2_sum
FROM test 
GROUP BY col1
UNION ALL
SELECT col2, null, sum(col3) 
FROM test
GROUP BY col2
) t
GROUP BY name

答案 2 :(得分:1)

with t as (
    select col1, col2, sum(col3), grouping((col1),(col2))
    from test
    group by grouping sets ((col1),(col2))
)
select
    coalesce(t1.col1, t1.col2) as col,
    t1.sum as col1_sum,
    t2.sum as col2_sum,
    coalesce(t2.sum, 0) - coalesce(t1.sum, 0) as difference
from t t1 full join t t2 on t1.col1 = t2.col2
where t1.col1 <> '' or t2.col2 <> '' or (t1.col1 = '' and t2.col2 = '')
;
 col | col1_sum | col2_sum | difference 
-----+----------+----------+------------
     |      100 |       43 |        -57
 A   |       25 |      115 |         90
 B   |        1 |          |         -1
 C   |       33 |        1 |        -32

答案 3 :(得分:0)

使用公用表表达式:

;with a as (
SELECT 
    col1 AS name
  , sum(col3) as col1_sum 
FROM test 
GROUP BY col1
)
, b as (
SELECT 
    col2 AS name
  , sum(col3) as col2_sum 
FROM test 
GROUP BY col2
)
select 
    a.name
  , a.col1_sum
  , b.col2_sum
  , coalesce(b.col2_sum,0) - coalesce(a.col1_sum,0) as difference
from a
  left join b
    on a.name = b.name
order by a.name

rextester演示:http://rextester.com/YROWT76204

返回:

+------+----------+----------+------------+
| name | col1_sum | col2_sum | difference |
+------+----------+----------+------------+
|      |      100 | 43       |        -57 |
| A    |       25 | 115      |         90 |
| B    |        1 | NULL     |         -1 |
| C    |       33 | 1        |        -32 |
+------+----------+----------+------------+

如果第一个查询没有所有名称,请从left join切换到full join并使用coalesce(a.name,b.name) as name

答案 4 :(得分:0)

select a.name, col1_sum, col2_sum , coalesce(col2_sum,0) - coalesce(col1_sum,0) as diff
from
     (SELECT case when col1 is null then '(empty)' else col1 end AS name, 
      sum(col3) as col1_sum FROM test GROUP BY col1) a
full outer join (SELECT case when col2 is null then '(empty)' else col2 end AS name, 
      sum(col3) as col2_sum FROM test GROUP BY col2) b
on a.name = b.name
order by a.name;
name | col1_sum | col2_sum | diff
:--- | -------: | -------: | ---:
     |      100 |       43 |  -57
A    |       25 |      115 |   90
B    |        1 |     null |   -1
C    |       33 |        1 |  -32

dbfiddle here

答案 5 :(得分:0)

首先,我要说你的解决方案可能是给定表结构的最简单方法。

其次,我建议你需要一个不同的表结构。 &#34;名称&#34;不应该分散在不同列的表中 - 它需要是一个索引字段。我试试这样的表:

CREATE TABLE test(
aInstance   int,
aName    text,
col_nam    int,
col_val    int
);

INSERT INTO test VALUES(1,'A',1, 10);
INSERT INTO test VALUES(2,'A',1, 15);
INSERT INTO test VALUES(2,'A',2, 15);
INSERT INTO test VALUES(3,'A',2, 100);
INSERT INTO test VALUES(3,'B',1, 1);
INSERT INTO test VALUES(3,'C',2, 1);
INSERT INTO test VALUES(4,'C',2, 33);

这不像人类可读,但在关系数据库中效果更好。