深度解析Mysql的開窗函數(易懂版)

SQL 開窗函數(Window Function)是一種強大的分析工具,它能在保留原有數據行的基礎上,對 "窗口"(指定范圍的行集合)進行聚合、排名或分析計算,解決了傳統GROUP BY聚合會合并行的局限性。

一、開窗函數的核心特點

  • 不合并行:與GROUP BY不同,開窗函數計算后會保留所有原始行,只是為每行附加一個計算結果。
  • 窗口定義:通過OVER()子句定義 "窗口"(即計算范圍),可按條件分區、排序或限定行范圍。
  • 適用場景:排名(如 top N)、累計計算(如累計求和)、移動分析(如近 3 天平均值)、前后行數據獲取等。

二、基本語法結構

開窗函數的通用語法:

函數名(參數) OVER ([PARTITION BY 分區列1, 分區列2...]  -- 可選:按列分組,每組獨立計算[ORDER BY 排序列1 [ASC|DESC], ...]  -- 可選:分區內的排序方式[ROWS | RANGE 窗口范圍]  -- 可選:定義窗口的具體行范圍(行級窗口)
)

  • 函數名:可以是排名函數(RANK()ROW_NUMBER()等)、聚合函數(SUM()AVG()等)或分析函數(LAG()LEAD()等)。
  • OVER()子句:核心部分,用于定義 "窗口" 的規則。

三、OVER()子句詳解

1.?PARTITION BY:分區(分組)
  • 作用:將數據按指定列分成多個獨立的 "分區",開窗函數在每個分區內單獨計算(類似GROUP BY的分組,但不合并行)。
  • 示例:按 "部門" 分區,每個部門內部獨立計算工資排名。
2.?ORDER BY:分區內排序
  • 作用:指定分區內的行排序規則,影響排名函數的結果和窗口范圍的界定。
  • 注意:若不指定PARTITION BY,則全表視為一個分區,按ORDER BY整體排序。
3.?ROWS | RANGE:窗口范圍(行級窗口)
  • 作用:在分區內,進一步限定參與計算的行范圍(如 "當前行 + 前 2 行 + 后 1 行")。
  • 關鍵字:
    • ROWS:基于物理行數界定范圍(如 "前 2 行")。
    • RANGE:基于值的邏輯范圍界定(如 "值在當前行 ±10 以內的行"),僅支持數值 / 日期類型。
  • 常用范圍表達式:
    • UNBOUNDED PRECEDING:分區的第一行
    • CURRENT ROW:當前行
    • n PRECEDING:當前行之前的第 n 行
    • n FOLLOWING:當前行之后的第 n 行
    • 組合示例:ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING(當前行 + 前 2 行 + 后 1 行)

四、常用開窗函數分類及示例

以下示例基于員工表employee,結構如下:

idnamedepartmentsalaryhire_date
1張三技術部80002020-01-15
2李四技術部90002019-03-20
3王五技術部90002018-05-10
4趙六市場部70002021-02-05
5錢七市場部85002020-08-18
1. 排名函數(用于生成排名)
(1)ROW_NUMBER():生成唯一序號
  • 功能:為分區內的每行分配一個連續的唯一序號(即使值相同,序號也不同)。
  • 示例:按部門分區,按工資降序排名(工資相同則按入職時間升序):
SELECT name, department, salary,ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC, hire_date ASC) AS row_num
FROM employee;
  • 結果:
    namedepartmentsalaryrow_num
    李四技術部90001(同工資,入職早排前)
    王五技術部90002
    張三技術部80003
    錢七市場部85001
    趙六市場部70002
(2)RANK():帶跳號的排名
  • 功能:相同值排名相同,后續排名會 "跳號"(如兩個第 1 名,下一個是第 3 名)。
  • 示例:按部門分區,按工資降序排名:
SELECT name, department, salary,RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_num
FROM employee;

  • 結果:
    namedepartmentsalaryrank_num
    李四技術部90001
    王五技術部90001(與李四并列第 1)
    張三技術部80003(跳號,直接第 3)
    錢七市場部85001
    趙六市場部70002
(3)DENSE_RANK():無跳號的排名
  • 功能:相同值排名相同,后續排名不跳號(如兩個第 1 名,下一個是第 2 名)。
  • 示例:按部門分區,按工資降序排名:
SELECT name, department, salary,DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rank_num
FROM employee;

  • 結果:
    namedepartmentsalarydense_rank_num
    李四技術部90001
    王五技術部90001
    張三技術部80002(不跳號,第 2)
    錢七市場部85001
    趙六市場部70002
2. 聚合開窗函數(聚合函數 +OVER()

SUM()AVG()COUNT()等聚合函數與OVER()結合,為每行計算所在窗口的聚合結果。

(1)全分區聚合(無ORDER BY和范圍)
  • 功能:計算整個分區的聚合值(每行的結果相同)。
  • 示例:計算每個部門的平均工資,附加到每行:
SELECT name, department, salary,AVG(salary) OVER (PARTITION BY department) AS dept_avg_salary
FROM employee;

  • 結果:
    namedepartmentsalarydept_avg_salary
    張三技術部80008666.67((8000+9000+9000)/3)
    李四技術部90008666.67
    王五技術部90008666.67
(2)累計聚合(帶ORDER BY和范圍)
  • 功能:按排序順序計算 "累計" 聚合值(如累計求和、累計平均值)。
  • 示例:按部門分區,按入職時間升序,計算累計工資總和:
SELECT name, department, hire_date,salary,SUM(salary) OVER (PARTITION BY department ORDER BY hire_date ASCROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW  -- 從第一行到當前行) AS cumulative_salary
FROM employee;
  • 結果(技術部):
    namedepartmenthire_datesalarycumulative_salary
    王五技術部2018-05-1090009000(第一行,累計 = 自身)
    李四技術部2019-03-20900018000(累計 = 9000+9000)
    張三技術部2020-01-15800026000(累計 = 9000+9000+8000)
3. 分析函數(獲取前后行數據)
(1)LAG(列名, n):獲取當前行的前 n 行數據
  • 功能:返回當前行之前第 n 行的指定列值(默認 n=1)。
  • 示例:獲取每個部門中,當前員工的前一位入職員工的工資:
SELECT name, department, hire_date,salary,LAG(salary, 1) OVER (PARTITION BY department ORDER BY hire_date ASC) AS prev_emp_salary
FROM employee;

  • 結果(技術部):
    namedepartmenthire_datesalaryprev_emp_salary
    王五技術部2018-05-109000NULL(第一行,無前一行)
    李四技術部2019-03-2090009000(前一行是王五的工資)
    張三技術部2020-01-1580009000(前一行是李四的工資)
(2)LEAD(列名, n):獲取當前行的后 n 行數據
  • 功能:返回當前行之后第 n 行的指定列值(默認 n=1)。
  • 示例:獲取每個部門中,當前員工的后一位入職員工的工資:
SELECT name, department, hire_date,salary,LEAD(salary, 1) OVER (PARTITION BY department ORDER BY hire_date ASC) AS next_emp_salary
FROM employee;

  • 結果(技術部):
    namedepartmenthire_datesalarynext_emp_salary
    王五技術部2018-05-1090009000(后一行是李四的工資)
    李四技術部2019-03-2090008000(后一行是張三的工資)
    張三技術部2020-01-158000NULL(最后一行,無后一行)

五、開窗函數與GROUP BY的區別

特性GROUP BY聚合開窗函數
行處理合并分組后的行(一行 / 組)保留所有原始行
計算范圍整個分組可自定義窗口范圍(分區、行范圍)
結果列僅聚合結果 + 分組列原始列 + 開窗計算結果

六、注意事項

  1. 排序影響ORDER BY在開窗函數中不僅影響排名,還會影響窗口范圍的界定(如累計計算)。
  2. 性能考量:復雜的窗口范圍(如RANGE)可能導致性能下降,大表建議優先用ROWS
  3. 數據庫支持:主流數據庫(MySQL 8.0+、PostgreSQL、SQL Server、Oracle)均支持開窗函數,但部分細節可能有差異。

通過上述講解,可掌握開窗函數的核心語法和應用場景。實際使用時,需根據業務需求靈活組合PARTITION BYORDER BY和窗口范圍,實現復雜的數據分析。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95285.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95285.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95285.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java靜態代理和動態代理

Java靜態代理和動態代理 靜態代理 現在有一個計算類,有四個方法,加減乘除,如果需要給這四個方法都加上同一個邏輯,可以創建一個類作為代理類,把計算類注入到這個類中,然后再代理類中定義方法,并…

MySQL——MySQL引擎層BufferPool工作過程原理

目錄一、MySQL引擎層BufferPool工作過程圖解二、MySQL引擎層BufferPool工作過程原理一、MySQL引擎層BufferPool工作過程圖解 圖解 二、MySQL引擎層BufferPool工作過程原理 首先關閉自動提交,執行一條修改語句。 SET AUTOCOMMIT 0; update employees set name張三…

Python初學者筆記第二十二期 -- (JSON數據解析)

第31節課 JSON數據解析 1.JSON基礎概念 JSON 是一種輕量級的數據交換格式(另一個叫XML),具有簡潔、易讀的特點,并且在不同編程語言之間能很好地實現數據傳遞。在 Python 中,json模塊能夠實現 Python 數據類型與 JSON 數…

基于多模態大模型的個性化學習路徑生成系統研究

摘要 隨著互聯網技術的迅猛發展,個性化學習路徑生成系統的研究在教育領域日益凸顯其重要性。本研究聚焦于基于多模態大模型的個性化學習路徑生成系統,旨在通過整合多模態數據,為學習者提供更加精準、個性化的學習路徑。多模態大模型&#xf…

ESP32 燒錄固件失敗原因排除

ESP32 燒錄固件時,有哪些特殊引腳需要注意電平狀態的在 ESP32 燒錄固件時,有幾個關鍵引腳的電平狀態會直接影響燒錄過程,需要特別注意:GPIO0(BOOT 引腳):燒錄模式:需要拉低&#xff…

3D視覺系統在機器人行業中的應用

視覺引導機器人技術(VGR)具有成熟的2D成像技術,但是經濟高效的3D技術的出現使機器人應用的可能性更大。工業自動化的第一次迭代使用“盲”機器人,該機器人取決于待處理材料的精確定位。這樣的機器人相對不靈活,只能通過…

MySQL高可用改造之數據庫開發規范(大事務與數據一致性篇)

文章目錄一、前言二、延遲的原因三、大事務處理規范3.1. 刪除類操作優化設計3.2. 大事務通用拆分原則四、數據一致性核對規范4.1. 主從變更記錄識別方法五、小結一、前言 MySQL 高可用架構中最基礎、最為核心的內容:MySQL 復制(Replication)…

第9節 大模型分布式推理核心挑戰與解決方案

文章目錄 # 前言 一、通信瓶頸突破:讓數據“跑”得更快 1. 問題:通信為什么會成為瓶頸? 2. 解決方案:從硬件到算法的全鏈路優化 (1)硬件層:升級“高速公路” (2)算法層:給數據“瘦身”并“錯峰出行” (3)架構層:讓數據“少跑路” 3. 效果評估:如何判斷通信瓶頸已…

ESP32開發板接4陣腳屏幕教程(含介紹和針腳編號對應)

“4針屏幕” 一般有兩種常見類型:IC 屏幕(如 0.96" OLED、SSD1306 等) 4 個針腳通常是:VCC → 接 ESP32 的 3.3V(有的屏幕支持 5V)GND → 接 ESP32 的 GNDSCL(時鐘)→ 接 ESP32…

2025 年國內可用 Docker 鏡像加速器地址

文章目錄一、加速器地址搭建 Docker 鏡像源二、使用一、加速器地址 docker.1ms.rundocker.domys.ccdocker.imgdb.dedocker-0.unsee.techdocker.hlmirror.comcjie.eu.orgdocker.m.daocloud.iohub.rat.devdocker.1panel.livedocker.rainbond.cc 搭建 Docker 鏡像源 以上鏡像源…

[Robotics_py] 路徑規劃算法 | 啟發式函數 | A*算法

第五章:路徑規劃算法 歡迎回來,未來的機器人專家-=≡(?ω?) 在之前的章節中,我們已為機器人配備了核心知識:它能夠跟蹤自身的機器人狀態/位姿,利用環境表示(柵格地圖)理…

解決 HTTP 請求 RequestBody 只能被讀取一次的問題

簡介 HTTP 請求 RequestBody 只能被讀取一次:HttpServletRequest 的輸入流 (InputStream) 在被讀取后會被關閉,導致后續無法再次讀取。本文將介紹如何通過 請求包裝類 (RequestWrapper) 來解決這個問題。問題背景 當我們需要在以下場景中多次讀取 Reques…

(LeetCode 面試經典 150 題) 226. 翻轉二叉樹 (深度優先搜索dfs )

題目:226. 翻轉二叉樹 思路:深度優先搜索dfs,時間復雜度0(n)。 C版本: /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr)…

2025牛客暑期多校訓練營3(FDJAEHB)

題目鏈接&#xff1a;牛客競賽_ACM/NOI/CSP/CCPC/ICPC算法編程高難度練習賽_牛客競賽OJ F Flower 思路 可知當n<a時無論怎么操作她都會離開 n%(ab&#xff09;是指進行完若干輪之后剩下的不足ab個&#xff0c;如果是>a的話那么最后一輪必然不在a中&#xff0c;否則就…

【KO】 Android基礎

以下是對這些 Android 相關問題的解答: 1. Activity 與 Fragment 之間常見的幾種通信方式 接口回調:Fragment 定義接口,Activity 實現該接口,Fragment 通過接口實例調用方法傳遞數據 。 使用 Bundle:Fragment 可通過 setArguments(Bundle) 傳數據給自身,Activity 可在創…

Gradle構建工具教程:由來與發展史(版本演進與未來優勢)

一、Gradle簡介Gradle是一個基于Apache Ant和Apache Maven概念的項目自動化構建開源工具&#xff0c;使用基于Groovy的領域特定語言&#xff08;DSL&#xff09;聲明項目設置。相較于傳統XML配置&#xff0c;這種DSL使構建腳本更簡潔易讀。Gradle支持Java、Groovy、Kotlin、Sca…

@Rancher簡介部署使用 - Docker Compose

Rancher 安裝和使用介紹 - Docker Compose 文章目錄Rancher 安裝和使用介紹 - Docker Compose1. Rancher 簡介1.1 什么是 Rancher1.2 Rancher 核心功能1.3 Rancher 架構2. 安裝前準備2.1 系統要求2.2 環境準備3. 使用 Docker Compose 安裝 Rancher3.1 創建 Docker Compose 文件…

程序員接私活的一些平臺和建議,千萬要注意,別掉坑里!

關于程序員接私活&#xff0c;社會各界說法不一&#xff0c;如果你確實急用錢&#xff0c;價格又合適&#xff0c;那就去做。 不過&#xff0c;私活也沒有那么好做&#xff0c;一般私活的性價比遠比上班拿工資的低。但是作為一個額外的收益渠道&#xff0c;一部分生活窘迫的程序…

多輪問答與指代消解

目錄引言一、LangChain是怎么實現的多輪問答1、記憶模塊&#xff08;Memory&#xff09;管理對話歷史?2、對話鏈&#xff08;Conversational Chain&#xff09;架構?3、智能體&#xff08;Agent&#xff09;決策機制?4、上下文感知的Prompt工程?5、RAG&#xff08;檢索增強…

文件IO、文件IO與標準IO的區別

一、文件IO --->fd&#xff08;文件描述符&#xff09;打開文件open讀、寫文件read/write關閉文件close#include <sys/types.h>#include <sys/stat.h>#include<fcntl.h>文件描述符&#xff1a;操作系統中已打開文件的標識符。小的、非負的整形數據范圍&am…