ORACLE OLAP 函数

ORACLE OLAP 函数
===========================================================
最近这个东东用得特别多,总结了一下 。

语法: FUNCTION_NAME( , ,...)
        OVER
        ( )

OLAP函数语法四个部分:
1、function本身 用于对窗口中的数据进行操作;
2、partitioning clause 用于将结果集分区;
3、order by clause 用于对分区中的数据进行排序;
4、windowing clause 用于定义function在其上操作的行的集合,即function所影响的范围。


一、order by对窗口的影响

不含order by的:
SQL> select deptno,sal,sum(sal) over()
  2  from emp;

 DEPTNO   SAL  SUM(SAL)OVER()
 ---------   -----  -------------------
         20   800                 24028
         30  1600                24028
         30  1250                24028
         20  2975                24028
         30  1250                24028
         30  2850                24028
         10  2450                24028
         20  3000                24028
         30  1500                24028
         20  1100                24028
         30    950                24028
         20  3000                24028
         10  1300                24028
          0                          24028
          0        1                24028
          0        2                24028

已选择16行。

已用时间:  00: 00: 00.03

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=13 Bytes=91)
   1    0   WINDOW (BUFFER) (Cost=2 Card=13 Bytes=91)
   2    1     TABLE ACCESS (FULL) OF 'EMP' (Cost=2 Card=13 Bytes=91)

不含order by时,默认的窗口是从结果集的第一行直到末尾。
因此我们看到的结果是,为所有的sal计算了一个合计值。


含order by的:
SQL> select deptno,sal,
  2         sum(sal) over(order by deptno) as sumsal
  3  from emp;

 DEPTNO   SAL  SUMSAL
----------- ------ ----------
            0                    3
            0     1             3
            0     2             3
          10  2450      3753
          10  1300      3753——3753=1+2+2450+1300
          20   800     14628
          20  3000    14628
          20  3000    14628
          20  1100    14628
          20  2975    14628
          30  1600    24028
          30    950    24028
          30  1500    24028
          30  2850    24028
          30  1250    24028
          30  1250    24028

已选择16行。

已用时间:  00: 00: 00.03

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=13 Bytes=91)
   1    0   WINDOW (SORT) (Cost=4 Card=13 Bytes=91)
   2    1     TABLE ACCESS (FULL) OF 'EMP' (Cost=2 Card=13 Bytes=91)

我们看到执行计划变了,窗口受到了order by的影响。
当含有order by时,默认的窗口是从第一行直到当前分组的最后一行。
sum会计算当前组所有值和前面所有行的合计值。


二、用于排列的函数

SQL> select empno, deptno, sal,
  2         rank() over
  3         (partition by deptno order by sal desc nulls last) as rank,
  4         dense_rank() over
  5         (partition by deptno order by sal desc nulls last) as dense_rank,
  6         row_number() over
  7         (partition by deptno order by sal desc nulls last) as row_number
  8   from  emp;

 EMPNO  DEPTNO   SAL  RANK  DENSE_RANK  ROW_NUMBER
--------- ---------- ------- ------- ---------------- -----------------
    9999            0       2         1                    1                    1
    9999            0       1         2                    2                    2
    9999            0                  3                    3                    3

    7839          10  5000         1                    1                    1
    7782          10  2450         2                    2                    2
    7934          10  1300         3                    3                    3

    7788          20  3000         1                    1                    1
    7902          20  3000         1                    1                    2
    7566          20  2975         3                    2                    3
    7876          20  1100         4                    3                    4
    7369          20    800         5                    4                    5

    7698          30  2850         1                    1                    1
    7499          30  1600         2                    2                    2
    7844          30  1500         3                    3                    3
    7521          30  1250         4                    4                    4
    7654          30  1250         4                    4                    5
    7900          30    950         6                    5                    6

已选择17行。

nulls last:强制NULL值放在最后,否则在降序排列时NULL会被排在最前面。


三、用于合计的函数


SQL> select deptno,sal,
  2         sum(sal) over (partition by deptno) as sumsal,
  3         avg(sal) over (partition by deptno) as avgsal,
  4         count(*) over (partition by deptno) as count,
  5         max(sal) over (partition by deptno) as maxsal
  6    from emp;

 DEPTNO    SAL  SUMSAL  AVGSAL  COUNT  MAXSAL
----------- ------- ---------- ---------- --------- ----------
            0                     3            3       2
            0        1           3            3       2
            0        2           3            3       2
                               
          10   2450     8750     2916.6      3          5000
          10   5000     8750     2916.6      3          5000
          10   1300     8750     2916.6      3          5000
                               
          20    800    10875                     5          3000
          20   1100   10875                     5          3000
          20   3000   10875                     5          3000
          20   3000   10875                     5          3000
          20   2975   10875                     5          3000
                               
          30   1600     9400     1566.6      6          2850
          30   2850     9400     1566.6      6          2850
          30   1250     9400     1566.6      6          2850
          30     950     9400     1566.6      6          2850
          30   1500     9400     1566.6      6          2850
          30   1250     9400     1566.6      6          2850

已选择17行。

                                                           
四、开窗语句

1、rows窗口: "rows 5 preceding"

适用于任何类型而且可以order by多列。

SQL> select deptno,ename,sal,
  2         sum(sal) over (order by deptno rows 2 preceding) sumsal
  3    from emp;

 DEPTNO ENAME     SAL   SUMSAL
---------- ----------  ------ ----------
          0  aaa   
          0  aaa               1           1
          0  aaa               2           3
        10  Clark        2450      2453 ——2453=1+2+2450
        10  Miller        1300      3752
        20  Smith         800      4550
        20  Scott        3000      5100
        20  Ford         3000      6800
        20  Adams     1100      7100
        20  Jones       2975      7075
        30  Allen        1600      5675
        30  James        950      5525
        30  Turner     1500      4050
        30  Blake       2850      5300
        30  Martin      1250      5600
        30  Ward       1250      5350

已选择16行。

rows 2 preceding:将当前行和它前面的两行划为一个窗口,因此sum函数就作用在这三行上面。


SQL> select deptno,ename,sal,
  2         sum(sal) over
  3         (partition by deptno order by ename rows 2 preceding) sumsal
  4    from emp
  5  order by deptno,ename;

 DEPTNO ENAME      SAL   SUMSAL
---------- ---------    ------ -----------
           0 aaa
           0 aaa                1             1
           0 aaa                2             3

         10 Clark        2450        2450
         10 Miller        1300        3750

         20 Adams      1100         1100 ——仍然为1100
         20 Ford         3000         4100
         20 Jones       2975         7075 ——7075=1100+3000+2975
         20 Scott        3000         8975
         20 Smith         800         6775

         30 Allen        1600          1600
         30 Blake       2850          4450
         30 James        950         5400
         30 Martin      1250          5050
         30 Turner     1500          3700
         30 Ward       1250          4000

已选择16行。

加了partiton by分区后之后,rows 2 preceding(窗口)只在当前分区内生效,不会影响分区之外的行。


SQL> select ename,sal,hiredate,
  2         first_value(ename)over
  3         (order by hiredate asc rows 5 preceding) first_ename,
  4         first_value(hiredate) over
  5         (order by hiredate asc rows 5 preceding) first_hiredate
  6    from emp
  7  order by hiredate asc;

ENAME      SAL   HIREDATE   FIRST_ENAME  FIRST_HIRE
----------   ------ -------------  ----------------- --------------
SMITH        800  17-12月-80  SMITH             17-12月-80
ALLEN       1600  20-2月 -81  SMITH             17-12月-80
WARD       1250  22-2月 -81  SMITH             17-12月-80
JONES       2975  02-4月 -81  SMITH             17-12月-80
BLAKE       2850  01-5月 -81  SMITH             17-12月-80
CLARK      2450  09-6月 -81  SMITH              17-12月-80
TURNER    1500  08-9月 -81  ALLEN               20-2月 -81
MARTIN    1250  28-9月 -81  WARD               22-2月 -81
KING        5000  17-11月-81  JONES              02-4月 -81
JAMES        950  03-12月-81  BLAKE              01-5月 -81
FORD       3000  03-12月-81  CLARK              09-6月 -81
MILLER     1300  23-1月 -82  TURNER            08-9月 -81
SCOTT     3000  19-4月 -87  MARTIN             28-9月 -81
ADAMS     1100  23-5月 -87  KING                17-11月-81
aaa               3  12-8月 -04  JAMES               03-12月-81
aaa                   08-11月-04  FORD                03-12月-81
aaa               1  20-11月-04  MILLER              23-1月 -82
aaa               2  29-11月-04  SCOTT               19-4月 -87

已选择18行。

order by hiredate asc rows 5 preceding: order by之后,取当前行的前5行+当前行作为窗口(共6行)。


2、"range unbounded preceding"

range unbounded preceding会把当前行之前的所有行都包含进来,但当partition by时:

SQL> select deptno,ename,sal,
  2         sum(sal) over
  3         (partition by deptno order by deptno range unbounded preceding) sumsal
  4    from emp;

 DEPTNO ENAME     SAL  SUMSAL
---------- --------    ------ ----------
           0 aaa                           3
           0 aaa               1          3
           0 aaa               2          3

         10 Clark       2450     3750
         10 Miller       1300     3750

         20 Smith        800    10875
         20 Scott       3000    10875
         20 Ford        3000    10875
         20 Adams    1100    10875
         20 Jones      2975    10875——10875=800+3000+3000+1100+2975

         30 Allen       1600     9400
         30 James       95      9400
         30 Turner     1500    9400
         30 Blake       2850    9400
         30 Martin      1250    9400
         30 Ward       1250    9400

已选择16行。


SQL> select deptno,ename,sal,
  2         sum(sal) over
  3         (order by deptno range unbounded preceding) sumsal
  4   from  emp;

 DEPTNO  ENAME      SAL   SUMSAL
 ---------- --------      -----  ---------
            0 aaa                            3
            0 aaa               1           3
            0 aaa               2           3
          10 Clark       2450      3753
          10 Miller       1300      3753
          20 Smith        800     14628
          20 Scott       3000     14628
          20 Ford        3000     14628
          20 Adams    1100     14628
          20 Jones      2975     14628
          30 Allen       1600     24028
          30 James       950    24028
          30 Turner     1500    24028
          30 Blake      2850     24028
          30 Martin     1250     24028
          30 Ward      1250     24028

已选择16行。

这SQL句子和下面这SQL是等价的:

select deptno,ename,sal,
       sum(sal) over (order by deptno) sumsal
  from  emp;

因为order by的默认窗口总是从结果集的第一行开始到它分组的最后一行。
而partiton by的默认窗口总是从分区的第一行开始。


3、range窗口: "range 100 preceding"

这个子句只适用于number和date,而且只能order by一列。
如果over()里asc排列,意思是[number-100,number]这样一个闭区间是它的窗口。
如果over()里desc排列,意思是[number,number+100]这样一个闭区间是它的窗口。


下面看一个date的:

SQL> select ename,sal,hiredate,hiredate-100 windowtop,
  2         first_value(ename) over
  3         (order by hiredate asc range 100 preceding) first_ename,
  4         first_value(hiredate) over
  5         (order by hiredate asc range 100 preceding) first_hiredate
  6    from emp
  7  order by hiredate asc;

ENAME     SAL  HIREDATE    WINDOWTOP   FIRST_ENAME  FIRST_HIRE
-------      ----- ------------   ----------------   ----------------- ---------------
SMITH     800  17-12月-80       08-9月 -80   SMITH               17-12月-80
ALLEN    1600  20-2月 -81       12-11月-80   SMITH               17-12月-80
WARD    1250  22-2月 -81       14-11月-80   SMITH               17-12月-80
JONES    2975  02-4月 -81       23-12月-80   ALLEN                20-2月 -81
BLAKE    2850  01-5月 -81       21-1月 -81   ALLEN                20-2月 -81
CLARK    2450  09-6月 -81       01-3月 -81   JONES               02-4月 -81
TURNER  1500  08-9月 -81       31-5月 -81   CLARK               09-6月 -81
MARTIN  1250  28-9月 -81        20-6月 -81  TURNER             08-9月 -81
KING     5000  17-11月-81        09-8月 -81  TURNER              08-9月 -81
FORD     3000  03-12月-81        25-8月 -81  TURNER             08-9月 -81
JAMES     950  03-12月-81        25-8月 -81  TURNER             08-9月 -81
MILLER  1300   23-1月 -82       15-10月-81   KING                 17-11月-81
SCOTT   3000  19-4月 -87       09-1月 -87   SCOTT               19-4月 -87
ADAMS  1100  23-5月 -87        12-2月 -87  SCOTT                19-4月 -87
aaa             3  12-8月 -04        04-5月 -04  aaa                    12-8月 -04
aaa                 08-11月-04       31-7月 -04  aaa                     12-8月 -04
aaa             1  20-11月-04        12-8月 -04  aaa                    12-8月 -04
aaa             2  29-11月-04        21-8月 -04  aaa                    08-11月-04

已选择18行。
                                  
first_value返回[hiredate-100,hiredate]这个区间内的离hiredate-100最近的一个值。


下面这句可以看出WINDOW里包含的记录个数:

SQL> select ename,sal,hiredate,hiredate-100 windowtop,
  2         count(hiredate) over
  3         (order by hiredate asc range 100 preceding) count_window
  4    from emp;

ENAME      SAL     HIREDATE    WINDOWTOP   COUNT_WINDOW
--------     -------  ------------     ---------------    ------------------
SMITH         800  17-12月-80      08-9月 -80                         1
ALLEN        1600  20-2月 -81      12-11月-80                         2
WARD        1250  22-2月 -81      14-11月-80                        3
JONES        2975  02-4月 -81      23-12月-80                        3
BLAKE        2850  01-5月 -81      21-1月 -81                        4
CLARK       2450  09-6月 -81       01-3月 -81                        3
TURNER     1500  08-9月 -81       31-5月 -81                        2
MARTIN     1250  28-9月 -81       20-6月 -81                        2
KING         5000  17-11月-81      09-8月 -81                         3
JAMES         950  03-12月-81      25-8月 -81                         5
FORD        3000  03-12月-81       25-8月 -81                         5
MILLER     1300   23-1月 -82      15-10月-81                         4
SCOTT     3000   19-4月 -87       09-1月 -87                         1
ADAMS     1100   23-5月 -87      12-2月 -87                         2
aaa               3   12-8月 -04       04-5月 -04                         1
aaa                    08-11月-04       31-7月 -04                         2
aaa               1   20-11月-04       12-8月 -04                         3
aaa               2   29-11月-04       21-8月 -04                         3

已选择18行。


下面看一个desc的例子:

SQL> select ename,sal,hiredate,hiredate+100 windowtop,
  2         first_value(ename) over
  3         (order by hiredate desc range 100 preceding) first_ename,
  4         first_value(hiredate) over
  5         (order by hiredate desc range 100 preceding) first_hiredate
  6   from emp
  7  order by hiredate desc;

ENAME      SAL    HIREDATE     WINDOWTOP    FIRST_ENAME  FIRST_HIRE
--------     -----    -------------   ----------------   ---------------- ---------------
aaa              2    29-11月-04       09-3月 -05    aaa                29-11月-04
aaa              1    20-11月-04       28-2月 -05    aaa                29-11月-04
aaa                    08-11月-04       16-2月 -05    aaa                29-11月-04
aaa              3    12-8月 -04       20-11月-04    aaa                20-11月-04
ADAMS    1100   23-5月 -87        31-8月 -87   ADAMS           23-5月 -87
SCOTT     3000   19-4月 -87        28-7月 -87   ADAMS           23-5月 -87
MILLER    1300    23-1月 -82       03-5月 -82   MILLER            23-1月 -82
FORD       3000   03-12月-81       13-3月 -82   MILLER            23-1月 -82
JAMES       950   03-12月-81        13-3月 -82   MILLER            23-1月 -82
KING       5000   17-11月-81        25-2月 -82   MILLER            23-1月 -82
MARTIN    1250   28-9月 -81       06-1月 -82   FORD              03-12月-81
TURNER    1500   08-9月 -81       17-12月-81   FORD              03-12月-81
CLARK     2450   09-6月 -81       17-9月 -81   TURNER            08-9月 -81
BLAKE     2850    01-5月 -81       09-8月 -81   CLARK             09-6月 -81
JONES     2975    02-4月 -81      11-7月 -81   CLARK              09-6月 -81
WARD      1250    22-2月 -81      02-6月 -81   BLAKE              01-5月 -81
ALLEN     1600     20-2月 -81      31-5月 -81   BLAKE              01-5月 -81
SMITH      800     17-12月-80      27-3月 -81   WARD              22-2月 -81

已选择18行。

 

4、窗口总结

1、unbounded preceding:从当前分区的第一行开始,到当前行结束。
2、current row:从当前行开始,也结束于当前行。
3、[numeric expression] preceding:对于rows来说从当前行之前的第[numeric expression]行开始,到当前行结束。对range来说从小于数值

表达式的值开始,到当前行结束。
4、[numeric expression] following:与[numeric expression] preceding相反。


一个preceding和following混合的例子:

SQL> select ename,hiredate,
  2         first_value(ename) over
  3         (order by hiredate asc range between 100 preceding and 100 following) as first_ename,
  4         last_value(ename) over
  5         (order by hiredate asc range between 100 preceding and 100 following) as last_ename
  6    from emp
  7  order by hiredate asc;

ENAME                HIREDATE     FIRST_ENAME          LAST_ENAME
-------------------- ------------    --------------------     --------------------
SMITH                17-12月-80    SMITH                     WARD
ALLEN                20-2月 -81     SMITH                     BLAKE
WARD                 22-2月 -81    SMITH                     BLAKE
JONES                02-4月 -81     ALLEN                     CLARK
BLAKE                01-5月 -81     ALLEN                     CLARK
CLARK                09-6月 -81    JONES                     TURNER
TURNER              08-9月 -81    CLARK                     JAMES
MARTIN              28-9月 -81    TURNER                   JAMES
KING                 17-11月-81    TURNER                    MILLER
FORD                 03-12月-81   TURNER                     MILLER
JAMES               03-12月-81    TURNER                    MILLER
MILLER              23-1月 -82    KING                         MILLER
SCOTT              19-4月 -87    SCOTT                      ADAMS
ADAMS              23-5月 -87   SCOTT                       ADAMS
aaa                   12-8月 -04    aaa                           aaa
aaa                   08-11月-04    aaa                           aaa
aaa                   20-11月-04    aaa                           aaa
aaa                   29-11月-04    aaa                           aaa

已选择18行。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值