SQL Fundamentals || Oracle SQL語言
1、認識子查詢
2、WHERE子句中使用子查詢
3、在HAVING子句中使用子查詢
4、在FROM子句中使用子查詢
5、在SELECT子句中使用子查詢
6、WITH子句
子查詢(進階)
8、行列轉換
9、設置數據層次
七、分析函數
- 分析函數語法;
- 分窗操作的;
- 使用分析函數可以進行更為復雜的查詢報表顯示。
- 在分析函數中可以使用若干統計函數.
傳統SQL的問題
雖然利用SQL之中提供的各種查詢命令可以完成大部分的查詢要求,但是還有許多功能是無法實現的,例如:
- 計算運行總量:逐一累加當前行與其之前行的每行記錄數據;
- 查找當前行數據占總數據的百分比;
- 分區顯示:按照不同的部門或職位進行排列、統計;
- 計算流動數據行的平均值等。
分析函數的基本語法
基本語法:
函數名稱([參數 , ....]) OVER (
PARTITION BY 子句 字段 , …
[ORDER BY 子句 字段 , … [ASC | DESC] [NULLS FIRST | NULLS LAST]
[WINDOWING 子句]) ;
語法組成:
函數名稱 |
類似於統計函數(COUNT()、SUM()等),但是在此時有了更多的函數支持; |
||||
OVER子句 |
為分析函數指明一個查詢結果集,此語句在SELECT子句之中使用; |
||||
PARTITION BY子句 |
將一個簡單的結果集分為N組(或稱為分區),而后按照不同的組對數據進行統計; |
||||
ORDER BY 子句 |
明確指明數據在每個組內的排列順序,分析函數的結果與排列順序有關; NULLS FIRST | NULLS LAST:表示返回數據行中包含NULL值是出現在排序序列前還是尾;
|
||||
WINDOWING 子句(代名詞) |
給出在定義變化的固定的數據窗口方法,分析函數將對此數據進行操作。 |
組合順序:
在分析函數之中存在有三種子句:PARTITION BY、ORDER BY、WINDOWING,而這三種子句的組合順序有如下幾種:
組合1 |
函數名稱([參數 ,…]) OVER(PARTITION BY 子句 , ORDER BY 子句 , WINDOWING子句); |
組合2 |
函數名稱([參數 ,…]) OVER(PARTITION BY 子句 , ORDER BY 子句); |
組合3 |
函數名稱([參數 ,…]) OVER(PARTITION BY 子句); |
組合4 |
函數名稱([參數 ,…]) OVER(ORDER BY 子句 , WINDOWING子句); |
組合5 |
函數名稱([參數 ,…]) OVER(ORDER BY 子句); |
組合6 |
函數名稱([參數 ,…]) OVER(); |
基本查詢語句中是不能出現字段和統計函數同時出現的.(如下語法是錯誤的)
SELECT deptno , ename, sal ,
SUM(sal)
FROM emp ;
1、PARTITION子句和ORDER BY子句的使用
使用PARTITION子句 按照部門范疇進行統計;每行數據之后都會有統計的結果出現. 同一部門的雇員的SUM(sal)的值相同,並且值等於同一部門雇員sal的相加. |
SELECT deptno , ename, sal , SUM(sal) OVER (PARTITION BY deptno) sum FROM emp ;
|
不使用PARTITION進行分區,直接利用OVER子句操作——如果沒有分區就會把所有的數據當成一個區,然后進行統計. |
SELECT deptno , ename, sal , SUM(sal) OVER () sum FROM emp ;
|
通過PARTITION設置多個分區字段——分析部門編號和職位進行分區 這里的范疇:先按照部門分區,再按照職位分區,返回的結果是:每個部門中職位的總工資 |
SELECT deptno , ename, sal , job , SUM(sal) OVER (PARTITION BY deptno , job) sum FROM emp ;
|
觀察ORDER BY子句 按照部門編號分區,按照工資降序排列(兩個數據相同並列為1,后面一個數據為3) |
SELECT deptno , ename, sal , RANK() OVER (PARTITION BY deptno ORDER BY sal DESC) rk FROM emp ;
|
設置多個排序字段(sal和hiredate) |
SELECT deptno , ename, sal , hiredate , RANK() OVER (PARTITION BY deptno ORDER BY sal , hiredate DESC) rk FROM emp ;
|
直接利用ORDER BY排序所有數據——如果不寫分區操作,就表示所有的數據進行排序 先將所有數據變為一組,而后按照姓名進行排序; 排序后,第一個數據的sum(sal)值為其sal本身,第二個數據的sum(sal)值為第一個數據和第二個數據的總和,以此類推. |
SELECT deptno , ename, sal , hiredate , SUM(sal) OVER (ORDER BY ename DESC) SUM FROM emp ;
|
2、WINDOWING子句
分窗子句主要是用於定義一個變化或固定的數據窗口方法,主要用於定義分析函數在操作行的集合,分窗子句有兩種實現方式:
值域窗(RANGE WINDOW),邏輯偏移 |
當前分區之中當前行的前N行到當前行的記錄集; |
行窗(ROWS WINDOW),物理偏移 |
以排序的結果順序計算偏移當前行的起始行記錄集。 |
而如果要想指定RANGE(值域窗)或ROWS(行窗)的偏移量,則可以采用如下的幾種排序列:
1 |
RANGE | ROWS 數字 PRECEDING; |
2 |
RANGE | ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW; |
3 |
RANGE | ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING; |
以上的幾種排列之中包含的概念如下:
PRECEDING |
主要是設置一個偏移量,這個偏移量可以是用戶設置的數字,或者是其他標記; |
BETWEEN … AND |
設置一個偏移量的操作范圍; |
UNBOUNDED PRECEDING |
不限制偏移量大小; |
CURRENT ROW |
表示當前行; |
FOLLOWING |
如果不寫此語句表示使用上N行與當前行指定數據比較,如果編寫此語句,表示當前行與下N行數據比較; |
例子:
RANGE子句:RANGE子句設置的是一個邏輯的偏移量
在sal上設置偏移量(PRECEDING) 按照向上N行的記錄偏移 |
SELECT deptno , ename, sal , SUM(sal) OVER (PARTITION BY deptno ORDER BY sal RANGE 300 PRECEDING) sum FROM emp ;
|
設置偏移量為300,采用下匹配方式處理 向下匹配方式,顯示結果向下N行的記錄偏移 |
SELECT deptno , ename, sal , SUM(sal) OVER (PARTITION BY deptno ORDER BY sal RANGE BETWEEN 0 PRECEDING AND 300 FOLLOWING) sum FROM emp ;
|
匹配當前行數據 |
SELECT deptno , ename, sal , SUM(sal) OVER (PARTITION BY deptno ORDER BY sal RANGE BETWEEN 0 PRECEDING AND CURRENT ROW) sum FROM emp ;
|
使用UNBOUNDED不設置邊界 現在的結果是在一個區域內進行逐行的操作. |
SELECT deptno , ename, sal , SUM(sal) OVER (PARTITION BY deptno ORDER BY sal RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) sum FROM emp ;
|
ROWS子句:ROWS子句設置的是一個物理的偏移量
設置2行物理偏移 按照部門編號分組,而后采用當前行和前2行數據進行計算. |
SELECT deptno , ename, sal , SUM(sal) OVER (PARTITION BY deptno ORDER BY sal ROWS 2 PRECEDING) sum FROM emp ;
|
設置查詢行范圍 此時和按照部門分區進行求和道理相同. |
SELECT deptno , ename, sal , SUM(sal) OVER (PARTITION BY deptno ORDER BY sal ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) sum FROM emp ;
|
分析函數:
1、數據統計函數
2、等級函數
3、報表函數
1、數據統計函數
函數名稱 |
描述 |
SUM([DISTINCT | ALL] 表達式) |
計算分區(分組)中的數據累加和 |
MIN([DISTINCT | ALL] 表達式) |
查找分區(分組)中的最小值 |
MAX([DISTINCT | ALL] 表達式) |
查找分區(分組)中的最大值 |
AVG([DISTINCT | ALL] 表達式) |
計算分區(分組)中的數據平均值 |
COUNT(* | [DISTINCT | ALL] 表達式) |
計算分區(分組)中的數據量 |
查詢雇員編號是7369的雇員姓名、職位、基本工資、部門編號、部門的人數、平均工資、最高工資、最低工資、總工資 |
SELECT * FROM ( SELECT empno,ename,job,sal,deptno , COUNT(empno) OVER (PARTITION BY deptno) count , ROUND(AVG(sal) OVER (PARTITION BY deptno)) avg , SUM(sal) OVER (PARTITION BY deptno) sum , MAX(sal) OVER (PARTITION BY deptno) max , MIN(sal) OVER (PARTITION BY deptno) min FROM emp ) temp WHERE temp.empno=7369 ; 法二: WITH t AS( SELECT empno,ename,job,sal,deptno , COUNT(empno) OVER (PARTITION BY deptno) count , ROUND(AVG(sal) OVER (PARTITION BY deptno)) avg , SUM(sal) OVER (PARTITION BY deptno) sum , MAX(sal) OVER (PARTITION BY deptno) max , MIN(sal) OVER (PARTITION BY deptno) min FROM emp ) SELECT * FROM t WHERE t.empno=7369 ; |
查詢每個雇員的編號、姓名、基本工資、所在部門的名稱、部門位置以及此部門的平均工資、最高和最低工資 |
確定所需要的數據表:dept表:部門信息,名稱,位置 emp表:雇員姓名,統計信息 確定已知的關聯字段: 雇員和部門:emp.deptno=dept.deptno 步驟一:進行多表關聯 步驟二:加入統計信息(部門的平均工資、最高和最低工資:使用分析函數,進行分窗) |
SELECT e.empno , e.ename , e.sal , d.dname , d.loc , ROUND(AVG(sal) OVER (PARTITION BY e.deptno ORDER BY sal RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) avg_salary , MAX(sal) OVER (PARTITION BY e.deptno ORDER BY sal RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) max_salary , MIN(sal) OVER (PARTITION BY e.deptno ORDER BY sal RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) min_salary FROM emp e,dept d WHERE e.deptno=d.deptno ; |
2、等級函數
為數據進行排序編號
函數名稱 |
描述 |
RANK() |
根據ORDER BY子句的排序字段,從分區(分組)查詢每一行數據,按照排序生成序號,會出現相同序號,跳號 |
DENSE_RANK() |
根據ORDER BY子句的排序字段,從分區(分組)查詢每一行數據,按照排序生成序號,不跳號 |
FIRST |
取出DENSE_RANK返回集合中第一行數據 |
LAST |
取出DENSE_RANK返回集合中最后一行數據 |
FIRST_VALUE(列) |
返回分區(分組)中的第一個值 |
LAST_VALUE(列) |
返回分區(分組)中的最后一個值 |
LAG(列名稱 [, 行數字] [, 默認值]) |
訪問分區(分組)中指定前N行的記錄,如果沒有則返回默認值 |
LEAD(列名稱 [, 行數字] [, 默認值]) |
訪問分區(分組)中指定后N行的記錄,如果沒有則返回默認值 |
ROW_NUMBER() |
返回每組中的行號 |
RANK()和DENSE_RANK()函數 |
SELECT deptno,ename,sal, RANK() OVER (PARTITION BY deptno ORDER BY sal) rank_result , DENSE_RANK() OVER (PARTITION BY deptno ORDER BY sal) dense_rank_result FROM emp ; |
ROW_NUMBER()函數 針對所有數據,ROW_NUMBER()自動生成了行號,但是在每個分區里面,也按照部門生成行號 |
SELECT deptno,ename,sal, ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal) row_result_deptno , ROW_NUMBER() OVER (ORDER BY sal) row_result_all FROM emp ; |
KEEP語句
分組函數 () KEEP (DENSE_RANK FIRST | LAST ORDER BY 表達式 [ASC | DESC] [NULLS [FIRST | LAST]] , ...) [OVER () 分區查詢] ; |
查詢每個部門的最高及最低工資 |
SELECT deptno, MAX(sal) KEEP (DENSE_RANK FIRST ORDER BY sal DESC) max_salary , MIN(sal) KEEP (DENSE_RANK LAST ORDER BY sal DESC) min_salary FROM emp GROUP BY deptno ; |
FIRST_VALUE()與LAST_VALUE()函數 |
SELECT deptno , empno , ename , sal , FIRST_VALUE(sal) OVER (PARTITION BY deptno ORDER BY sal RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) first_result , LAST_VALUE(sal) OVER (PARTITION BY deptno ORDER BY sal RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) last_result FROM emp WHERE deptno=10 ; |
LAG()與LEAD()函數 相鄰記錄的比較 |
SELECT deptno , empno , ename , sal , LAG(sal,2,0) OVER (PARTITION BY deptno ORDER BY sal ) lag_result , LEAD(sal,2,0) OVER (PARTITION BY deptno ORDER BY sal ) lead_result FROM emp WHERE deptno=20 ;
|
3、報表函數
函數名稱 |
描述 |
CUME_DIST() |
計算一行在分區(分組)中的相對位置,如果分區有5條記錄,記錄會按照1、0.8、0.6、0.4、0.2的方式進行划分 |
NTILE(數字) |
將一個分區(分組)分為“表達式”的散列表示 針對數據分區中的有序結果集進行划分 |
RATIO_TO_REPORT(表達式) |
該函數計算expression/(sum(expression))的值,它給出相對於總數的百分比 |
驗證CUME_DIST()函數 |
SELECT deptno,ename,sal , CUME_DIST() OVER (PARTITION BY deptno ORDER BY sal) cume FROM emp WHERE deptno IN (10,20) ;
|
使用NTILE()函數 |
SELECT deptno , sal , SUM(sal) OVER (PARTITION BY deptno ORDER BY sal) sum_result , NTILE(3) OVER (PARTITION BY deptno ORDER BY sal) ntile_result_a , NTILE(6) OVER (PARTITION BY deptno ORDER BY sal) ntile_result_b FROM emp ;
|
RATIO_TO_REPORT |
計算各部門工資所占的總工資比率 SELECT deptno ,SUM(sal) , ROUND(RATIO_TO_REPORT(SUM(sal)) OVER () ,5) rate , ROUND(RATIO_TO_REPORT(SUM(sal)) OVER () ,5) * 100 || '%' precent FROM emp GROUP BY deptno; |