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

性能分析:spa

總結:

經過2,3執行結果的性能分析:不難看出,相同的功能實現,ROLLUP相對於UNION ALL效率有了極大的提高。code

實戰案例:

#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()函數 (有坑)blog

#有坑版
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;

相關文章
相關標籤/搜索