ORACLE 分析函数(sets,cube,rollup,rank(),dense_rank(),row_number()lag和lead)

A. rollup、cube、grouping sets区别:

如果是ROLLUP(A, B, C)的话,GROUP BY顺序
(A、B、C)
(A、B)
(A)
最后对全表进行GROUP BY操作。

如果是GROUP BY CUBE(A, B, C),GROUP BY顺序
(A、B、C)
(A、B)
(A、C)
(A)
(B、C)
(B)
(C),
最后对全表进行GROUP BY操作。

如果是 GROUP BY grouping SETS(A, B, C),GROUP BY顺序
首先对(A)进行GROUP BY
然后是(B)进行GROUP BY
最后是(C)进行GROUP BY
  1. 創建測試表
[oracle@DB01 ~]$ sql BUS/[email protected]:1521/MPBUS

SQL> SET SQLFORMAT ansiconsole

SQL> create table tmp1(CITY varchar2(20), PRODUCT varchar2(20), YEAR number, SALES number);

SQL> 
insert into tmp1 values ('北京','彩電', 1999, 1000);
insert into tmp1 values ('北京','彩電', 2000, 2000);
insert into tmp1 values ('北京','彩電', 2001, 3000);
insert into tmp1 values ('北京','冰箱', 1999, 4000);
insert into tmp1 values ('北京','冰箱', 2000, 5000);
insert into tmp1 values ('北京','冰箱', 2001, 6000);
insert into tmp1 values ('天津','彩電', 1999, 1100);
insert into tmp1 values ('天津','彩電', 2000, 2100);
insert into tmp1 values ('天津','彩電', 2001, 3100);
insert into tmp1 values ('天津','冰箱', 1999, 4100);
insert into tmp1 values ('天津','冰箱', 2000, 5100);
insert into tmp1 values ('天津','冰箱', 2001, 6100);
commit;

SQL> select * from tmp1;
CITY  PRODUCT  YEAR  SALES  
北京    彩電       1999  1000   
北京    彩電       2000  2000   
北京    彩電       2001  3000   
北京    冰箱       1999  4000   
北京    冰箱       2000  5000   
北京    冰箱       2001  6000   
天津    彩電       1999  1100   
天津    彩電       2000  2100   
天津    彩電       2001  3100   
天津    冰箱       1999  4100   
天津    冰箱       2000  5100   
天津    冰箱       2001  6100
  1. sum函数,统计总合
#按照年份,统计每個城市的总收入
SQL> select year, city, sum(sales)  
     from tmp1 group by year, city; 
YEAR  CITY  SUM(SALES)  
1999  北京    5000        
2001  北京    9000        
2000  北京    7000        
2001  天津    9200        
1999  天津    5200        
2000  天津    7200 
  1. rollup函数(A,B)
#按照年份,统计每個城市的总收入
#首先对(A、B)进行GROUP BY,
#然后是(A)进行GROUP BY,
#最后对全表进行GROUP BY操作

SQL> select year, city, sum(sales)  
     from tmp1 group by rollup(year, city)
     order by year,city; 
YEAR  CITY  SUM(SALES)  
1999  北京    5000        
1999  天津    5200        
1999        10200       
2000  北京    7000        
2000  天津    7200        
2000        14200       
2001  北京    9000        
2001  天津    9200        
2001        18200       
            42600

SQL> select 
      decode(grouping(year),1,'全年',year) "年份" 
     ,decode(grouping(city),1,'全市',city) "城市"
     ,sum(sales) "金额"  
     from tmp1 group by rollup(year, city)
     order by year,city;
年份    城市  金额     
1999  北京  5000   
1999  天津  5200   
1999  全市  10200  
2000  北京  7000   
2000  天津  7200   
2000  全市  14200  
2001  北京  9000   
2001  天津  9200   
2001  全市  18200  
全年   全市  42600 
  1. cube函数(A,B)
#按照年份,统计每個城市的总收入
#首先会对(A、B)进行GROUP BY,
#然后依次是(A),(B)
#最后对全表进行GROUP BY操作

SQL> select year, city, sum(sales)  
     from tmp1 group by cube(year, city)
     order by year,city nulls last; 
YEAR  CITY  SUM(SALES)  
1999  北京    5000        
1999  天津    5200        
1999        10200       
2000  北京    7000        
2000  天津    7200        
2000        14200       
2001  北京    9000        
2001  天津    9200        
2001        18200       
      北京    21000       
      天津    21600       
            42600 

#grouping函数
#在以上例子中,是用rollup和cube函数都会对结果集产生null,这时候可用grouping函数来确认
#该记录是由哪个字段得出来的
#grouping函数用法,带一个参数,参数为字段名,如果当前行是由rollup或者cube汇总得来的,结果就返回1,反之返回0
SQL> select 
      decode(grouping(year),1,'全年',year) "年份" 
     ,decode(grouping(city),1,'全市',city) "城市"
     ,sum(sales) "金额"  
     from tmp1 group by cube(year, city)
     order by year,city nulls last; 
年份    城市  金额     
1999  北京  5000   
1999  天津  5200   
1999  全市  10200  
2000  北京  7000   
2000  天津  7200   
2000  全市  14200  
2001  北京  9000   
2001  天津  9200   
2001  全市  18200  
全年   北京  21000  
全年   天津  21600  
全年   全市  42600 
  1. sets函数(A,B)
#按照年份,统计每個城市的总收入
#首先对(A)进行GROUP BY
#然后是(B)进行GROUP BY
SQL> select year, city, sum(sales)  
     from tmp1 group by grouping sets(year, city)
     order by year,city; 
YEAR  CITY  SUM(SALES)  
1999        10200       
2000        14200       
2001        18200       
      北京    21000       
      天津    21600 

SQL> select 
     decode(grouping(year),1,'全年',year) "年份" 
    ,decode(grouping(city),1,'全市',city) "城市"
    ,sum(sales) "金额"  
    from tmp1 group by grouping sets(year, city)
    order by year,city;

年份    城市  金额     
1999  全市  10200  
2000  全市  14200  
2001  全市  18200  
全年    北京  21000  
全年    天津  21600

B.rank,dense_rank,row_number的区别:

结果集中如果出现两个相同的数据,那么rank会进行跳跃式的排名,
比如两个第1,那么没有第2接下来就是第3(如 1,1,3);
但是dense_rank不会跳跃式的排名,两个第1接下来还是第2(1,1,2);
row_number最牛,即使两个数据相同,排名也不一样(1,2,3)。
  1. 分析函数初始化数据
create table earnings -- 打工赚钱表  
(  
  earnmonth varchar2(6), -- 打工月份  
  area varchar2(20), -- 打工地区  
  sname varchar2(20), -- 打工者姓名  
  times int, -- 本月打工次数  
  singleincome number(10,2), -- 每次赚多少钱  
  personincome number(10,2) -- 当月总收入  
) ;

insert into earnings values('200912','北平','大魁',11,30,11*30);  
insert into earnings values('200912','北平','大凯',8,25,8*25);  
insert into earnings values('200912','北平','小东',30,6.25,30*6.25);  
insert into earnings values('200912','北平','大亮',16,8.25,16*8.25);  
insert into earnings values('200912','北平','贱敬',30,11,30*11);  
  
insert into earnings values('200912','金陵','小玉',15,12.25,15*12.25);  
insert into earnings values('200912','金陵','小凡',27,16.67,27*16.67);  
insert into earnings values('200912','金陵','小妮',7,33.33,7*33.33);  
insert into earnings values('200912','金陵','小俐',0,18,0);  
insert into earnings values('200912','金陵','雪儿',11,9.88,11*9.88);  
  
insert into earnings values('201001','北平','大魁',0,30,0);  
insert into earnings values('201001','北平','大凯',14,25,14*25);  
insert into earnings values('201001','北平','小东',19,6.25,19*6.25);  
insert into earnings values('201001','北平','大亮',7,8.25,7*8.25);  
insert into earnings values('201001','北平','贱敬',21,11,21*11);  
  
insert into earnings values('201001','金陵','小玉',6,12.25,6*12.25);  
insert into earnings values('201001','金陵','小凡',17,16.67,17*16.67);  
insert into earnings values('201001','金陵','小妮',27,33.33,27*33.33);  
insert into earnings values('201001','金陵','小俐',16,18,16*18);  
insert into earnings values('201001','金陵','雪儿',11,9.88,11*9.88); 
commit;
  1. rank() over开窗函数
#重复值所在行的序列值相同,但其后的序列值从重复行数开始递增(如1,1,3 【跳过2】)
#按照月份、地区,求打工收入排序
SQL> select earnmonth 月份,area 地区,sname 打工者, personincome 收入,   
           rank() over (partition by earnmonth,area order by personincome desc) 排名  
     from earnings;
月份      地区  打工者  收入      排名  
200912  北平  大魁   330     1   
200912  北平  贱敬   330     1   
200912  北平  大凯   200     3   
200912  北平  小东   187.5   4   
200912  北平  大亮   132     5   
200912  金陵  小凡   450.09  1   
200912  金陵  小妮   233.31  2   
200912  金陵  小玉   183.75  3   
200912  金陵  雪儿   108.68  4   
200912  金陵  小俐   0       5   
...
  1. dense_rank() over开窗函数
#排序时如果遇到列有重复值,则重复值所在行的序列值相同,而其后的序列值依旧递增(如 1,1,2)
#按照月份、地区,求打工收入排序
SQL> select earnmonth 月份,area 地区,sname 打工者, personincome 收入,   
           dense_rank() over (partition by earnmonth,area order by personincome desc) 排名  
     from earnings; 
月份      地区  打工者  收入      排名  
200912  北平  大魁   330     1   
200912  北平  贱敬   330     1   
200912  北平  大凯   200     2   
200912  北平  小东   187.5   3   
200912  北平  大亮   132     4   
200912  金陵  小凡   450.09  1   
200912  金陵  小妮   233.31  2   
200912  金陵  小玉   183.75  3   
200912  金陵  雪儿   108.68  4   
200912  金陵  小俐   0       5   
...
  1. row_number() over
#不管是否有重复行,(分组内)序列值始终递增
#按照月份、地区,求打工收入排序
SQL> select earnmonth 月份,area 地区,sname 打工者, personincome 收入,     
        row_number() over (partition by earnmonth,area order by personincome desc) 排名 
       from earnings;  
月份      地区  打工者  收入      排名  
200912  北平  大魁   330     1   
200912  北平  贱敬   330     2   
200912  北平  大凯   200     3   
200912  北平  小东   187.5   4   
200912  北平  大亮   132     5   
200912  金陵  小凡   450.09  1   
200912  金陵  小妮   233.31  2   
200912  金陵  小玉   183.75  3   
200912  金陵  雪儿   108.68  4   
200912  金陵  小俐   0       5   
...
  1. sum累计求和 (逐条求和)
SQL> select earnmonth 月份,area 地区,sname 打工者,personincome as 收入
     ,sum(personincome) over (partition by earnmonth,area order by personincome) 逐条累加收入  
     from earnings;
月份    地区  打工者  收入    逐条累加收入   
200912  北平  大亮   132     132      
200912  北平  小东   187.5   319.5    
200912  北平  大凯   200     519.5    
200912  北平  大魁   330     1179.5   
200912  北平  贱敬   330     1179.5   
200912  金陵  小俐   0       0        
200912  金陵  雪儿   108.68  108.68   
200912  金陵  小玉   183.75  292.43   
200912  金陵  小妮   233.31  525.74   
200912  金陵  小凡   450.09  975.83   
...
  1. max,min,avg和sum函数综合运用
#按照月份和地区求打工收入最高值,最低值,平均值和总额
SQL> select distinct earnmonth 月份, area 地区,  
            max(personincome) over(partition by earnmonth,area) 最高值,  
            min(personincome) over(partition by earnmonth,area) 最低值,  
            avg(personincome) over(partition by earnmonth,area) 平均值,  
            sum(personincome) over(partition by earnmonth,area) 总额  
     from earnings; 
月份      地区  最高值     最低值   平均值      总额       
200912  金陵  450.09  0     195.166  975.83   
200912  北平  330     132   235.9    1179.5   
...

SQL> select earnmonth 月份, area 地区,  
  2         max(personincome) over(partition by earnmonth,area) 最高值,  
  3         min(personincome) over(partition by earnmonth,area) 最低值,  
  4         avg(personincome) over(partition by earnmonth,area) 平均值,  
  5         sum(personincome) over(partition by earnmonth,area) 总额  
  6  from earnings;
月份      地区  最高值     最低值   平均值      总额       
200912  北平  330     132   235.9    1179.5   
200912  北平  330     132   235.9    1179.5   
200912  北平  330     132   235.9    1179.5   
200912  北平  330     132   235.9    1179.5   
200912  北平  330     132   235.9    1179.5   
200912  金陵  450.09  0     195.166  975.83   
200912  金陵  450.09  0     195.166  975.83   
200912  金陵  450.09  0     195.166  975.83   
200912  金陵  450.09  0     195.166  975.83   
200912  金陵  450.09  0     195.166  975.83
...
  1. lag和lead函数
#说明:Lag和Lead函数可以在一次查询中取出某个字段的前N行和后N行的数据(可以是其他字段的数据,比如根据字段甲查询上一行或下两行的字段乙)
#语法如下:
lag(value_expression [,offset] [,default]) over ([query_partition_clase] order_by_clause);
lead(value_expression [,offset] [,default]) over ([query_partition_clase] order_by_clause);
其中:
value_expression:可以是一个字段或一个内建函数。
offset是正整数,默认为1,指往前或往后几点记录.因组内第一个条记录没有之前的行,最后一行没有之后的行,
default就是用于处理这样的信息,默认为空。

#求出每个打工者上个月和下个月收入
SQL> select earnmonth 本月,sname 打工者,  
     lag(personincome,1,0) over(partition by sname order by earnmonth) 上月收入,  
     personincome as 本月收入,
     lead(personincome,1,0) over(partition by sname order by earnmonth) 下月收入  
     from earnings order by sname,earnmonth; 

本月    打工者  上月收入  本月收入    下月收入    
200912  大亮   0         132           57.75   
201001  大亮   132       57.75         0       
200912  大凯   0         200           350     
201001  大凯   200       350           0       
200912  大魁   0         330           0       
201001  大魁   330       0             0 
...
  1. GROUP BY grouping sets(A, B, C)
#首先对(A)进行GROUP BY
#然后是(B)进行GROUP BY
#最后是(C)进行GROUP BY

SQL>  select city, product, year, sum(sales)
     from tmp1
     group by grouping sets (city,product,year);

CITY  PRODUCT  YEAR  SUM(SALES)  
               1999  10200       
               2001  18200       
               2000  14200       
天津                   21600       
北京                   21000       
      冰箱             30300       
      彩電             12300 

or

SQL>  
     select city, null as product,null as year,sum(sales)
     from tmp1
     group by city
     union all
     select null city, product,null as year,sum(sales)
     from tmp1
     group by product
     union all
     select null city, null as product,year,sum(sales)
    from tmp1
    group by year;

CITY  PRODUCT  YEAR  SUM(SALES)  
天津                   21600       
北京                   21000       
      冰箱             30300       
      彩電             12300       
               1999  10200       
               2001  18200       
               2000  14200
  1. GROUP BY CUBE(A, B, C)
#首先会对(A、B、C)进行GROUP BY,
#然后依次是(A、B),(A、C),(A),(B、C),(B),(C),
#最后对全表进行GROUP BY操作

SQL> select city, product, year, sum(sales)
    from tmp1 group by CUBE(city,product,year)
    order by city, product, year nulls last; 

CITY  PRODUCT  YEAR  SUM(SALES)  
北京    冰箱       1999  4000        
北京    冰箱       2000  5000        
北京    冰箱       2001  6000        
北京    冰箱             15000       
北京    彩電       1999  1000        
北京    彩電       2000  2000        
北京    彩電       2001  3000        
北京    彩電             6000        
北京             1999  5000        
北京             2000  7000        
北京             2001  9000        
北京                   21000       
天津    冰箱       1999  4100        
天津    冰箱       2000  5100        
天津    冰箱       2001  6100        
天津    冰箱             15300       
天津    彩電       1999  1100        
天津    彩電       2000  2100        
天津    彩電       2001  3100        
天津    彩電             6300        
天津             1999  5200        
天津             2000  7200        
天津             2001  9200        
天津                   21600       
      冰箱       1999  8100        
      冰箱       2000  10100       
      冰箱       2001  12100       
      冰箱             30300       
      彩電       1999  2100        
      彩電       2000  4100        
      彩電       2001  6100        
      彩電             12300       
               1999  10200       
               2000  14200       
               2001  18200       
                     42600
  1. GROUP BY A,CUBE(B, C)
#首先会对(A、B、C)进行GROUP BY,
#然后依次是(A、B),(A、C)
#最后对(A)进行GROUP BY操作
SQL> 
     select city,product,year,sum(sales)
     from tmp1 group by city,CUBE(product,year)
     order by city, product, year nulls last;

CITY  PRODUCT  YEAR  SUM(SALES)  
北京    冰箱       1999  4000        
北京    冰箱       2000  5000        
北京    冰箱       2001  6000        
北京    冰箱             15000       
北京    彩電       1999  1000        
北京    彩電       2000  2000        
北京    彩電       2001  3000        
北京    彩電             6000        
北京             1999  5000        
北京             2000  7000        
北京             2001  9000        
北京                   21000       
天津    冰箱       1999  4100        
天津    冰箱       2000  5100        
天津    冰箱       2001  6100        
天津    冰箱             15300       
天津    彩電       1999  1100        
天津    彩電       2000  2100        
天津    彩電       2001  3100        
天津    彩電             6300        
天津             1999  5200        
天津             2000  7200        
天津             2001  9200        
天津                   21600

  1. ROLLUP(A, B, C)
#首先会对(A、B、C)进行GROUP BY,
#然后对(A、B)进行GROUP BY,
#然后是(A)进行GROUP BY,
#最后对全表进行GROUP BY操作。
SQL> 
   select city,product,year,sum(sales)
    from tmp1 group by rollup(city,product,year)
    order by city, product, year nulls last;

CITY  PRODUCT  YEAR  SUM(SALES)  
北京    冰箱       1999  4000        
北京    冰箱       2000  5000        
北京    冰箱       2001  6000        
北京    冰箱             15000       
北京    彩電       1999  1000        
北京    彩電       2000  2000        
北京    彩電       2001  3000        
北京    彩電             6000        
北京                   21000       
天津    冰箱       1999  4100        
天津    冰箱       2000  5100        
天津    冰箱       2001  6100        
天津    冰箱             15300       
天津    彩電       1999  1100        
天津    彩電       2000  2100        
天津    彩電       2001  3100        
天津    彩電             6300        
天津                   21600       
                     42600          
  1. A,ROLLUP(B, C)
#首先会对(A、B、C)进行GROUP BY,
#然后对(A、B)进行GROUP BY,
#最后是(A)进行GROUP BY,
SQL> 
     select city, product,year,sum(sales)
     from tmp1 group by city,rollup(product,year)
     order by city, product, year nulls last;

CITY  PRODUCT  YEAR  SUM(SALES)  
北京    冰箱       1999  4000        
北京    冰箱       2000  5000        
北京    冰箱       2001  6000        
北京    冰箱             15000       
北京    彩電       1999  1000        
北京    彩電       2000  2000        
北京    彩電       2001  3000        
北京    彩電             6000        
北京                     21000       
天津    冰箱       1999  4100        
天津    冰箱       2000  5100        
天津    冰箱       2001  6100        
天津    冰箱             15300       
天津    彩電       1999  1100        
天津    彩電       2000  2100        
天津    彩電       2001  3100        
天津    彩電             6300        
天津                    21600         

你可能感兴趣的:(ORACLE 分析函数(sets,cube,rollup,rank(),dense_rank(),row_number()lag和lead))