引言:從 “提取數據” 到 “洞察價值”,SQL 進階之路
????????在掌握了基礎查詢與多表關聯后,你是否曾遇到這樣的挑戰:如何按部門統計平均薪資?怎樣找出每個崗位薪資最高的員工?或者如何計算銷售額的月度環比增長率?這些問題的核心,在于從 “簡單提取數據” 升級為 “深度分析數據”
????????本文作為 SQL 查詢系列的下篇,將聚焦分組查詢、子查詢、窗口函數三大核心技術,帶你突破數據處理的瓶頸。你將學習如何用GROUP BY
實現 “按類別匯總”,用子查詢解決 “嵌套邏輯” 問題,更能掌握窗口函數的 “黑科技”,輕松實現排名、累計值、移動平均等復雜分析。
目錄
引言:從 “提取數據” 到 “洞察價值”,SQL 進階之路
六、分組查詢和聚合函數
一、統計函數(聚合函數)
特點:
二、分組查詢(GROUP BY)
1. 基本語法
2. 關鍵要點
3. 示例解析
三、單行函數
四、統計函數與分組查詢與單行函數的關系
三者同時使用
七、WHERE 子查詢與 FROM 子查詢
(一)、WHERE 子查詢
1. 語法特點
2. 示例解析
單行子查詢(比較運算):
多行子查詢(IN?或?ANY):
聚合函數子查詢:
3. 關鍵字擴展(ANY/ALL)
= ANY:
< ANY:
> ANY:
> ALL:
< ALL:
(二)、FROM 子查詢
1. 語法特點
2. 示例解析
簡單子查詢作為臨時表:
預先過濾數據:
3. 優勢
(三)、WHERE 子查詢 vs FROM 子查詢
四、總結
八、SELECT查詢
(一)、SELECT 查詢的基礎用法
字段選擇規則
字段別名設置
函數與表達式支持
SELECT子查詢
一、語法特點
二、示例解析
三、使用場景
四、注意事項
九、分頁查詢
(一)、分頁查詢的必要性
(二)、分頁查詢語法(以 MySQL 為例)
語法規則
示例
1. 查詢首頁數據(前 10 條):
2. 查詢第二頁數據(第 11-20 條):
(三)、分頁查詢與其他語法的結合
與排序結合:
與篩選條件結合:
與連接查詢結合:
(四)、分頁查詢的注意事項
十、函數整理
窗口函數
為什么窗口函數對數據分析崗位至關重要?
功能:
1. 基礎語法框架
2. 常用窗口函數類型與示例
1)排名函數
2)聚合函數 + 窗口函數
3)取值函數
3. 窗口幀控制(ROWS vs RANGE)
4. 核心特點總結
六、分組查詢和聚合函數
一、統計函數(聚合函數)
統計函數用于對數據表中的數據進行匯總計算,返回單一結果。常見統計函數包括:
COUNT(字段):統計非NULL值的數量(如統計人數、記錄數)。
- 示例:
SELECT COUNT(EMPNO) 人數 FROM emp;(統計員工總數)
AVG(字段):計算數值型字段的平均值(如平均工資)。
- 示例:
SELECT AVG(SAL) 平均工資 FROM emp;(計算所有員工平均工資)。
其他常用函數:SUM(字段)(求和)、MAX(字段)(最大值)、MIN(字段)(最小值)等。
特點:
- 可直接作用于單表,無需分組時,返回整個表的匯總結果。
- 常與分組查詢結合,對每個分組單獨計算統計結果。
二、分組查詢(GROUP BY)
分組查詢用于將表中的數據按指定字段分組,對每個分組單獨應用統計函數,實現 “按類別匯總” 的需求。
1. 基本語法
SELECT 分組字段1, 分組字段2, 統計函數(字段)
FROM 表名
[WHERE 條件] -- 分組前篩選原始數據(不涉及統計結果)
GROUP BY 分組字段1, 分組字段2 -- 按字段分組,字段需出現在SELECT中
[HAVING 統計條件] -- 分組后篩選統計結果(需使用統計函數)
[ORDER BY 排序字段]; -- 對最終結果排序
2. 關鍵要點
WHERE?vs?HAVING:
-
WHERE:在分組之前篩選數據,不能使用統計函數(如WHERE AVG(SAL) > 2000?錯誤)。
-
HAVING:在分組之后篩選統計結果,可使用統計函數(如HAVING AVG(SAL) > 2000?正確)。
分組字段:GROUP BY?后的字段必須在?SELECT?中出現(除非使用統計函數覆蓋),確保每個分組的唯一性。
3. 示例解析
按崗位分組統計人數:
SELECT JOB, COUNT(EMPNO) 人數 FROM emp GROUP BY JOB;
# 4.查詢每個崗位的詳細信息,包含平均薪資
-- 查詢每個崗位的詳細信息,包含平均薪資
SELECT emp.job 崗位,COUNT(emp.empno) 員工人數,AVG(emp.sal) 平均薪資,MIN(emp.sal) 最低薪資,MAX(emp.sal) 最高薪資,SUM(emp.sal) 薪資總和
FROM emp
GROUP BY emp.job
ORDER BY 平均薪資 DESC;
# 5.查詢每個部門的詳細信息,包含平均薪資
SELECT d.deptno 部門編號, -- 部門編號(來自 dept 表)d.dname 部門名稱, -- 部門名稱(來自 dept 表)COUNT(e.empno) 部門人數,AVG(e.sal) 平均薪資
FROM emp e
LEFT JOIN dept d
ON e.deptno = d.deptno -- 連接員工表和部門表
GROUP BY d.deptno; -- 按部門分組(確保部門編號和名稱唯一)
結合右連接查詢,按部門分組并篩選平均薪資高于 2000 的部門:
# 6.#查詢平均薪資高于2000的部門信息
SELECT d.deptno 部門編號, -- 部門編號(來自 dept 表)d.dname 部門名稱, -- 部門名稱(來自 dept 表)COUNT(e.empno) 部門人數,AVG(e.sal) 平均薪資
FROM emp e
RIGHT JOIN dept d
USING(DEPTNO) -- 連接員工表和部門表
GROUP BY d.deptno -- 按部門分組(確保部門編號和名稱唯一)
HAVINGavg(e.SAL) > 2000
ORDER BY 平均薪資 DESC;
三、單行函數
單行函數是對表中的每一行數據單獨處理,返回與原表行數相同的結果。常見類型包括:
-
字符函數:UPPER(字段)(轉大寫)、LOWER(字段)(轉小寫)、LENGTH(字段)(長度)等。
-
示例:SELECT UPPER(ENAME) FROM emp;(將員工姓名轉為大寫)。
-
-
數值函數:ROUND(字段, 小數位)(四舍五入)、TRUNC(字段, 小數位)(截斷)等。
-
示例:SELECT ROUND(SAL, 2) FROM emp;(工資保留兩位小數)。
-
-
日期函數:SYSDATE()(當前系統時間)、TO_DATE(字符串, 格式)(字符串轉日期)等。
-
示例:SELECT TO_DATE('2025-01-01', 'YYYY-MM-DD') FROM dual;(將字符串轉為日期)。
-
-
轉換函數:TO_CHAR(字段, 格式)(日期 / 數值轉字符串)、TO_NUMBER(字符串)(字符串轉數值)等。
-
示例:SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD') FROM dual;(當前日期轉為字符串)。
-
特點:
-
處理粒度為 “單行”,不改變表的行數,僅對每行數據進行轉換或計算。
-
可與統計函數、分組查詢混合使用,實現更復雜的業務邏輯。
SELECT deptno 部門編號,UPPER(ename) 部門名稱大寫, -- 單行函數:部門名稱轉大寫COUNT(empno) 部門人數, -- 統計函數:按部門統計人數AVG(sal) 平均薪資 -- 統計函數:按部門計算平均工資
FROM emp
GROUP BY deptno, ename; -- 分組查詢:按部門編號和名稱分組具體來說,當你使用 GROUP BY 進行分組查詢時,SELECT 后面只能出現兩種類型的列:
出現在 GROUP BY 子句中的列
使用聚合函數(如 SUM(), COUNT(), AVG(), MAX(), MIN() 等)處理過的列
四、統計函數與分組查詢與單行函數的關系
統計函數 vs 單行函數:
-
統計函數:對一組數據(可能是全表或分組)匯總計算,返回單一結果。
-
單行函數:對每行數據單獨處理,返回與原表行數相同的結果。
分組查詢的橋梁作用:
-
分組查詢通過?GROUP BY?將數據劃分為多個子集,每個子集可應用統計函數生成匯總結果。
-
單行函數可在分組前對原始數據進行轉換(如日期格式化、字符串處理),或在分組后對統計結果進行二次處理。
例如:
-
不分組:AVG(SAL)?計算所有員工的平均工資。
# 所有人數
SELECT COUNT(EMPNO) 人數
FROM emp;
# 所有員工平均工資
SELECT AVG(SAL) 平均工資
FROM emp;
-
按部門分組:GROUP BY deptno?+?AVG(SAL)?計算每個部門的平均工資。
# 統計各崗位平均工資
SELECT JOB 崗位,AVG(SAL) 平均工資
FROM emp
GROUP BY JOB;
三者同時使用
SELECT deptno 部門編號,UPPER(dname) 部門名稱大寫, -- 單行函數:部門名稱轉大寫COUNT(empno) 部門人數, -- 統計函數:按部門統計人數AVG(sal) 平均薪資 -- 統計函數:按部門計算平均工資
FROM emp
GROUP BY deptno, dname; -- 分組查詢:按部門編號和名稱分組
SELECT deptno 部門編號,UPPER(ename) 部門名稱大寫, -- 單行函數:部門名稱轉大寫COUNT(empno) 部門人數, -- 統計函數:按部門統計人數AVG(sal) 平均薪資 -- 統計函數:按部門計算平均工資
FROM emp
GROUP BY deptno, ename; -- 分組查詢:按部門編號和名稱分組具體來說,當你使用 GROUP BY 進行分組查詢時,SELECT 后面只能出現兩種類型的列:
出現在 GROUP BY 子句中的列
使用聚合函數(如 SUM(), COUNT(), AVG(), MAX(), MIN() 等)處理過的列
七、WHERE 子查詢與 FROM 子查詢
(一)、WHERE 子查詢
定義:子查詢出現在?WHERE?或?HAVING?子句中,作為條件表達式的一部分,用于篩選主查詢的數據。
1. 語法特點
子查詢結果需能作為條件值或條件列表,常見形式:
-
單行子查詢:返回單一值,用于?=、>、<?等比較運算。
-
多行子查詢:返回多個值,用于?IN、ANY、ALL?等邏輯運算。
執行順序:先執行子查詢,再將結果作為條件篩選主查詢數據。
2. 示例解析
單行子查詢(比較運算):
-- 查詢比SMITH工資高的員工信息
SELECT *
FROM emp
WHERE SAL > (SELECT SAL FROM emp WHERE ENAME = 'SMITH')
ORDER BY SAL DESC;
子查詢?(SELECT SAL FROM emp WHERE ENAME = 'SMITH')?返回 SMITH 的工資(單行值)。
主查詢篩選工資大于該值的員工。
多行子查詢(IN?或?ANY):
-- 查詢與銷售崗位薪資相同的員工信息
SELECT *
FROM emp
WHERE SAL IN (SELECT SAL FROM emp WHERE JOB = 'SALESMAN');
子查詢返回所有銷售崗位的薪資(多行值)。
主查詢篩選薪資在該列表中的員工。
聚合函數子查詢:
-- 查詢比平均工資高的員工信息
SELECT *
FROM emp
WHERE SAL > (SELECT AVG(SAL) FROM emp);
3. 關鍵字擴展(ANY/ALL)
= ANY:
等價于?IN,匹配列表中任意一個值。
SELECT *
FROM emp
WHERE SAL = ANY (SELECT SAL FROM emp WHERE JOB = 'SALESMAN');
< ANY:
小于列表中的最大值。
SELECT *
FROM emp
WHERE SAL < ANY (SELECT SAL FROM emp WHERE JOB = 'SALESMAN');
> ANY:
比最小值大的數據
> ALL:
大于列表中的最大值。
< ALL:
小于列表中的最小值。
(二)、FROM 子查詢
定義:子查詢出現在?FROM?子句中,作為主查詢的 “臨時表”,需為子查詢指定別名。
1. 語法特點
-
子查詢結果作為數據源,主查詢對其進行二次篩選或關聯。
-
子查詢可預先過濾數據,減少主查詢的處理量。
-
執行順序:先執行子查詢生成臨時表,再執行主查詢。
2. 示例解析
簡單子查詢作為臨時表:
-- 與WHERE子查詢示例1結果相同,但語法結構不同
SELECT *
FROM (SELECT *FROM empWHERE SAL > (SELECT SAL FROM emp WHERE ENAME = 'SMITH')
) AS high_sal_emp -- 必須指定別名
ORDER BY SAL DESC;
子查詢生成 “工資高于 SMITH 的員工” 臨時表。
主查詢對臨時表按工資降序排序。
預先過濾數據:
SELECT *
FROM (SELECT empno, ename, sal, deptnoFROM empWHERE job = 'SALESMAN'
) AS salesmen
WHERE sal >= 1500;
子查詢預先篩選出銷售崗位的員工。
主查詢在臨時表基礎上,進一步篩選薪資≥1500 的員工。
3. 優勢
邏輯分層:將復雜查詢拆分為 “數據準備層”(子查詢)和 “結果處理層”(主查詢),便于維護。
性能優化:子查詢可提前過濾冗余數據,減少主查詢的計算量。
(三)、WHERE 子查詢 vs FROM 子查詢
維度 | WHERE 子查詢 | FROM 子查詢 |
位置 | 出現在WHERE/HAVING子句中 | 出現在FROM子句中 |
作用 | 作為條件篩選主查詢數據 | 作為數據源(臨時表)供主查詢使用 |
執行順序 | 先執行子查詢,再執行主查詢 | 先執行子查詢生成臨時表,再執行主查詢 |
子查詢結果 | 需為單一值或值列表(匹配條件) | 需為完整數據集(可含多字段、多行) |
別名要求 | 無需別名 | 必須為子查詢指定別名(臨時表名) |
典型場景 | 基于子查詢結果的條件篩選(如 “比 SMITH 工資高”) | 復雜數據預處理(如 “先篩選銷售崗位,再處理薪資”) |
四、總結
WHERE 子查詢:適用于將子查詢結果作為條件,直接篩選主查詢數據,語法簡潔,適合簡單條件判斷。
FROM 子查詢:適用于復雜數據預處理,通過臨時表分層處理邏輯,便于維護和性能優化。
兩者可結合使用,實現更復雜的業務需求(如子查詢嵌套、多表關聯等)。
八、SELECT查詢
定義:SELECT?是 SQL 中用于從表中提取數據的基礎關鍵字,所有查詢操作均以?SELECT?開頭,決定返回哪些字段及如何展示。
(一)、SELECT 查詢的基礎用法
-
字段選擇規則
-
可選擇表中所有字段:用?*?表示(如?SELECT * FROM emp;),適合快速查看全表數據,但效率較低(不推薦大數據量場景)。
-
可選擇指定字段:用逗號分隔字段名(如?SELECT EMPNO, ENAME, SAL FROM emp;),僅返回所需數據,減少資源消耗。
-
支持字段去重:在字段前加?DISTINCT(如?SELECT DISTINCT JOB FROM emp;),僅保留該字段的唯一值(DISTINCT?僅對緊跟的第一個字段生效)。
-
字段別名設置
-
為字段指定可讀性更強的別名(尤其適合中文展示),語法:字段名 別名?或?字段名 AS 別名(AS?可省略)。
-
示例:SELECT ENAME 姓名, JOB 職位, SAL 薪資 FROM emp;
-
函數與表達式支持
可在?SELECT?后直接使用單行函數處理字段(如字符轉換、數值計算等):
SELECT UPPER(ENAME) 姓名大寫, ROUND(SAL, 2) 薪資保留兩位小數 FROM emp;
可在?SELECT?后使用統計函數(聚合函數)進行匯總計算(常與?GROUP BY?結合):
SELECT JOB, COUNT(EMPNO) 人數, AVG(SAL) 平均薪資 FROM emp GROUP BY JOB;
可嵌套子查詢作為字段值,返回與主查詢行數一致的結果
SELECT ENAME, SAL, (SELECT MAX(SAL) FROM emp) 最高工資 FROM emp;
SELECT子查詢
定義:SELECT子查詢是嵌套在SELECT子句中的子查詢,作為主查詢返回結果的一個字段值,其結果與主查詢的行數保持一致(每行返回一個對應值)。
一、語法特點
-
位置:出現在SELECT子句中,作為一個 “虛擬字段” 存在。
-
結果要求:子查詢需返回單行單列的值(即單個數值或字符串),確保與主查詢的每行記錄一一對應。
-
執行邏輯:主查詢每讀取一行數據,子查詢會執行一次,返回對應的值作為該字段的結果。
二、示例解析
SELECT ENAME 姓名,SAL 薪資,(SELECT MAX(SAL) FROM emp) AS 最高工資 -- SELECT子查詢:返回全表最高工資
FROM emp;
-
子查詢(SELECT MAX(SAL) FROM emp)獨立計算全表最高工資(單行單列結果)。
-
主查詢返回每位員工的姓名、薪資,同時將子查詢結果作為 “最高工資” 字段,與每行員工信息對應。
三、使用場景
-
關聯單行數據:獲取與主查詢每行記錄相關的單行參考值(如對比個人薪資與全表最高薪資)。
-
簡化多步查詢:無需單獨執行子查詢再手動關聯結果,直接在SELECT中嵌套實現。
四、注意事項
-
子查詢必須返回單行單列結果,否則會報錯(如返回多行時需配合LIMIT 1等限制)。
-
避免在大數據量場景中過度使用,因每行執行一次子查詢可能導致性能下降(可通過關聯查詢優化)。
總結:SELECT子查詢通過在字段列表中嵌套單行子查詢,為每條主查詢記錄附加一個動態計算的參考值,適用于需對比或補充單行關聯數據的場景。
九、分頁查詢
(一)、分頁查詢的必要性
-
性能優化:當表數據量龐大時(如百萬級記錄),一次性查詢所有數據會導致:
-
數據庫查詢耗時久,占用大量內存。
-
網絡傳輸數據量大,前端渲染壓力大。分頁查詢可按需獲取數據,顯著提升效率。
-
用戶體驗:網頁或應用中,分頁展示數據更符合用戶瀏覽習慣(如 “下一頁”“上一頁” 按鈕),避免信息過載。
(二)、分頁查詢語法(以 MySQL 為例)
關鍵字:LIMIT n, m
-
n:起始數據的索引(從 0 開始)。
-
m:每頁顯示的條數。
語法規則
SELECT 字段 FROM 表名
[WHERE 條件]
[ORDER BY 排序字段]
LIMIT n, m;
示例
1. 查詢首頁數據(前 10 條):
SELECT * FROM emp LIMIT 0, 10; -- 或簡寫為 LIMIT 10
- n=0?表示從第一條數據開始(索引 0)。
- m=10?表示每頁顯示 10 條。
2. 查詢第二頁數據(第 11-20 條):
SELECT * FROM emp LIMIT 10, 10;
- n=10?表示從第 11 條數據開始(索引 10)。
- m=10?表示每頁顯示 10 條。
(三)、分頁查詢與其他語法的結合
與排序結合:
分頁前需對數據排序,確保每頁數據的順序一致。
SELECT * FROM emp
ORDER BY SAL DESC -- 按工資降序排序
LIMIT 10, 10; -- 查詢第二頁數據
與篩選條件結合:
先篩選數據,再分頁展示。
SELECT * FROM emp
WHERE DEPTNO = 10 -- 僅查詢部門10的員工
LIMIT 0, 5; -- 每頁顯示5條
與連接查詢結合:
多表關聯后分頁展示結果。
SELECT e.ENAME, d.DNAME
FROM emp e
LEFT JOIN dept d
ON e.DEPTNO = d.DEPTNO
LIMIT 0, 5;
(四)、分頁查詢的注意事項
-
數據庫兼容性:
-
MySQL 使用?LIMIT n, m。
-
Oracle 使用?ROWNUM?或?OFFSET...FETCH(如?OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY)。
-
SQL Server 使用?OFFSET...FETCH(與 Oracle 類似)。
-
索引優化:分頁查詢時,若涉及排序字段,需確保該字段有索引,否則大量數據排序會導致性能下降。
-
動態計算頁碼:在實際應用中,頁碼需根據總記錄數和每頁條數動態計算,例如:
-
總記錄數:SELECT COUNT(*) FROM emp;
-
總頁數:CEIL(總記錄數 / 每頁條數)
SELECT COUNT(*) FROM emp;
SELECT CEIL((SELECT COUNT(*) FROM emp) / 10);
十、函數整理
窗口函數
窗口函數是現代數據分析中處理復雜計算、排名、移動平均、累計值、分區內比較等任務的利器,是數據分析師日常工作中頻繁使用的工具。
為什么窗口函數對數據分析崗位至關重要?
-
處理復雜排名和分位數: 計算銷售排名、部門內薪資排名、成績百分位等(ROW_NUMBER(), RANK(), DENSE_RANK(), NTILE(), PERCENT_RANK(), CUME_DIST())。
-
計算趨勢和移動指標: 計算滾動平均銷售額、移動總和、環比/同比變化等(SUM() OVER(...), AVG() OVER(...), 結合 ROWS/RANGE 子句)。
-
訪問前后行數據: 分析用戶行為序列(如上一步/下一步操作)、計算與前一行的差值或比率(LAG(), LEAD())。
-
分區內聚合而不折疊行: 計算每個員工薪資占其部門總薪資的比例、計算每個客戶訂單總額的同時保留訂單明細(SUM() OVER(PARTITION BY ...))。
-
累積計算: 計算年初至今(YTD)銷售額、累計用戶數等(SUM() OVER(ORDER BY ... ROWS UNBOUNDED PRECEDING))。
-
高效處理“Top N per Group”問題: 找出每個部門薪資最高的前3名員工(結合 ROW_NUMBER() 或 RANK() 和子查詢/CTE)。
功能:
對數據的指定分區(窗口) 進行跨行計算,不折疊結果集(保留原始行),實現排名、累積、移動平均等復雜分析。
與 GROUP BY 關鍵區別:
維度 | GROUP BY (分組聚合) | 窗口函數 |
結果行數 | 折疊為分組數(行數減少) | 保留原表行數(行數不變) |
計算粒度 | 每組返回一個匯總值 | 每行返回基于窗口的獨立計算結果 |
典型場景 | 部門平均工資、崗位人數統計 | 部門內薪資排名、累計銷售額分析 |
1. 基礎語法框架
SELECT 字段1, 字段2, 窗口函數() OVER ( [PARTITION BY 分區字段] -- 將數據劃分為多個窗口(類似分組) [ORDER BY 排序字段] -- 窗口內數據排序(影響排名、累積計算) [ROWS/RANGE 窗口幀] -- 定義計算范圍(如 "當前行前3行") ) AS 別名
FROM 表名;
2. 常用窗口函數類型與示例
1)排名函數
函數 | 功能說明 | 示例場景 |
ROW_NUMBER() | 為分區內每行生成唯一連續序號 | 按部門給員工薪資排名(無并列) |
RANK() | 并列時跳過后續序號(1,1,3) | 銷售業績排名(允許名次并列) |
DENSE_RANK() | 并列時不跳號(1,1,2) | 學生成績等級排名(緊密排序) |
示例:查詢每個部門內員工的薪資排名(允許并列)
SELECT DEPTNO 部門編號, ENAME 員工姓名, SAL 薪資, RANK() OVER ( PARTITION BY DEPTNO -- 按部門分區 ORDER BY SAL DESC -- 薪資降序排序 ) AS 部門內薪資排名
FROM emp;
結果示例:
部門編號 | 員工姓名 | 薪資 | 部門內薪資排名 | |
10 | KING | 5000 | 1 | |
10 | CLARK | 2450 | 2 | |
20 | SCOTT | 3000 | 1 | |
20 | FORD | 3000 | 1 | -- 并列第一 |
20 | ADAMS | 1100 | 3 | -- RANK() 跳過2 |
2)聚合函數 + 窗口函數
功能:在分區內計算聚合值(如累加、移動平均),不折疊行。
常用函數:
SUM(字段) OVER (...) -- 累計求和
AVG(字段) OVER (...) -- 移動平均
MAX/MIN(字段) OVER (...)
示例1:計算每位員工的累計薪資(按入職順序累加)
SELECT ENAME, HIREDATE, SAL, SUM(SAL) OVER ( ORDER BY HIREDATE -- 按入職日期排序 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -- 從首行到當前行 ) AS 累計薪資
FROM emp;
3)取值函數
函數 | 功能說明 |
LAG(字段, N) | 獲取當前行前N行的數據 |
LEAD(字段, N) | 獲取當前行后N行的數據 |
FIRST_VALUE(字段) | 返回窗口內第一行的值 |
LAST_VALUE(字段) | 返回窗口內最后一行的值 |
示例:分析每月銷售額環比增長率
SELECT sale_month, sales, LAG(sales, 1) OVER (ORDER BY sale_month) AS 上月銷售額, (sales - LAG(sales, 1) OVER (ORDER BY sale_month)) / LAG(sales, 1) OVER (ORDER BY sale_month) AS 環比增長率
FROM sales_table;
3. 窗口幀控制(ROWS vs RANGE)
關鍵字 | 說明 | 示例 |
ROWS | 物理行 范圍(推薦使用) | ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING (當前行前后各1行) |
RANGE | 邏輯值 范圍(易混淆) | RANGE BETWEEN 100 PRECEDING AND 200 FOLLOWING (值在±100內) |
常用幀范圍:
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -- 從分區開始到當前行(累計算)
ROWS BETWEEN 3 PRECEDING AND 1 FOLLOWING -- 前3行到后1行
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING -- 當前行到分區結束
4. 核心特點總結
- 不折疊結果:保留原表所有行,新增計算列,適合明細級分析報告。
- 分層計算:通過 PARTITION BY 實現“組內分析”(如部門內排名)。
- 動態范圍:ORDER BY + 窗口幀 支持時間序列分析(移動平均、累計值)。
- 性能優化:比自連接/子查詢更高效處理復雜分析(如 Top N 問題)。
- 面試重點:數據分析崗位必考,用于解決:
- 排名問題(ROW_NUMBER(), RANK())
- 趨勢分析(LAG()/LEAD(), 移動平均)
- 占比計算(SUM() OVER(PARTITION BY))