GROUP BY 單純分組已無法滿足多層次小計需求。Oracle 提供 ROLLUP(層次彙總)與 CUBE(全維度交叉彙總)擴展,單一查詢即可產生報表所需的各層級小計與總計。本文以實測資料對比兩者差異與適用場景。
| 特性 | ROLLUP | CUBE |
|---|---|---|
| 彙總維度 | 依 GROUP BY 欄位順序,產生層次式小計(由細到粗) | 產生所有欄位組合的交叉小計(全排列) |
| 結果行數 | 較少,N 個欄位最多 N+1 層級 | 較多,N 個欄位最多 2^N 種組合 |
| 典型用途 | 階層報表(年→季→月、國→省→市) | 多維分析(OLAP)、交叉表 |
| 優點 | 單一結果集、可用於游標、優化器常產生較佳計劃 | 完整多維視角、適合臨時分析 |
CREATE TABLE department (department CHAR(10), employee CHAR(6), salary INT);
BEGIN
INSERT INTO department VALUES ('A','ZHANG',100);
INSERT INTO department VALUES ('A','LI',200);
INSERT INTO department VALUES ('A','WANG',300);
INSERT INTO department VALUES ('A','ZHAO',400);
INSERT INTO department VALUES ('A','DUAN',500);
INSERT INTO department VALUES ('B','DUAN',600);
INSERT INTO department VALUES ('B','DUAN',700);
COMMIT;
END;
資料分布:部門 A 5 人,部門 B 2 人(皆為 DUAN)。
SELECT department, employee, SUM(salary) FROM department GROUP BY ROLLUP(department, employee);
結果:
ROLLUP 依 department → employee 層次產生小計,不會產生「跨部門的員工小計」(如所有 DUAN 的總和)。
SELECT department, employee, SUM(salary) FROM department GROUP BY CUBE(department, employee);
結果: 在 ROLLUP 基礎上新增 5 行:
CUBE 相當於 ROLLUP(department, employee) UNION ALL ROLLUP(employee, department) 去重。
SELECT CASE WHEN GROUPING(department)=1 THEN 'ALL_DEPT' ELSE department END AS dept, CASE WHEN GROUPING(employee)=1 THEN 'ALL_EMP' ELSE employee END AS emp, SUM(salary) AS total_sal FROM department GROUP BY CUBE(department, employee);
GROUPING(col) 回傳 1 表示該行為該欄位的彙總行,0 為明細行。配合 GROUPING_ID 可生成位元組合編碼,便於前端渲染層級。
HAVING 過濾彙總行,或用 GROUPING SETS 自訂組合(12c+ 推薦)。