GROUPING函数可以接受一列,返回0或者1。如果列值为空,那么GROUPING()返回1;如果列值非空,那么返回0。GROUPING只能在使用ROLLUP或CUBE的查询中使用。当需要在返回空值的地方显示某个值时,GROUPING()就非常有用。
1、在ROLLUP中对单列使用GROUPING()
SQL> select division_id,sum(salary)
2 from employees2
3 group by rollup(division_id)
4 order by division_id;
DIV SUM(SALARY)
--- -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
8881000
加上GROUPING来看看
SQL> select grouping(division_id),division_id,sum(salary)
2 from employees2
3 group by rollup(division_id)
4 order by division_id;
GROUPING(DIVISION_ID) DIV SUM(SALARY)
--------------------- --- -----------
0 BUS 1610000
0 OPE 1320000
0 SAL 4936000
0 SUP 1015000
1 8881000
可以看到,为空的地方返回1,非空的地方返回0。
2、使用CASE转换GROUPING()的返回值
可能你会觉得前面的0和1太枯燥了,代表不了任何意义,说白了就是不够人性化,呵呵。这个时候我们可以使用CASE来转换为一些有意义的值。
SQL> select
2 case grouping(division_id)
3 when 1 then 'all divisions'
4 else division_id
5 end as div,
6 sum(salary)
7 from employees2
8 group by rollup(division_id)
9 order by division_id;
DIV SUM(SALARY)
------------- -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
all divisions 8881000
3、使用CASE和GROUPING()转换多个列的值
SQL> select
2 case grouping(division_id)
3 when 1 then 'all divisions'
4 else division_id
5 end as div,
6 case grouping(job_id)
7 when 1 then 'all jobs'
8 else job_id
9 end as job,
10 sum(salary)
11 from employees2
12 group by rollup(division_id,job_id)
13 order by division_id,job_id;
DIV JOB SUM(SALARY)
------------- -------- -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
BUS all jobs 1610000
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
OPE all jobs 1320000
SAL MGR 4446000
SAL WOR 490000
SAL all jobs 4936000
DIV JOB SUM(SALARY)
------------- -------- -----------
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
SUP all jobs 1015000
all divisions all jobs 8881000
16 rows selected.
4、CUBE与GROUPING()结合使用
SQL> select
2 case grouping(division_id)
3 when 1 then 'all divisions'
4 else division_id
5 end as div,
6 case grouping(job_id)
7 when 1 then 'all jobs'
8 else job_id
9 end as job,
10 sum(salary)
11 from employees2
12 group by cube(division_id,job_id)
13 order by division_id,job_id;
DIV JOB SUM(SALARY)
------------- -------- -----------
BUS MGR 530000
BUS PRE 800000
BUS WOR 280000
BUS all jobs 1610000
OPE ENG 245000
OPE MGR 805000
OPE WOR 270000
OPE all jobs 1320000
SAL MGR 4446000
SAL WOR 490000
SAL all jobs 4936000
DIV JOB SUM(SALARY)
------------- -------- -----------
SUP MGR 465000
SUP TEC 115000
SUP WOR 435000
SUP all jobs 1015000
all divisions ENG 245000
all divisions MGR 6246000
all divisions PRE 800000
all divisions TEC 115000
all divisions WOR 1475000
all divisions all jobs 8881000
21 rows selected.
5、使用GROUPING SETS子句
使用GROUPING SETS子句可以只返回小计记录。
SQL> select division_id,job_id,sum(salary)
2 from employees2
3 group by grouping sets(division_id,job_id)
4 order by division_id,job_id;
DIV JOB SUM(SALARY)
--- --- -----------
BUS 1610000
OPE 1320000
SAL 4936000
SUP 1015000
ENG 245000
MGR 6246000
PRE 800000
TEC 115000
WOR 1475000
9 rows selected
当你与COUNT和SUM这类总计函数一起使用GROUP BY语句时,你一般得不到多级总数。GROUP BY中每个唯一的列组合生成一个总数,但这些总数不会“累加”到更高一级的总数中。
要实现这一点,你可以用GROUP BY ROLLUP或GROUP BY CUBE替代GROUP BY,不过它们会生成所有可能的总数,而你可能不需要全部总数。对GROUP BY CUBE而言,将会生成2^n组总数,这里的n是GROUP BY中列的数目。
查看下面的查询,它使用了SH样本模式:
SELECT prod_id, cust_id, channel_id, SUM(quantity_sold)
FROM sales
WHERE cust_id < 3
GROUP BY CUBE (prod_id, cust_id, channel_id)
这将生成8组总数:
所有行的总和
每个通道,包括所有产品和顾客
每个顾客,包括所有产品和通道
每项产品,包括所有顾客和通道
每个通道/顾客组合,包括所有产品
每个通道/产品组合,包括所有顾客
每个产品/顾客组合,包括所有通道
每个产品、顾客和通道组合
可能的组合非常多。GROUP BY CUBE中每增加一列,生成的总数就会翻一番。
可以用GROUP BY GROUPING SETS来代替GROUP BY CUBE。你可以应用来指定你感兴趣的总数组合。因为它不必计算它不需要集合(也不会产生太多结果),所以对SQL引擎来说更为高效。
其格式为:
GROUP BY GROUPING SETS ((list), (list) ... )
这里(list)是圆括号中的一个列序列,这个组合生成一个总数。要增加一个总和,必须增加一个(NUlL)分组集。
例如,如果只要生成每项产品(包括所有顾客和通道)和每个顾客/通道组合(包括所有产品)的总数,可以输入:
SELECT prod_id, cust_id, channel_id, SUM(quantity_sold)
FROM sales
WHERE cust_id < 3
GROUP BY GROUPING SETS (
(prod_id), (cust_id, channel_id)
);
这种方法将这个数据集生成的总数数量从180个减少到37个,并帮助你着重回答你希望解答的问题。