Oracle分析函数详述1

一.分析函数(OVER)

目录:
===============================================
1.Oracle分析函数简介
2. Oracle分析函数简单实例
3.分析函数OVER解析

一、Oracle分析函数简介:

在日常的生产环境中,我们接触得比较多的是OLTP系统(即Online Transaction Process),这些系统的特点是具备实时要求,或者至少说对响应的时间多长有一定的要求;其次这些系统的业务逻辑一般比较复杂,可能需要经过多次的运算。比如我们经常接触到的电子商城。

在这些系统之外,还有一种称之为OLAP的系统(即Online Aanalyse Process),这些系统一般用于系统决策使用。通常和数据仓库、数据分析、数据挖掘等概念联系在一起。这些系统的特点是数据量大,对实时响应的要求不高或者根本不关注这方面的要求,以查询、统计操作为主。

我们来看看下面的几个典型例子:
①查找上一年度各个销售区域排名前10的员工
②按区域查找上一年度订单总额占区域订单总额20%以上的客户
③查找上一年度销售最差的部门所在的区域
④查找上一年度销售最好和最差的产品

我们看看上面的几个例子就可以感觉到这几个查询和我们日常遇到的查询有些不同,具体有:

①需要对同样的数据进行不同级别的聚合操作
②需要在表内将多条数据和同一条数据进行多次的比较
③需要在排序完的结果集上进行额外的过滤操作

二、Oracle分析函数简单实例:

下面我们通过一个实际的例子:按区域查找上一年度订单总额占区域订单总额20%以上的客户,来看看分析函数的应用。

【1】测试环境:

SQL >   desc  orders_tmp;
 Name                          
Null ?    Type
 
-- --------------------- -------- ----------------
 CUST_NBR                    NOT   NULL   NUMBER ( 5 )
 REGION_ID                  
NOT   NULL   NUMBER ( 5 )
 SALESPERSON_ID      
NOT   NULL   NUMBER ( 5 )
 
YEAR                               NOT   NULL   NUMBER ( 4 )
 
MONTH                          NOT   NULL   NUMBER ( 2 )
 TOT_ORDERS              
NOT   NULL   NUMBER ( 7 )
 TOT_SALES                
NOT   NULL   NUMBER ( 11 , 2 )

【2】测试数据:
SQL >   select   *   from  orders_tmp;

  CUST_NBR  REGION_ID SALESPERSON_ID       
YEAR        MONTH  TOT_ORDERS  TOT_SALES
-- -------- ---------- -------------- ---------- ---------- ---------- ----------
        11            7               11                         2001            7            2        12204
        
4            5                4                          2001           10           2        37802
        
7            6                7                          2001            2            3         3750
       
10            6                8                          2001            1            2        21691
       
10            6                7                          2001            2            3        42624
       
15            7               12                         2000            5            6           24
       
12            7                9                         2000            6            2        50658
        
1            5                2                          2000            3            2        44494
        
1            5                1                          2000            9            2        74864
        
2            5                4                           2000            3            2        35060
        
2            5                4                          2000            4            4         6454
        
2            5                1                          2000           10            4        35580
        
4            5                4                          2000           12            2        39190

13  rows selected.

【3】测试语句:
SQL >   select  o.cust_nbr customer,
 
2          o.region_id region,
 
3           sum (o.tot_sales) cust_sales,
 
4           sum(sum(o.tot_sales)) over(partition by o.region_id) region_sales
 
5      from  orders_tmp o
 
6     where  o. year   =   2001
 
7     group by o.region_id, o.cust_nbr;

  CUSTOMER     REGION CUST_SALES REGION_SALES
-- -------- ---------- ---------- ------------
         4               5        37802          37802
        
7               6         3750          68065
       
10              6        64315          68065
       
11              7        12204          12204


三、分析函数OVER解析:

请注意上面的绿色高亮部分,group by的意图很明显:将数据按区域ID,客户进行分组,那么Over这一部分有什么用呢?假如我们只需要统计每个区域每个客户的订单总额,那么我们只需要 group by o.region_id,o.cust_nbr就够了。但我们还想在每一行显示该客户所在区域的订单总额,这一点和前面的不同:需要在前面分组的基础上按区域累加。很显然group by和sum是无法做到这一点的(因为聚集操作的级别不一样,前者是对一个客户,后者是对一批客户)。

这就是over函数的作用了!它的作用是告诉SQL引擎:按区域对数据进行分区,然后累积每个区域每个客户的订单总额(sum(sum(o.tot_sales)))。

现在我们已经知道2001年度每个客户及其对应区域的订单总额,那么下面就是筛选那些个人订单总额占到区域订单总额20%以上的大客户了
SQL >   select   *
 
2      from  ( select  o.cust_nbr customer,
 
3                  o.region_id region,
 
4                   sum (o.tot_sales) cust_sales,
 
5                   sum ( sum (o.tot_sales))  over (partition  by  o.region_id) region_sales
 
6              from  orders_tmp o
 
7             where  o. year   =   2001
 
8             group   by  o.region_id, o.cust_nbr) all_sales
 
9     where all_sales.cust_sales > all_sales.region_sales * 0.2;

  CUSTOMER     REGION CUST_SALES REGION_SALES
-- -------- ---------- ---------- ------------
         4            5        37802          37802
       
10            6        64315          68065
       
11            7        12204          12204

SQL
>  

现在我们已经知道这些大客户是谁了!哦,不过这还不够,如果我们想要知道每个大客户所占的订单比例呢?看看下面的SQL语句,只需要一个简单的Round函数就搞定了。
SQL >   select  all_sales. * ,
 
2           100 * round(cust_sales / region_sales, 2|| '%' Percent
  3      from  ( select  o.cust_nbr customer,
 
4                  o.region_id region,
 
5                   sum (o.tot_sales) cust_sales,
 
6                   sum ( sum (o.tot_sales))  over (partition  by  o.region_id) region_sales
 
7              from  orders_tmp o
 
8             where  o. year   =   2001
 
9             group   by  o.region_id, o.cust_nbr) all_sales
 
10     where  all_sales.cust_sales  >  all_sales.region_sales  *   0.2 ;

  CUSTOMER     REGION CUST_SALES REGION_SALES 
PERCENT
-- -------- ---------- ---------- ------------ ----------------------------------------
         4              5                   37802          37802     100 %
       
10            6                   64315          68065       94 %
       
11            7                   12204          12204     100 %

SQL
>  

总结:

①Over函数指明在那些字段上做分析,其内跟Partition by表示对数据进行分组。注意Partition by可以有多个字段。

②Over函数可以和其它聚集函数、分析函数搭配,起到不同的作用。例如这里的SUM,还有诸如Rank,Dense_rank等。


一.分析函数2(rank\dense_rank\row_number)

目录
===============================================
1.使用rownum为记录排名
2.使用分析函数来为记录排名
3.使用分析函数为记录进行分组排名

一、使用rownum为记录排名:

在前面一篇《Oracle开发专题之:分析函数》,我们认识了分析函数的基本应用,现在我们再来考虑下面几个问题:

①对所有客户按订单总额进行排名
②按区域和客户订单总额进行排名
③找出订单总额排名前13位的客户
④找出订单总额最高、最低的客户
⑤找出订单总额排名前25%的客户


按照前面第一篇文章的思路,我们只能做到对各个分组的数据进行统计,如果需要排名的话那么只需要简单地加上rownum不就行了吗?事实情况是否如此想象般简单,我们来实践一下。

【1】测试环境:

SQL >   desc  user_order;
 Name                                      
Null ?    Type
 
-- --------------------------------------- -------- ----------------------------
 REGION_ID                                           NUMBER ( 2 )
 CUSTOMER_ID                                  
NUMBER ( 2 )
 CUSTOMER_SALES                          
NUMBER

【2】测试数据:
SQL >   select   *   from  user_order  order   by  customer_sales;

 REGION_ID CUSTOMER_ID CUSTOMER_SALES
-- -------- ----------- --------------
         5             1               151162
       
10            29              903383
        
6             7               971585
       
10            28             986964
        
9            21             1020541
        
9            22            1036146
        
8            16            1068467
        
6             8             1141638
        
5             3             1161286
        
5             5             1169926
        
8            19            1174421
        
7            12            1182275
        
7            11            1190421
        
6            10            1196748
        
6             9             1208959
       
10            30            1216858
        
5             2                1224992
           9             24              1224992
           9             23              1224992
          
8            18            1253840
        
7            15            1255591
        
7            13            1310434
       
10            27           1322747
        
8            20            1413722
        
6             6             1788836
       
10            26           1808949
        
5             4             1878275
        
7            14            1929774
        
8            17            1944281
        
9            25            2232703

30  rows selected.

注意这里有3条记录的订单总额是一样的。假如我们现在需要筛选排名前12位的客户,如果使用rownum会有什么样的后果呢?
SQL >   select  rownum, t. *
 
2      from  ( select   *  
 
3              from  user_order
 
4             order   by  customer_sales  desc ) t
 
5     where  rownum  <=   12
 
6     order   by  customer_sales  desc ;

    ROWNUM  REGION_ID CUSTOMER_ID CUSTOMER_SALES
-- -------- ---------- ----------- --------------
         1            9                  25          2232703
        
2            8                  17          1944281
        
3            7                   14          1929774
        
4            5                     4          1878275
        
5           10                  26          1808949
        
6            6                    6          1788836
        
7            8                  20          1413722
        
8           10                 27          1322747
        
9            7                 13          1310434
       
10            7                15          1255591
       
11            8                18          1253840
         
12             5                     2          1224992

12  rows selected.

很明显假如只是简单地按rownum进行排序的话,我们漏掉了另外两条记录(参考上面的结果)。

二、使用分析函数来为记录排名:

针对上面的情况,Oracle从8i开始就提供了3个分析函数:rand,dense_rank,row_number来解决诸如此类的问题,下面我们来看看这3个分析函数的作用以及彼此之间的区别:

Rank,Dense_rank,Row_number函数为每条记录产生一个从1开始至N的自然数,N的值可能小于等于记录的总数。这3个函数的唯一区别在于当碰到相同数据时的排名策略。

①ROW_NUMBER:

Row_number函数返回一个唯一的值,当碰到相同数据时,排名按照记录集中记录的顺序依次递增。 

②DENSE_RANK:
Dense_rank函数返回一个唯一的值,除非当碰到相同数据时,此时所有相同数据的排名都是一样的。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值