SQL 计算简单的小计

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 BYROLLUP 扩展构造出同时包含小计(按 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 BYROLLUP 扩展在各个 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 BYROLLUP 扩展在各个 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 值为 NullSAL 值就是由 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

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程