Oracle函数之聚合函数---1、关于grouping与grouping_id

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如下:

Oracle函数之聚合函数---1、关于grouping与grouping_id_第1张图片


结果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如下:


Oracle函数之聚合函数---1、关于grouping与grouping_id_第2张图片

从结果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结果如下:

Oracle函数之聚合函数---1、关于grouping与grouping_id_第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如下:

Oracle函数之聚合函数---1、关于grouping与grouping_id_第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;

结果:

Oracle函数之聚合函数---1、关于grouping与grouping_id_第5张图片


很显然,代码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;

结果:

Oracle函数之聚合函数---1、关于grouping与grouping_id_第6张图片

这个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,即总计。




你可能感兴趣的:(sql与plsql)