SQL Fundamentals: 子查詢 || 分析函數(PARTITION BY,ORDER BY, WINDOWING)


 SQL Fundamentals || Oracle SQL語言

子查詢(基礎)

1、認識子查詢

2、WHERE子句中使用子查詢

3、在HAVING子句中使用子查詢

4、在FROM子句中使用子查詢

5、在SELECT子句中使用子查詢

6、WITH子句

 

子查詢(進階)

7、分析函數

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值是出現在排序序列前還是尾;

NULLS FIRST

NULLS FIRST表示在進行排序,出現null值的數據行排列在最前面,

 

 

NULLS LAST

NULLS LAST則表示出現的null值數據行排列在最面。

使用NULLS LAST

SELECT deptno , ename, sal , comm ,

     RANK() OVER (ORDER BY comm DESC NULLS LAST) rk ,

      SUM(sal) OVER (ORDER BY comm DESC NULLS LAST) SUM

FROM emp ;

 

WINDOWING 子句(代名詞)

給出在定義變化的固定的數據窗口方法,分析函數將對此數據進行操作。

 

組合順序:

在分析函數之中存在有三種子句:PARTITION BYORDER BYWINDOWING,而這三種子句的組合順序有如下幾種:

組合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 ;

 

1PARTITION子句和ORDER BY子句的使用

使用PARTITION子句

按照部門范疇進行統計;每行數據之后都會有統計的結果出現.

同一部門的雇員的SUMsal)的值相同,並且值等於同一部門雇員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 ;

 

 

2WINDOWING子句

分窗子句主要是用於定義一個變化或固定的數據窗口方法,主要用於定義分析函數在操作行的集合,分窗子句有兩種實現方式:

值域窗(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語句

      • 保留滿足條件的數據,在使用DENSE_RANK()函數確定的集合后,通過FIRSTLAST取得集合中的數據.

分組函數 ()

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條記錄,記錄會按照10.80.60.40.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;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM