SQL 计算简单的小计,在本实例中,“简单的小计”指的是一种特殊的结果集,该结果集不仅包括某一列的聚合运算结果,也包括了整个表中该列的合计值。例如,一个结果集里既包括了 EMP
表各个 JOB
对应的工资合计值,也包括了全部工资的总计。EMP
表各个 JOB
对应的工资合计值是小计,全部工资的合计值是总计。
SQL 计算简单的小计 问题描述
在本实例中,“简单的小计”指的是一种特殊的结果集,该结果集不仅包括某一列的聚合运算结果,也包括了整个表中该列的合计值。例如,一个结果集里既包括了 EMP
表各个 JOB
对应的工资合计值,也包括了全部工资的总计。EMP
表各个 JOB
对应的工资合计值是小计,全部工资的合计值是总计。上述结果集看起来应该如下所示。
JOB SAL
--------- ----------
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
TOTAL 29025
SQL 计算简单的小计 解决方案
针对 GROUP BY
子句的 ROLLUP
扩展完美地解决了本问题。对于不支持 ROLLUP
的数据库,可以借助标量子查询或 UNION
查询解决本问题,当然做法会繁琐一些。
DB2 和 Oracle
使用聚合函数 SUM
计算工资合计值,并使用 GROUP BY
的 ROLLUP
扩展构造出同时包含小计(按 JOB
分区)和总计(针对全表数据)的结果集。
1 select case grouping(job)
2 when 0 then job
3 else 'TOTAL'
4 end job,
5 sum(sal) sal
6 from emp
7 group by rollup(job)
SQL Server 和 MySQL
使用聚合函数 SUM
计算工资合计值,并使用 WITH ROLLUP
构造出同时包含小计(按 JOB
分区)和总计(针对全表数据)的结果集。然后调用 COALESCE
函数把总计行的标题改为 TOTAL
(否则这一行的 JOB
列会出现 Null
值)。
1 select coalesce(job,'TOTAL') job,
2 sum(sal) sal
3 from emp
4 group by job with rollup
如果是 SQL Server,也可以不使用 COALESCE
函数,我们可以像上述 Oracle 和 DB2 的解决方案那样使用 GROUPING
函数来判断聚合运算的层级。
PostgreSQL
使用聚合函数 SUM
计算各个 DEPTNO
的工资合计值,然后使用 UNION ALL
把该查询和生成全表的工资总计的查询连在一起。
1 select job, sum(sal) as sal
2 from emp
3 group by job
4 union all
5 select 'TOTAL', sum(sal)
6 from emp
SQL 计算简单的小计 扩展知识
DB2 和 Oracle
首先使用聚合函数 SUM
,按照 JOB
分组并生成各个 JOB
的工资合计值。
select job, sum(sal) sal
from emp
group by job
JOB SAL
--------- -----
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
然后,使用 GROUP BY
的 ROLLUP
扩展在各个 JOB
的工资小计之外,再生成一个工资总计。
select job, sum(sal) sal
from emp
group by rollup(job)
JOB SAL
--------- -------
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
29025
最后,借助 GROUPING
函数把工资总计行对应的 JOB
列的显示内容修改一下。如果 JOB
值是 Null
,那么 GROUPING
函数会返回 1
,这意味着 SAL
值是由 ROLLUP
生成的工资总计。如果 JOB
值不为 Null
,则 GROUPING
函数将返回 0
,这意味着 SAL
值是 GROUP BY
查询的结果,而不是 ROLLUP
的结果。在 CASE
表达式中调用 GROUPING(JOB)
,这样就能根据需要返回具体的职位或代表总计行的标签 TOTAL
。
select case grouping(job)
when 0 then job
else 'TOTAL'
end job,
sum(sal) sal
from emp
group by rollup(job)
JOB SAL
--------- ----------
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
TOTAL 29025
SQL Server 和 MySQL
首先使用聚合函数 SUM
,按照 JOB
分组生成各个 JOB
的工资合计值。
select job, sum(sal) sal
from emp
group by job
JOB SAL
--------- -----
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
然后,使用 GROUP BY
的 ROLLUP
扩展在各个 JOB
的工资小计之外,再生成一个工资总计。
select job, sum(sal) sal
from emp
group by job with rollup
JOB SAL
--------- -------
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
29025
最后,针对 JOB
列调用 COEALESCE
函数。如果 JOB
值为 Null
,SAL
值就是由 ROLLUP
生成的工资总计。如果 JOB
值不为 Null
,则 SAL
值是由通常的 GROUP BY
产生的结果,而不是 ROLLUP
的结果。
select coalesce(job,'TOTAL') job,
sum(sal) sal
from emp
group by job with rollup
JOB SAL
--------- ----------
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
TOTAL 29025
PostgreSQL
首先对结果按照 JOB
分组,并使用聚合函数 SUM
生成各个 JOB
的工资合计值。
select job, sum(sal) sal
from emp
group by job
JOB SAL
--------- -----
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
最后,在上述查询的基础上使用 UNION ALL
查询生成的工资总计。
select job, sum(sal) as sal
from emp
group by job
union all
select 'TOTAL', sum(sal)
from emp
JOB SAL
--------- -------
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
TOTAL 29025