1、作用
grouping与grouping_id都是和group by rollup或group by cube同时出现的,实现了小计与总计的功能。
2、引入此函数目的
在小计与总计的字段,往往是NULL值,因此不容易区分并且写SQL时不美观且麻烦。
3、注意
grouping与grouping_id的字段,必须是group by的字段;
与rollup或cube关键字一同出现;
当字段为NULL时,grouping返回1,否则返回0;
当字段的后续列为NULL时,grouping_id返回1,当字段的前导列为NULL时,grouping_id返回2(仅当cube才出现此种情况),如果全部为NULL,则返回3,如果全不为NULL,则返回0.
3、示例
3.1、grouping
grouping函数的官方解释链接如下(11gR2):
http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions071.htm#SQLRF00647
代码1:
SELECT p_code,
MONTH,
COUNT(DISTINCT t_code),
COUNT(DISTINCT diag_code),
GROUPING(p_code),
GROUPING(MONTH)
FROM T1
WHERE p_code <= 100013
GROUP BY rollup(p_code,MONTH);
结果1可以看出,哪个值为NULL,对应的grouping字段为1.但是显得很不美观且代码有些冗余。
这段代码可以改写的更为简洁和美观:
代码2:
SELECT DECODE(GROUPING(p_code),1,'All p_code',p_code) AS p_code,
DECODE(GROUPING(MONTH),1,'All month',MONTH) AS MONTH,
COUNT(DISTINCT t_code),
COUNT(DISTINCT diag_code)
FROM T1
WHERE p_code <= 100013
GROUP BY rollup(p_code,MONTH);
从结果2可以看出,想要的结果1步得出。这时典型的小计和总计,当然结果也可以排序。
3.2、grouping_id
grouping_id函数的官方解释链接如下(11gR2):
http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions072.htm#SQLRF00648
代码3:
SELECT p_code,
MONTH,
GROUPING_id(p_code,MONTH),
COUNT(DISTINCT t_code),
COUNT(DISTINCT diag_code)
FROM T1
WHERE p_code <= 100013
GROUP BY rollup(p_code,MONTH);
代码3结果如下:
结果3可以看出,grouping_id也可以实现grouping的功能,但是优势是可以一次grouping_id多个字段。
如果只想得到每个值和总计,不想得到小计,则可以改写。
代码4:
SELECT CASE WHEN p_code IS NULL THEN 'All code' ELSE to_char(p_code) END AS p_code,
CASE WHEN MONTH IS NULL THEN 'All month' ELSE to_char(MONTH) END AS MONTH,
COUNT(DISTINCT t_code),
COUNT(DISTINCT diag_code)
FROM T1
WHERE p_code <= 100013
GROUP BY rollup(p_code,MONTH)
HAVING grouping_id(p_code,MONTH) IN (0,3);
结果4如下:
4、实际需求
需求1:统计2013年每个月以及全年的t_code的和。
代码:
--代码1
SELECT DECODE(grouping(MONTH),1,'2013 all year',MONTH) AS MONTH,
COUNT(t_code) AS cnt_t_code
FROM T1
WHERE MONTH BETWEEN 201301 AND 201312
GROUP BY ROLLUP(MONTH);
--代码2
SELECT CASE WHEN MONTH IS NOT NULL THEN to_char(MONTH)
WHEN MONTH IS NULL THEN '2013 all year'
END AS MONTH,
COUNT(t_code) AS cnt_t_code
FROM T1
WHERE MONTH BETWEEN 201301 AND 201312
GROUP BY rollup(MONTH);
--代码3
SELECT to_char(MONTH),
COUNT(t_code) AS cnt_t_code
FROM T1
WHERE MONTH BETWEEN 201301 AND 201312
GROUP BY MONTH
UNION ALL
SELECT '2013 all year',
COUNT(t_code) AS cnt_t_code
FROM T1
WHERE MONTH BETWEEN 201301 AND 201312;
很显然,代码1最简洁且高效。
需求2:统计2013年每个月、每个p_code(<=100013)所包含的t_code的和以及全年每个p_code(<=100013)的和以及全年所有p_code(<=100013)的和。
代码:
SELECT DECODE(GROUPING(MONTH),1,'all year',MONTH) AS MONTH,
DECODE(GROUPING(p_code),1,'all p_code',p_code) AS p_code,
COUNT(t_code) AS cnt_t_code
FROM T1
WHERE MONTH BETWEEN 201301 AND 201312
AND p_code <= 100013
GROUP BY CUBE(MONTH,p_code)
HAVING grouping_id(MONTH,p_code)IN (0,2,3)
ORDER BY 1,2;
这个sql用到了grouping与grouping_id共同使用,grouping的作用为了将NULL值(小计与总计)转化为非NULL,grouping_id的作用是过滤掉每个月的小计数量,只保留0,2,3的值;
0:代表2个字段都不为NULL;
1:代表每个月的小计(前导列不为NULL,后续列为NULL;此需求不要求这种数据);
2:代表每种p_code的小计(前导列为NULL,后续列不为NULL);
3:2个字段全部为NULL,即总计。