什么是分析函數(partition by):
分析函數是Oracle專門用於解決復雜報表統計需求的函數,它可以在數據中進行分組,然后計算基於組的某種統計值,並且每一組的每一行都可以返回一個統計值。
分析函數和聚合函數的不同之處是什么?
普通的聚合函數用group by分組,每個分組返回一個統計值,只有一行,而分析函數采用partition by分組,每組中包含多個值。
開窗函數 其實就是group by的另一種。它與group by的區別在於開窗函數可以在分組列中再排序,其實就是加了一列隱藏列,可以在group by中再分組的意思.
關於開窗函數(over()):
開窗函數指定了分析函數中的分組的大小。
分析函數帶有一個開窗函數over(),包含三個分析子句:分組(partition by), 排序(order by), 窗口(rows) ,這些就是窗口的規則。
他們的使用形式如下:over(partition by xxx order by yyy rows between zzz)。
注意:窗口子句不能單獨出現,必須有order by子句時才能出現。
兩個order by的執行時機:
分析函數(以及與其配合的開窗函數over())是在整個sql查詢結束后(sql語句中的order by的執行比較特殊)再進行的操作, 也就是說sql語句中的order by也會影響分析函數的執行結果:
a) 兩者一致:如果sql語句中的order by滿足與分析函數配合的開窗函數over()分析時要求的排序,即sql語句中的order by子句里的內容和開窗函數over()中的order by子句里的內容一樣,那么sql語句中的排序將先執行,分析函數在分析時就不必再排序;
b) 兩者不一致:如果sql語句中的order by不滿足與分析函數配合的開窗函數over()分析時要求的排序,即sql語句中的order by子句里的內容和開窗函數over()中的order by子句里的內容不一樣,那么sql語句中的排序將最后在分析函數分析結束后執行排序。
開窗函數的例子;
開窗函數指定了分析函數工作的數據窗口大小,這個數據窗口大小可能會隨着行的變化而變化,舉例如下:
1、over(order by salary) 按照salary排序進行累計,order by是個默認的開窗函數。
SELECT EMPLOYEE_ID, SALARY, MANAGER_ID, DEPARTMENT_ID, SUM(SALARY) OVER(ORDER BY SALARY) DD FROM INFA_TEST.EMPLOYEES EMP ORDER BY SALARY
功能:按salary升序排序,統計小於等於當前salary的salary總和。
返回結果:
ROWNUM | EMPLOYEE_ID | SALARY | MANAGER_ID | DEPARTMENT_ID | DD | 備注 |
1 | 132 | 2100 | 121 | 50 | 2100 | |
2 | 128 | 2200 | 120 | 50 | 6500 | 2200+2200+2100 |
3 | 136 | 2200 | 122 | 50 | 6500 | 2200+2200+2100 |
4 | 127 | 2400 | 120 | 50 | 11300 | 6500+2400+2400 |
5 | 135 | 2400 | 122 | 50 | 11300 | 6500+2400+2400 |
6 | 119 | 2500 | 114 | 30 | 26300 | 11300+2500*5 |
7 | 140 | 2500 | 123 | 50 | 26300 | 11300+2500*5 |
8 | 144 | 2500 | 124 | 50 | 26300 | 11300+2500*5 |
9 | 191 | 2500 | 122 | 50 | 26300 | 11300+2500*5 |
10 | 182 | 2500 | 120 | 50 | 26300 | 11300+2500*5 |
注意 SALARY為2200、2400和2500行的DD值,
2、over(partition by DEPARTMENT_ID)按照部門分區。
SELECT EMPLOYEE_ID, SALARY, MANAGER_ID, DEPARTMENT_ID, SUM(SALARY) OVER(PARTITION BY DEPARTMENT_ID) DD FROM INFA_TEST.EMPLOYEES EMP ORDER BY DEPARTMENT_ID
功能:按DEPARTMENT_ID分區,匯總各個部門的SALARY總和。
返回結果:
ROWNUM | EMPLOYEE_ID | SALARY | MANAGER_ID | DEPARTMENT_ID | DD | 備注 |
1 | 200 | 4400 | 101 | 10 | 4400 | |
2 | 201 | 13000 | 100 | 20 | 19000 | 13000+6000 |
3 | 202 | 6000 | 201 | 20 | 19000 | 13000+6000 |
4 | 114 | 11000 | 100 | 30 | 24900 | 11000+3100+2900+2500+2600+2800 |
5 | 115 | 3100 | 114 | 30 | 24900 | 11000+3100+2900+2500+2600+2800 |
6 | 116 | 2900 | 114 | 30 | 24900 | 11000+3100+2900+2500+2600+2800 |
7 | 119 | 2500 | 114 | 30 | 24900 | 11000+3100+2900+2500+2600+2800 |
8 | 118 | 2600 | 114 | 30 | 24900 | 11000+3100+2900+2500+2600+2800 |
9 | 117 | 2800 | 114 | 30 | 24900 | 11000+3100+2900+2500+2600+2800 |
注意 DEPARTMENT_ID為20,30的DD值
3、over(partition by DEPARTMENT_ID order by SALARY)按照部門分區。
SELECT EMPLOYEE_ID, SALARY, MANAGER_ID, DEPARTMENT_ID, SUM(SALARY) OVER(PARTITION BY DEPARTMENT_ID ORDER BY SALARY) DD FROM INFA_TEST.EMPLOYEES EMP ORDER BY DEPARTMENT_ID
功能:按DEPARTMENT_ID分區,按SALARY升序排序,統計各個部門內部小於當前SALARY的和。
返回結果:
ROWNUM | EMPLOYEE_ID | SALARY | MANAGER_ID | DEPARTMENT_ID | DD | 備注 |
1 | 200 | 4400 | 101 | 10 | 4400 | DEPARTMENT_ID=10的SALARY |
2 | 201 | 13000 | 100 | 20 | 6000 | DEPARTMENT_ID=20的SALARY排序並求和 |
3 | 202 | 6000 | 201 | 20 | 19000 | DEPARTMENT_ID=20的SALARY排序並求和:6000+13000 |
4 | 114 | 11000 | 100 | 30 | 2500 | DEPARTMENT_ID=30的SALARY排序並求和 |
5 | 115 | 3100 | 114 | 30 | 5100 | DEPARTMENT_ID=30的SALARY排序並求和:2500+2600 |
6 | 116 | 2900 | 114 | 30 | 7900 | DEPARTMENT_ID=30的SALARY排序並求和:5100+2800 |
7 | 119 | 2500 | 114 | 30 | 10800 | DEPARTMENT_ID=30的SALARY排序並求和:7900+2900 |
8 | 118 | 2600 | 114 | 30 | 13900 | DEPARTMENT_ID=30的SALARY排序並求和:10800+3100 |
9 | 117 | 2800 | 114 | 30 | 24900 | DEPARTMENT_ID=30的SALARY排序並求和:13900+11000 |
注意 DEPARTMENT_ID為20、30的DD值和2中的區別
4、over(order by salary range between 50 preceding and 150 following)
SELECT EMPNO, SAL, MGR, DEPTNO, SUM(SAL) OVER(PARTITION BY DEPTNO ORDER BY SAL RANGE BETWEEN 0 PRECEDING AND 100 FOLLOWING) DD FROM EMP;
功能:按DEPTNO分區,按SAL升序排序,匯總當前SAL到比當前SAL大100之間的SAL總和。
返回結果:
ROWNUM | EMPNO | SAL | MGR | DEPTNO | DD | 備注 |
1 | 7934 | 1300 | 7782 | 10 | 1300 | |
2 | 7782 | 2450 | 7839 | 10 | 2450 | |
3 | 7839 | 5000 | 10 | 5000 | ||
4 | 7369 | 800 | 7902 | 20 | 800 | |
5 | 7566 | 2975 | 7839 | 20 | 5975 | 3000在2975和(2975+100)之間,故求2975與3000的和 |
6 | 7902 | 3000 | 7566 | 20 | 3000 | |
7 | 7900 | 950 | 7698 | 30 | 950 | |
8 | 7521 | 1250 | 7698 | 30 | 2500 | 1250在1250和(1250+100)之間,故求1250和1250的和 |
9 | 7654 | 1250 | 7698 | 30 | 2500 | |
10 | 7844 | 1500 | 7698 | 30 | 3100 | 1600在1500和(1500+100)之間,故求1500和1600的和 |
11 | 7499 | 1600 | 7698 | 30 | 1600 | |
12 | 7698 | 2850 | 7839 | 30 | 2850 |
解釋:返回前置行和當前行SAL相等,后續行比他大100的記錄,在SAL列上求和。
上下邊界沒有限制:OVER (PARTITION BY DEPTNO ORDER BY SAL RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
SELECT EMPNO, SAL, MGR, DEPTNO, SUM(SAL) OVER(PARTITION BY DEPTNO ORDER BY SAL RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) DD FROM EMP;
ROWNUM | EMPNO | SAL | MGR | DEPTNO | DD | 備注 |
1 | 7934 | 1300 | 7782 | 10 | 8750 | 1300+2450+5000 |
2 | 7782 | 2450 | 7839 | 10 | 8750 | 1300+2450+5000 |
3 | 7839 | 5000 | 10 | 8750 | 1300+2450+5000 | |
4 | 7369 | 800 | 7902 | 20 | 6775 | 800+2975+3000 |
5 | 7566 | 2975 | 7839 | 20 | 6775 | 800+2975+3000 |
6 | 7902 | 3000 | 7566 | 20 | 6775 | 800+2975+3000 |
7 | 7900 | 950 | 7698 | 30 | 9400 | 950+1250+1250+1500+1600+2850 |
8 | 7521 | 1250 | 7698 | 30 | 9400 | 950+1250+1250+1500+1600+2850 |
9 | 7654 | 1250 | 7698 | 30 | 9400 | 950+1250+1250+1500+1600+2850 |
10 | 7844 | 1500 | 7698 | 30 | 9400 | 950+1250+1250+1500+1600+2850 |
11 | 7499 | 1600 | 7698 | 30 | 9400 | 950+1250+1250+1500+1600+2850 |
12 | 7698 | 2850 | 7839 | 30 | 9400 | 950+1250+1250+1500+1600+2850 |
解釋:返回以DEPTNO分組的SAL列上求和
5、over(order by salary rows between 1 preceding and 2 following)-- 每行對應的數據窗口是之前行幅度值不超過1,之后行幅度值不超過2
1 SELECT EMPNO, 2 SAL, 3 MGR, 4 DEPTNO, 5 SUM(SAL) OVER(PARTITION BY DEPTNO ORDER BY SAL ROWS BETWEEN 1 PRECEDING AND 2 FOLLOWING) DD 6 FROM EMP;
返回結果
ROWNUM | EMPNO | SAL | MGR | DEPTNO | DD | 備注 |
1 | 7934 | 1300 | 7782 | 10 | 8750 | 本行和后兩行SAL的和:1300+2450+5000 |
2 | 7782 | 2450 | 7839 | 10 | 8750 | 本行和前一行和后一行SAL的和:2450+1300+5000 |
3 | 7839 | 5000 | 10 | 7450 | 本行和前一行SAL的和:5000+2450 | |
4 | 7369 | 800 | 7902 | 20 | 6775 | 本行和后兩行SAL的和:800+2975+3000 |
5 | 7566 | 2975 | 7839 | 20 | 6775 | 本行和前一行和后一行SAL的和:2975+800+3000 |
6 | 7902 | 3000 | 7566 | 20 | 5975 | 本行和前一行SAL的和:3000+2975 |
7 | 7900 | 950 | 7698 | 30 | 3450 | 本行和后兩行SAL的和:950+1250+1250 |
8 | 7521 | 1250 | 7698 | 30 | 4950 | 本行和前一行和后兩行SAL的和:1250+950+1250+1500 |
9 | 7654 | 1250 | 7698 | 30 | 5600 | 本行和前一行和后兩行SAL的和:1250+1250+1500+1600 |
10 | 7844 | 1500 | 7698 | 30 | 7200 | 本行和前一行和后兩行SAL的和:1500+1250+1600+2850 |
11 | 7499 | 1600 | 7698 | 30 | 5950 | 本行和前一行和后一行SAL的和:1600+1500+2850 |
12 | 7698 | 2850 | 7839 | 30 | 4450 | 本行和前一行SAL的和:2850+1600 |
解釋:如果分組后本行前一行或者后一行沒有數據了,就不進行求和了.