Oracle GROUPING函数的使用


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个,并帮助你着重回答你希望解答的问题。

相关内容