您好!欢迎访问家园网-www.jy.wang!

家园网

ROLLUP vs 普通 GROUP BY 对比

网络 作者:本站 点击:

你前一个生成的结果中deptno列和dname的列中都有null的,

这里怎么没有了



您观察得非常仔细!完全正确!

ROLLUP 会生成小计和总计行,

那些行中的 deptno 和 dname 会是 NULL


一、代码回顾

SELECT e.deptno, d.dname, SUM(e.sal) AS 工资总和
FROM emp e, dept d
WHERE e.deptno = d.deptno
GROUP BY ROLLUP(e.deptno, d.dname);

关键:这里有 ROLLUP!不是普通的 GROUP BY

二、ROLLUP(e.deptno, d.dname) 产生的分组

ROLLUP 会生成 3 种分组级别


级别

分组依据

说明

deptno

dname

1

(deptno, dname)

正常分组(最细粒度)

有值

有值

2

(deptno)

按部门小计

有值

NULL

3

()

总计

NULL

NULL

三、正确的最终结果

假设数据(与之前相同)

emp 表

empno

ename

sal

deptno

1001

张三

5000

10

1002

李四

6000

10

1003

王五

7000

20

1004

赵六

8000

20

1005

孙七

9000

30


dept 表

deptnodname
10财务部
20技术部
30销售部

正确结果

deptno

dname

工资总和

分组级别

10

财务部

11000

级别1:(10, 财务部)

20

技术部

15000

级别1:(20, 技术部)

30

销售部

9000

级别1:(30, 销售部)

10

NULL

11000

级别2:(10) 部门10小计

20

NULL

15000

级别2:(20) 部门20小计

30

NULL

9000

级别2:(30) 部门30小计

NULL

NULL

35000

级别3:() 总计

四、可视化理解

text

┌─────────────────────────────────────────────────────────────┐
│ 级别1:按 (deptno, dname) 分组                              │
├─────────────────────────────────────────────────────────────┤
│ │ deptno │ dname  │ 工资总和 │                              │
│ │ 10     │ 财务部 │ 11000    │                              │
│ │ 20     │ 技术部 │ 15000    │                              │
│ │ 30     │ 销售部 │ 9000     │                              │
└─────────────────────────────────────────────────────────────┘
                              ↓
                        ROLLUP 向上滚动
                              ↓
┌─────────────────────────────────────────────────────────────┐
│ 级别2:按 (deptno) 分组(小计)                             │
├─────────────────────────────────────────────────────────────┤
│ │ deptno │ dname  │ 工资总和 │                              │
│ │ 10     │ NULL   │ 11000    │  ← 部门10的小计             │
│ │ 20     │ NULL   │ 15000    │  ← 部门20的小计             │
│ │ 30     │ NULL   │ 9000     │  ← 部门30的小计             │
└─────────────────────────────────────────────────────────────┘
                              ↓
                        ROLLUP 继续向上滚动
                              ↓
┌─────────────────────────────────────────────────────────────┐
│ 级别3:按 () 分组(总计)                                   │
├─────────────────────────────────────────────────────────────┤
│ │ deptno │ dname  │ 工资总和 │                              │
│ │ NULL   │ NULL   │ 35000    │  ← 所有部门的总计           │
└─────────────────────────────────────────────────────────────┘


五、为什么会有 NULL

分组级别

deptno

dname

为什么是 NULL

级别1

有值

有值

正常分组,都有值

级别2

有值

NULL

只按 deptno 分组,dname 不参与分组,所以为 NULL

级别3

NULL

NULL

总计行,不按任何列分组,所以都为 NULL


六、ROLLUP vs 普通 GROUP BY 对比

写法

结果行数

是否有 NULL

是否有小计/总计

GROUP BY e.deptno, d.dname

3行

❌ 无

❌ 无

GROUP BY ROLLUP(e.deptno, d.dname)

7行

✅ 

✅ 


七、如何区分明细行和小计/总计行?

Oracle 提供了 GROUPING() 函数来判断:

sql

SELECT 
    e.deptno, 
    d.dname, 
    SUM(e.sal) AS 工资总和,
    GROUPING(e.deptno) AS 是否部门小计,
    GROUPING(d.dname) AS 是否总计FROM emp e, dept dWHERE e.deptno = d.deptnoGROUP BY ROLLUP(e.deptno, d.dname);

结果

deptno

dname

工资总和

是否部门小计

是否总计

10

财务部

11000

0

0

20

技术部

15000

0

0

30

销售部

9000

0

0

10

NULL

11000

1

0

20

NULL

15000

1

0

30

NULL

9000

1

0

NULL

NULL

35000

1

1


  • GROUPING(...)=0:正常明细行

  • GROUPING(...)=1:小计或总计行


八、总结

问题答案
结果中会有 NULL 吗?✅ 会! 小计行和总计行的 dname 或 deptno 为 NULL
为什么我之前的回答没有 NULL?我错误地给出了普通 GROUP BY 的结果,忽略了 ROLLUP
正确的结果有几行?7行(3行明细 + 3行小计 + 1行总计)
NULL 代表什么?代表该列不参与当前级别的分组

一句话总结:使用 ROLLUP 时,结果中确实会出现 NULL——小计行的 dname 为 NULL,总计行的 deptno 和 dname 都为 NULL。




标签: