mysql - rollup 使用

ROLLUP

rollup相对于简单的分组合计增加了小计和合计(适用于统计功能),解释起来会比较抽象,下面我们来看看具体事例。

1.统计不同部门工资的总和和所有部门工资的总和。

select deptno,sum(sal) from emp group by deptno with rollup;

2.先对deptno进行分组,再对job进行分组

select deptno,job,sum(sal) from emp group by deptno,job with rollup;

  这里可能就有人会有疑问了,为什么数据比原来多了10条,理论上应该只是全部的总结,只会比group by 多一条数据才合理,查了资料才弄明白,对于聚合单数据(group by 后面的变量一个为单数据,多个则为多数据)是适合的,但是在多数据的情况下就不一样了,下面我们分析一下,首先会根据depno变量,将原始数据分为9个101,102,103...109九个组,group by WITH ROLLUP会在每个分组后面加上本组类的信息(deptno),第5行数据就是1,2,3,4行数据聚合所执行sum(sal)所得的结果,依次类推...108,109也是一样,同时在最后,会将全部的分组聚合。

性能分析:

 

3.对比不使用 rollup实现类似功能(可用UNION ALL语句)

#实现单个部门,单个工种的工资的总和
select deptno,job,sum(sal) from emp group by deptno,job
union all
#实现单个部门工资的总和
select deptno,null,sum(sal) from emp group by deptno
union all
#实现所有部门工资的总和
select null,null,sum(sal) from emp
order by deptno desc,job desc

性能分析:

总结:

通过2,3执行结果的性能分析:不难看出,相同的功能实现,ROLLUP相对于UNION ALL效率有了极大的提升。

实战案例:

#emp 表结构
CREATE TABLE `emp` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `empno` mediumint(8) unsigned NOT NULL DEFAULT '0',
  `ename` varchar(20) NOT NULL DEFAULT '',
  `job` varchar(9) NOT NULL DEFAULT '',
  `mgr` mediumint(8) unsigned NOT NULL DEFAULT '0',
  `hiredate` date NOT NULL,
  `sal` decimal(7,2) NOT NULL,
  `comm` decimal(7,2) NOT NULL,
  `deptno` mediumint(8) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=500001 DEFAULT CHARSET=utf8;

1.对员工表的信息按照部门,汇总岗位信息的薪资情况。

#常规处理
select deptno,sum(if(job = 'dev',sal,null)) dev_sal,sum(if(job = 'manager',sal,null)) manager_sal,sum(if(job = 'salesman',sal,null)) salesman_sal,sum(if(job = 'Test',sal,null)) Test_sal
from emp group by deptno 

2.如果相对上结果,加上一个汇总展示,如何处理?

#1.使用 union  all
select deptno,sum(if(job = 'dev',sal,null)) dev_sal,sum(if(job = 'manager',sal,null)) manager_sal,sum(if(job = 'salesman',sal,null)) salesman_sal,sum(if(job = 'Test',sal,null)) Test_sal
from emp group by deptno 
union all 
select null ,sum(if(job = 'dev',sal,null)) dev_sal,sum(if(job = 'manager',sal,null)) manager_sal,sum(if(job = 'salesman',sal,null)) salesman_sal,sum(if(job = 'Test',sal,null)) Test_sal
from emp

#2.使用 rollup
select deptno,sum(if(job = 'dev',sal,null)) dev_sal,sum(if(job = 'manager',sal,null)) manager_sal,sum(if(job = 'salesman',sal,null)) salesman_sal,sum(if(job = 'Test',sal,null)) Test_sal
from emp group by deptno with rollup;

存在问题:

  1. 这个记录没有出现总计两个字,怎么实现呢? 使用 ifnull()函数 (有坑)

#有坑版
select ifnull(deptno,'汇总') deptno,sum(if(job = 'dev',sal,null)) dev_sal,sum(if(job = 'manager',sal,null)) manager_sal,sum(if(job = 'salesman',sal,null)) salesman_sal,sum(if(job = 'Test',sal,null)) Test_sal
from emp group by deptno with rollup;

#为什么说有坑? 如果deptno 本身为null ,那么以上查询将会出现多个汇总行。
#填坑版 (使用双层ifnull判断 or 将字段定义为not nullselect ifnull(deptno,'汇总') deptno,dev_sal,manager_sal,salesman_sal,Test_sal from (
select ifnull(deptno,'空城(默认)') deptno,sum(if(job = 'dev',sal,null)) dev_sal,sum(if(job = 'manager',sal,null)) manager_sal,sum(if(job = 'salesman',sal,null)) salesman_sal,sum(if(job = 'Test',sal,null)) Test_sal
from emp group by deptno ) a group by deptno with rollup;

2.如果想对其中一列进行排序如何处理?使用order by field()处理

#天真的处理方式
select ifnull(deptno,'空城(默认)') deptno,sum(if(job = 'dev',sal,null)) dev_sal,sum(if(job = 'manager',sal,null)) manager_sal,sum(if(job = 'salesman',sal,null)) salesman_sal,sum(if(job = 'Test',sal,null)) Test_sal
from emp group by deptno with rollup ORDER BY Test_sal ;
#结果报错: Incorrect usage of CUBE/ROLLUP and ORDER BY
#原因:MySQL 虽然提供了 group by with rollup 函数进行group by 字段的汇总,but 与 order by 互斥,不能同时用

#正确方式 使用order by field()
#根据测试岗位的Test_sal薪资降序排列 总计置于底部 =>可以把上面代码当成一个子表嵌套 结合 order by field()自定义函数实现 
select *from (
    select ifnull(deptno,'总计') deptno,dev_sal,manager_sal,salesman_sal,Test_sal from (
        select ifnull(deptno,'空城(默认)') deptno,sum(if(job = 'dev',sal,null)) dev_sal,
        sum(if(job = 'manager',sal,null)) manager_sal,sum(if(job = 'salesman',sal,null)) salesman_sal,
        sum(if(job = 'Test',sal,null))     Test_sal from emp group by deptno 
        )a group by deptno with rollup
) b ORDER BY FIELD(b.deptno,'总计'),b.Test_sal DESC;

posted @ 2019-05-28 09:15  小白个人成长记  阅读(8857)  评论(1编辑  收藏  举报