MySQL 窗口函數是什么,有這么好用

先看這段像天書一樣的 SQL ,看著就頭疼。

SELECTs1.name,s1.subject,s1.score,sub.avg_score AS average_score_per_subject,(SELECT COUNT(DISTINCT s2.score) + 1 FROM scores s2 WHERE s2.score > s1.score) AS score_rank
FROM scores s1
JOIN (SELECT subject, AVG(score) AS avg_scoreFROM scoresGROUP BY subject
) sub ON s1.subject = sub.subject
ORDER BY s1.score DESC;

這段SQL是干什么用的呢,就是為了計算一個成績排名,簡直大動干戈啊。

那有沒有簡化的方法呢?有的。

簡化后的版本就是利用今天說的窗口函數。

SELECTname,subject,score,AVG(score) OVER (PARTITION BY subject) AS average_score_per_subject,RANK() OVER (ORDER BY score DESC) AS score_rank
FROM scores
ORDER BY score DESC;

是不是看上去就簡潔清晰多了。

下面我們看看是什么樣的功能。

首先創建一個表,包含姓名、學科、分數三個字段,用于后面功能的演示。

CREATE TABLE `scores` (`name` varchar(20) COLLATE utf8_bin NOT NULL,`subject` varchar(20) COLLATE utf8_bin NOT NULL,`score` int(3) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

然后向表中插入一些隨機記錄。

INSERT INTO scores (name, subject, score) VALUES ('Student1', '化學', 75);
INSERT INTO scores (name, subject, score) VALUES ('Student2', '生物', 92);
INSERT INTO scores (name, subject, score) VALUES ('Student3', '物理', 87);
INSERT INTO scores (name, subject, score) VALUES ('Student4', '數學', 68);
INSERT INTO scores (name, subject, score) VALUES ('Student5', '英語', 91);
INSERT INTO scores (name, subject, score) VALUES ('Student6', '化學', 58);
INSERT INTO scores (name, subject, score) VALUES ('Student7', '物理', 79);
INSERT INTO scores (name, subject, score) VALUES ('Student8', '數學', 90);
INSERT INTO scores (name, subject, score) VALUES ('Student9', '數學', 45);

##什么是窗口函數

在 MySQL 8.x 版本中,MySQL 提供了窗口函數,窗口函數是一種在查詢結果的特定窗口范圍內進行計算的函數。

很早以前用 Oracle 和 MS SQL 的時候會用到里面的窗口函數,但是用 MySQL 后才發現,MySQL 竟然沒有窗口函數,以至于一些負責的統計查詢都要用各種子查詢、join,層層嵌套,看上去很簡單的需求,結果搞得 SQL 語句寫的是龍飛鳳舞,別人一看跟天書似的。就一個字兒,懵。

窗口函數主要的應用場景是統計和計算,例如對查詢結果進行分組、排序和計算聚合,通過各個函數的組合,可以實現各種復雜的邏輯,而且比起 MySQL 8.0之前用子查詢、join 的方式,性能上要好得多。

OVER()

OVER() 是用于定義窗口函數的子句,它必須結合其他的函數才有意義,比如求和、求平均數。而它只用于指定要計算的數據范圍和排序方式。

function_name(...) OVER ([PARTITION BY expr_list] [ORDER BY expr_list] [range]
)

PARTITION BY

用于指定分區字段,對不同分區進行分析計算,分區其實就列,可以指定一個列,也可以指定多個列。

ORDER BY

用于對分區內記錄進行排序,排序后可以與「范圍和滾動窗口」一起使用。

范圍和滾動窗口

用于指定分析函數的窗口,包括范圍和滾動窗口。

范圍窗口(Range window)

指定窗口的起止行號,使用UNBOUNDED PRECEDING表示起點,UNBOUNDED FOLLOWING表示終點。

例如:

SUM(salary) OVER (ORDER BY id  RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING)

這會計算當前行及之前5行和之后5行的salary總和。

滾動窗口(Row window)

使用了基于當前行的滾動窗口

例如:

SUM(salary) OVER (ORDER BY id  ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING)

這會計算當前行及之前2行和之后2行的salary總和。

OVER()可搭配的函數:

聚合函數

MAX(),MIN(),COUNT(),SUM()等,用于生成每個分區的聚合結果。

排序相關

ROW_NUMBER(),RANK(),DENSE_RANK()等,用于生成每個分區的行號或排名。

窗口函數

LAG(),LEAD(),FIRST_VALUE(),LAST_VALUE()等,用于基于窗口框生成結果。

搭配聚合函數

1、按subject列進行分區,并求出某學科的最大最小值

獲取分數和此學科最高分

SELECT subject,score, MAX(score) OVER (PARTITION  BY subject) as `此學科最高分` FROM scores;

得出的結果是:

subjectscore此學科最高分
化學7575
化學5875
數學6890
數學9090
數學4590
物理8787
物理7987
生物9292
英語9191

2、獲取學科的報名人數

SELECT subject,score, count(name) OVER (PARTITION  BY subject) as `報名此學科人數` FROM scores;

得到的結果為:

subjectscore報名此學科人數
化學752
化學582
數學683
數學903
數學453
物理872
物理792
生物921
英語911

3、求學科的總分

SELECT subject, SUM(score) OVER (PARTITION  BY subject) as `此學科總分` FROM scores;

得到的結果:

subject此學科總分
化學133
化學133
數學203
數學203
數學203
物理166
物理166
生物92
英語91

4、使用 order by 求累加分數

SELECT name,subject,score, SUM(score) OVER (order  BY score) as `累加分數` FROM scores;

得到的結果:

namesubjectscore累加分數
Student9數學4545
Student6化學58103
Student4數學68171

我們看這是怎么算出來的,OVER 函數里面是 order by 。

首先根據分數排序(默認升序),得到第一行分數是45,所以累加分數就是它自己,也就是45。

然后排序得到第二行 58,然后將第一行和第二行相加,這樣得到累加分數就是45+58=103。

同理,第三行就是前三行的總和,也就是45+58+68=171。

以此類推,第 N 行就是1~N的累加和。

5、使用 order by + 范圍

前面因為沒有限定范圍,所以就是前 N 行的累加,還可以限定范圍。

SELECT name,subject,score, SUM(score) OVER (order BY `score` ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as `累加分數` FROM scores;

這里的累加分數是指當前行+前一行+后一行的和。

獲取的結果為:

namesubjectscore累加分數
Student9數學45103
Student6化學58171
Student4數學68201
Student1化學75222
Student7物理79241
Student3物理87256
Student8數學90268
Student5英語91273

第一行 103,是當前行 45+后一行(58)的和,等于103,因為沒有前一行。

第二行171,是當前行58+前一行(45)+后一行(68)的和,等于171。

以此類型,后面的累加分數都是這樣算出來的。

搭配排序相關函數

ROW_NUMBER()

ROW_NUMBER() 函數用于為結果集中的每一行分配一個唯一的排序。

如下,對成績進行排名,分數高的排在前面,如果有兩個人分數相同,那仍然是一個第一,另一個第二。

SELECT name,subject,score, ROW_NUMBER() OVER (order BY `score` desc) as `排名` FROM scores;

查詢結果為:

namesubjectscore排名
Student2生物921
Student5英語912
Student8數學903
Student3物理874
Student7物理795

如果不用 ROW_NUMBER(),比如在 MySQL 5.7的版本中,就會像下面這樣:

SELECT s1.name, s1.subject, s1.score, COUNT(s2.score) + 1 AS `排名`
FROM scores s1
LEFT JOIN scores s2 ON s1.score < s2.score
GROUP BY s1.name, s1.subject, s1.score
ORDER BY s1.score DESC;

是不是比使用 ROW_NUMBER()復雜的多。

RANK()

RANK() 函數用于為結果集中的每一行分配一個排名值,它也是排名的,但是它和 ROW_NUMBER()有,RANK()函數在遇到相同值的行會將排名設置為相同的,就像是并列排名。

就像是奧運比賽,如果有兩個人都是相同的高分,那可能就是并列金牌,但是這時候就沒有銀牌了,僅次于這兩個人的排名就會變成銅牌。

SELECT name,subject,score, RANK() OVER (order BY `score` desc) as `排名` FROM scores;

查詢結果為:

namesubjectscore排名
Student1化學921
Student2生物921
Student5英語913
Student8數學904
Student3物理875

DENSE_RANK()

DENSE_RANK() 也是用作排名的,和 RANK()函數的差別就是遇到相同值的時候,不會跳過排名,比如兩個人是并列金牌,排名都是1,那僅次于這兩個人的排名就是2,而不像 RANK()那樣是3。

SELECT name,subject,score, DENSE_RANK() OVER (order BY `score` desc) as `排名` FROM scores;

查詢結果為:

namesubjectscore排名
Student1化學921
Student2生物921
Student5英語912
Student8數學903

配合其他窗口函數

NTILE()

NTILE() 函數用于將結果集劃分為指定數量的組,并為每個組分配一個編號。例如,將分數倒序排序并分成4個組,相當于有了4個梯隊。

SELECT name,subject,score, NTILE(4) OVER (order BY `score` desc) as `` FROM scores;

查詢結果為:

namesubjectscore
Student1化學921
Student2生物921
Student5英語911
Student8數學902
Student3物理872
Student7物理793
Student4數學683
Student6化學584
Student9數學454

LAG()

LAG() 函數用于在查詢結果中訪問當前行之前的行的數據。它允許您檢索前一行的值,并將其與當前行的值進行比較或計算差異。LAG()函數對于處理時間序列數據或比較相鄰行的值非常有用。

LAG()函數完整的表達式為 LAG(column, offset, default_value),包含三個參數:

column:就是列名,獲取哪個列的值就是哪個列名,很好理解。

offset: 就是向前的偏移量,取當前行的前一行就是1,前前兩行就是2。

default_value:是可選值,如果向前偏移的行不存在,就取這個默認值。

例如比較相鄰兩個排名的分數差,可以這樣寫:

SELECTname,subject,score,ABS(score - LAG(score, 1,score) OVER (ORDER BY score DESC)) AS `分值差`
FROMscores;

得到的結果為:

namesubjectscore分值差
Student1化學920
Student2生物920
Student5英語911
Student8數學901
Student3物理873
Student7物理798
Student4數學6811

LEAD()

LEAD() 函數和 LAG()的功能一致,只不過它的偏移量是向后偏移,也就是取當前行的后 N 行。

所以前面的比較相鄰兩行差值的邏輯,也可以向后比較。

SELECTname,subject,score,score - LEAD(score, 1,score) OVER (ORDER BY score DESC) AS `分值差`
FROMscores;

得到的結果:

namesubjectscore分值差
Student1化學920
Student2生物921
Student5英語911
Student8數學903
Student3物理878
Student7物理7911
Student4數學6810

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

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

相關文章

Android 13 MTK平臺添加自定義按鍵,以及CTS問題解決

添加自定義按鍵流程 一般來說上層添加以下幾處修改 驅動層的鍵值上報,讓驅動處理好即可 frameworks / base/core/java/android/view/KeyEvent.java public static final int KEYCODE_DEMO_APP_4 = 304;/** add by songhui for fingerprint Key code */+ public static fina…

IntelliJ IDEA Bookmark使用

1 增加 右鍵行號欄 2 查看 從favorite這里查看 參考IntelliJ IDEA 小技巧&#xff1a;Bookmark(書簽)的使用_bookmark idea 使用_大唐冠軍侯的博客-CSDN博客

neo4j的CQL命令實例演示

天行健&#xff0c;君子以自強不息&#xff1b;地勢坤&#xff0c;君子以厚德載物。 每個人都有惰性&#xff0c;但不斷學習是好好生活的根本&#xff0c;共勉&#xff01; 文章均為學習整理筆記&#xff0c;分享記錄為主&#xff0c;如有錯誤請指正&#xff0c;共同學習進步。…

07-2_Qt 5.9 C++開發指南_二進制文件讀寫(stm和dat格式)

文章目錄 1. 實例功能概述2. Qt預定義編碼文件的讀寫2.1 保存為stm文件2.2 stm文件格式2.3 讀取stm文件 3. 標準編碼文件的讀寫3.1 保存為dat文件3.2 dat文件格式3.3 讀取dat文件 4. 框架及源碼4.1 可視化UI設計4.2 mainwindow.cpp 1. 實例功能概述 除了文本文件之外&#xff…

pve和openwrt以及我的電腦中網絡的關系和互通組網

情況1 一臺主機 有4個口&#xff0c;分別eth0,eth1,eth2,eth3 pve有管理口 這個情況下 &#xff0c;沒有openwrt 直接電腦和pve管理口連在一起就能進pve管理界面 情況2 假設pve 的管理口味eth0 openwrt中橋接的是eth0 eth1 eth2 那么電腦連接eth3或者pve管理口設置eth3&#xf…

【C#】設置有線網卡IP地址,子網掩碼,網關,DNS

方法 public partial class ComputerInfo{/// <summary>/// 設置IP地址&#xff0c;子網掩碼&#xff0c;網關&#xff0c;DNS/// </summary>public static List<NetworkAdapterInfo> SetIpAddressSubMaskDnsGeteway(string ipAddress, string subMask, stri…

MySQL庫的操作

文章目錄 MySQL庫的操作1. 創建數據庫2. 字符集和校驗規則(1) 查看系統默認字符集以及校驗規則(2) 查看數據庫支持的字符集和校驗規則(3) 案例(4) 校驗規則對數據庫的影響 3. 查看數據庫4. 修改數據庫5. 刪除數據庫6. 數據庫的備份和恢復(1) 備份(2) 還原 7. 查看連接情況 MySQ…

在 Windows 中恢復數據的 5 種方法

發生數據丟失的原因有多種。無論是因為文件被意外刪除、文件系統或操作系統損壞&#xff0c;還是由于軟件或硬件級別的存儲故障&#xff0c;數據都會在您最意想不到的時候丟失。今天我們重點介紹五種數據恢復方法&#xff0c;以應對意外情況的發生。 1.從另一臺機器啟動硬盤 如…

分享一組天氣組件

先看效果&#xff1a; CSS部分代碼&#xff08;查看更多&#xff09;&#xff1a; <style>:root {--bg-color: #E9F5FA;--day-text-color: #4DB0D3;/* 多云 */--cloudy-background: #4DB0D3;--cloudy-temperature: #E6DF95;--cloudy-content: #D3EBF4;/* 晴 */--sunny-b…

python基礎環境建設(pip、anaconda)

1.pip 配置文件路徑&#xff1a; centos&#xff1a;~/.pip/pip.conf windows: C:\Users\admin\AppData\Roaming\pip\pip.ini 文件內容&#xff1a; [global] index-url http://IP/repository/pypi-tsinghua/simple trusted-hostIP今天centos7.9、python3.6環境 pip install…

Https、CA證書、數字簽名

Https Http協議 Http協議是目前應用比較多應用層協議&#xff0c;瀏覽器對于Http協議已經實現。Http協議基本的構成部分有 請求行 &#xff1a; 請求報文的第一行請求頭 &#xff1a; 從第二行開始為請求頭內容的開始部分。每一個請求頭都是由K-V鍵值對組成。請求體&#xf…

【C++入門到精通】C++入門 —— vector (STL)

閱讀導航 前言一、vector簡介1. 概念2. 特點 二、vector的使用1.vector 構造函數2. vector 空間增長問題?resize 和 reserve 函數 3. vector 增刪查改?operator[] 函數 三、迭代器失效溫馨提示 前言 前面我們講了C語言的基礎知識&#xff0c;也了解了一些數據結構&#xff0…

軟件測試基礎篇——Docker

1、docker技術概述 docker描述&#xff1a;docker是一項虛擬化的容器技術&#xff08;類似于虛擬機&#xff09;&#xff0c;docker技術給使用者提供一個平臺&#xff0c;在該平臺上可以利用提供的容器&#xff0c;對每一個應用程序進行單獨的封裝隔離&#xff0c;每一個應用程…

spring 2.7.14 cors 設置 allowedOrigins(“*“)通配符 失效怎么解決

失效代碼&#xff1a; package com.yukuanyan.searcher_web.config;import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebM…

計算機競賽 opencv python 深度學習垃圾圖像分類系統

0 前言 &#x1f525; 優質競賽項目系列&#xff0c;今天要分享的是 &#x1f6a9; opencv python 深度學習垃圾分類系統 &#x1f947;學長這里給一個題目綜合評分(每項滿分5分) 難度系數&#xff1a;3分工作量&#xff1a;3分創新點&#xff1a;4分 這是一個較為新穎的競…

圖像的伽馬變換

伽馬變換&#xff08;Gamma Correction&#xff09;是一種在圖像處理中常用的非線性變換方法&#xff0c;用于調整圖像的亮度和對比度。它在圖像的像素值上應用一個冪次函數&#xff0c;以改變圖像的灰度級分布&#xff0c;從而影響圖像的感知亮度。伽馬變換通常用于糾正顯示器…

Monkey測試真的靠譜嗎?

Monkey測試&#xff0c;顧名思義&#xff0c;就是模擬一只猴子在鍵盤上亂敲&#xff0c;從而達到測試被測系統的穩定性。Monkey測試&#xff0c;是Android自動化測試的一種手段&#xff0c;Monkey測試本身非常簡單&#xff0c;Android SDK 工具支持adb Shell命令&#xff0c;實…

208、仿真-51單片機脈搏心率與心電報警Proteus仿真設計(程序+Proteus仿真+配套資料等)

畢設幫助、開題指導、技術解答(有償)見文未 目錄 一、硬件設計 二、設計功能 三、Proteus仿真圖 四、程序源碼 資料包括&#xff1a; 需要完整的資料可以點擊下面的名片加下我&#xff0c;找我要資源壓縮包的百度網盤下載地址及提取碼。 方案選擇 單片機的選擇 方案一&a…

ElasticSearch 7.4學習記錄(基礎概念和基礎操作)

若你之前從未了解過ES&#xff0c;本文將由淺入深的一步步帶你理解ES&#xff0c;簡單使用ES。作者本人就是此狀態&#xff0c;通過學習和梳理&#xff0c;產出本文&#xff0c;已對ES有個全面的了解和想法&#xff0c;不僅將知識點梳理&#xff0c;也涉及到自己的理解&#xf…

行業追蹤,2023-08-09

自動復盤 2023-08-09 凡所有相&#xff0c;皆是虛妄。若見諸相非相&#xff0c;即見如來。 k 線圖是最好的老師&#xff0c;每天持續發布板塊的rps排名&#xff0c;追蹤板塊&#xff0c;板塊來開倉&#xff0c;板塊去清倉&#xff0c;丟棄自以為是的想法&#xff0c;板塊去留讓…