MySQL 窗口函數溫故知新

本文用于復習數據庫窗口函數,希望能夠溫故知新,也希望讀到這篇文章的有所收獲。

本文以:MySQL為例

參考文檔: https://www.begtut.com/mysql/mysql-window-functions.html

使用的樣例數據:https://www.begtut.com/mysql/mysql-sample-database.html


1. 概括的說明
函數說明
ROW_NUMBER為其分區中的每一行分配一個序號。
RANK根據ORDER BY的字段,為每一行分配一個排名。 值相同的行分配相同的排名, 下一行排名不聯系,會累加值相同的行數。
DENSE_RANK與RANK()函數類似,只是當出現值相同的行時,排名是連續的,不是累加行數。
PERCENT_RANK計算分區或結果集中行的百分位數。計算公式為:(當前從小到大排序序號-1 ) / (總序號數-1) 【就是(rank - 1) / (total_rows - 1) 】
FIRST_VALUE返回指定表達式相對于窗口框架中第一行的值。
LAST_VALUE返回指定表達式相對于窗口框架中最后一行的值。
LEAD返回分區中當前行之后的第N行的值。 如果不存在后續行,則返回NULL。
LAG返回分區中當前行之前的第N行的值。 如果不存在前一行,則返回NULL。
NTILE將每個窗口分區的行分配到指定數量的已排名組中。 (把結果分成n個組)
CUME_DIST計算一組值中值的累積分布。
NTH_VALUE返回窗口框架第N行的參數

2.??注意 rows between 的用法

  • rows between …… and ……
  • unbounded preceding 前面所有行 、n preceding ?前面n行
  • unbounded following 后面所有行 、n following ?后面n行
  • current row 當前行
SELECTorderNumber,productCode,quantityOrdered,SUM(quantityOrdered) OVER(PARTITION BY orderNumber ORDER BY productcode) AS quantity_amount,-- 前面一行和當前行的值累加SUM(quantityOrdered) OVER(PARTITION BY orderNumber ORDER BY productcode ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) quantity_add
FROMmysqldemo.orderdetails
WHEREorderNumber = 10103;
3. 注意 range between的用法

range between 按照排序字段的值限制窗口大小。主要將order by后面字段排序后,然后根據排序字段的值,框定一個范圍,再對這個范圍內的行進行匯總。樣例如下:
?

sum(num) over(order by dateTime range between interval 6 day preceding and current row) 
-- 必須是date類型的數據,這一天和前面6天(如果存在)的數據sum(close) over(order by salary range between 100 preceding and 200 following) 
--通過 salary 字段差值來進行選擇。如當前行的 salary 字段值是 200,那么這個窗口大小的定義就會選擇分區中 salary 字段值落在 100 至 400 區間的記錄(行),再求這些行的sum(close).

需要注意的點:

  • rows表示行,就是前n行,后n行。
  • range表示的是具體的值,比這個值小n的行,比這個值大n的行。是以當前值為錨點進行計算。
  • 同時 range 也可以使用 between unbounded preceding and unbounded following,效果和等同于rows一樣,取上下限所有行,不指定值。
  • range 窗口僅對數字和日期起作用,因為需要計算值的范圍。
  • 在range 的開窗中,order by 中只能有一列;rows 的開窗的order by 可以有多列。
SELECTorderNumber,productCode,quantityOrdered,SUM(quantityOrdered) OVER(PARTITION BY orderNumber ORDER BY quantityOrdered) AS quantity_amount,-- quantityOrdered 的值-1 和 +2的值區間范圍內的行的累加SUM(quantityOrdered) OVER(PARTITION BY orderNumber ORDER BY quantityOrdered RANGE BETWEEN 1 PRECEDING AND 2 following) quantity_add
FROMmysqldemo.orderdetails;

4.?ROW_NUMBER & RANK & DENSE_RANK

比較常用,都很熟悉,基本用法就不用贅述了。

SELECTorderNumber,productCode,quantityOrdered,ROW_NUMBER() OVER (ORDER BY quantityOrdered) AS nb,RANK() OVER (PARTITION BY orderNumber ORDER BY quantityOrdered) AS rank_quantity,DENSE_RANK() OVER (PARTITION BY orderNumber ORDER BY quantityOrdered) AS dense_rank_quantity
FROMmysqldemo.orderdetails
WHEREorderNumber = 10103;

rank和dense_rank 的區別,就是遇到有多行值相同時,那么下一行的序號,rank會加上重復的行數,那么rank對應的序號就不連續了;dense_rank 不會加上重復的行數,保持序號任然是連續的。

需要注意的點:

  • ROW_NUMBER 不加partition的時候,對所有行加序號,加partition之后分組加序號。
  • RANK 注意不加order by的時候,不排序,全是1,即使加partition也沒用;一定要加order by才會排序。
  • SUM 用法和 ROW_NUMBER 相同,匯總和分組匯總。
SELECT *, ROW_NUMBER() OVER () row_num0,ROW_NUMBER() OVER (PARTITION BY productline) row_num1,RANK() OVER() AS Rank00,RANK() OVER(PARTITION BY productline) AS Rank01,RANK() OVER(PARTITION BY productline,order_year) AS Rank02,RANK() OVER(order by amount) AS Rank1,RANK() OVER(PARTITION BY productline order by amount) AS Rank2,SUM(amount) OVER(PARTITION BY productline,order_year ) AS amount0,SUM(amount) OVER(PARTITION BY productline ) AS amount1,SUM(amount) OVER() AS amount2
FROM (SELECT productline, year(orderDate) order_year, sum(quantityOrdered) as amountFROM ordersINNER JOIN orderdetails USING (orderNumber)INNER JOIN products USING (productCode)GROUP BY productline,order_year) T;

5.?PERCENT_RANK()

函數返回一個從0到1的數字。 計算公式為:(rank - 1) / (total_rows - 1)。

rank是當前行的等級,total_rows是要計算的行數。 公式的意思就是計算當前行的等級減1,除以分區或結果集中的總行數減1。

  • PERCENT_RANK()對于分區或結果集中的第一行,函數始終返回零。重復的列值將接收相同的PERCENT_RANK()值。
  • PERCENT_RANK()是一個順序敏感函數,因此,您應始終使用ORDER BY子句。
CREATE TABLE productLineSales -- 我們創建了一張表,后面還會重復用到它
SELECTproductLine,YEAR(orderDate) orderYear,SUM(quantityOrdered * priceEach) orderValue
FROM orderDetails
INNER JOIN orders USING (orderNumber)
INNER JOIN products USING (productCode)
GROUP BY productLine , YEAR(orderDate);?WITH t AS (SELECT productLine, SUM(orderValue) orderValueFROM productLineSalesGROUP BY productLine
)
SELECTproductLine,orderValue,ROUND(PERCENT_RANK() OVER (ORDER BY orderValue),2) percentile_rank
FROM t;?

在這個例子中: 首先,我們使用表達式按產品線匯總訂單值。 其次,我們用它PERCENT_RANK()來計算每種產品的訂單價值的百分等級。
以下是輸出中的一些分析:

  • 訂單價值Trains并不比任何其他產品線更好,后者用零表示。
  • Vintage Cars 表現優于50%的其他產品。
  • Classic Cars 表現優于任何其他產品系列,因此其百分比等級為1或100%

6. CUME_DIST

它表示值小于或等于當前行的值除以總行數。 公式為: ROW_NUMBER() / total_rows 。注意和 PERCENT_RANK 的區別。

  • CUME_DIST()函數的返回值大于零且小于或等于1。
  • 重復的列值接收相同的CUME_DIST()值。?

樣例:計算某產品的訂單訂貨量數量分布 (注意第7行開始有重復的值31,對應百分比也是相同的。表示數量小于等于31的一共10行,占總行數28的35.71%)
?

SELECT orderNumber, productCode, quantityOrdered, ROW_NUMBER() OVER(ORDER BY quantityordered) AS nb,CUME_DIST() OVER(ORDER BY quantityordered) AS pct,PERCENT_RANK() OVER(ORDER BY quantityordered) AS pct_rank
FROM mysqldemo.orderdetails
WHERE productcode = 'S18_2949';

7. FIRST_VALUE

樣例:獲取客戶首單訂單金額。

SELECT customernumber,amount,paymentDate,FIRST_VALUE (amount) OVER (PARTITION BY customernumber ORDER BY paymentDate) AS first_amount
FROM payments
ORDER BY customernumber;

8. Last_Value
樣例:獲取客戶最后一筆訂單金額。
注意:Last_Value 和 First_Value 不同, 他認為每一行,是當前行中的最后一行。注意對比下面兩個字段的不同。

SELECT customernumber, amount, paymentDate,last_value (amount) OVER (PARTITION BY customernumber ORDER BY paymentDate) AS last_amount,last_value (amount) OVER (PARTITION BY customernumber ORDER BY paymentDate RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_amount_umbounded
FROM payments
ORDER BY customernumber;


8. Lead和Lag

函數類似,是查詢某一字段的從當前行往后找到第N行的數據(Lead)和往前找到第N行的數據(Lag)。在找到某一行的偏移n行的數據非常有用。
lead/lag(expression, offffset, default) over(partion by ......order by ......)

  • expression 要取的是哪一個字段
  • offset 是從當前行前進(lead)/后退(lag)的行數。 必須是一個非負整數,為零則取當前行。
  • default 如果沒有后續行,則函數返回default。例如,如果offset是1,則lead的最后一行,lag的第一行的返回值為default。 未指定default_value,則返回 NULL 。

樣例: 查詢出上一個訂單,下一個訂單的時間?

SELECT?customerName,orderDate,LEAD(orderDate,1) OVER (PARTITION BY customerNumber ORDER BY orderDate ) nextOrderDate,LAG(orderDate,1) OVER (PARTITION BY customerNumber ORDER BY orderDate ) PreviousOrderDate
FROM orders
INNER JOIN customers USING (customerNumber);?


樣例:查詢出下單時間間隔最長的用戶。

SELECT customerName,?MAX(orderdate_interval) AS MAX_interval,?RANK() OVER(ORDER BY MAX(orderdate_interval) DESC) AS data_rank
FROM(SELECT?customerName,orderDate,LEAD(orderDate,1) OVER (PARTITION BY customerNumber ORDER BY orderDate ) nextOrderDate,datediff(LEAD(orderDate,1) OVER (PARTITION BY customerNumber ORDER BY orderDate), orderDate) orderdate_intervalFROM ordersINNER JOIN customers USING (customerNumber)) T1
WHERE nextOrderDate IS NOT NULL
GROUP BY customerName;?

9. NTILE 平均分組

樣例:將產品線按照年份,匯總訂單金額,并且劃分為三個組。
注意不能平均分配時,例如將9行數據分成4個組,他會把第1組分3個,剩余3個組每個組2個;

SELECTproductline,?orderYear,?orderValue,NTILE(3) OVER (PARTITION BY orderYear ORDER BY orderValue DESC) product_line_group
FROM?productlineSales;?


樣例: 查詢出2013支付金額排名前30%的所有用戶?

SELECT customerNumber, pay_amount, level 
FROM (SELECT customerNumber, SUM(amount) AS pay_amount,NTILE(10) OVER(ORDER BY SUM(amount) DESC) AS levelFROM mysqldemo.paymentsWHERE Year(paymentDate) = 2013GROUP BY customerNumber)a 
WHERE level in (1,2,3);


通過這種方法計算出來的百分比不準確,通過下面的SQL,會發現前3個組的人數超過了30%。

SELECT COUNT(customerNumber), level
FROM (SELECT customerNumber, SUM(amount) AS pay_amount,NTILE(10) OVER(ORDER BY SUM(amount) DESC) AS levelFROM mysqldemo.paymentsWHERE Year(paymentDate) = 2013GROUP BY customerNumber)a 
GROUP BY level;


使用用 CUME_DIST 效果更好。

SELECT customerNumber, pay_amount, level, pct
FROM (SELECT customerNumber, SUM(amount) AS pay_amount,NTILE(10) OVER(ORDER BY SUM(amount) DESC) AS level,CUME_DIST() over(order by SUM(amount) desc) as pctFROM mysqldemo.paymentsWHERE Year(paymentDate) = 2013GROUP BY customerNumber)a 

直接定位帶排序小于等于30%的即可。從結果可以看出,和NTILE不一樣,第三組的人沒有全部都取。?

10. NTH_VALUE

函數格式為:

NTH_VALUE(expression, N)
OVER (partition_clauseorder_clauseframe_clause)?

從有序行集中的第N行獲取值;如果第N行不存在,則函數返回NULL;N必須是正整數。
注意:From First(標準SQL 支持 From Last, MySQL只支持From First。如果要模擬效果From Last,則可以使用其中ORDER BY倒敘排列)
樣例:2015年每月購買金額第三的人

SELECT paymentmonth,customernumber, amount, 
NTH_VALUE(customernumber, 3) OVER(PARTITION BY paymentmonth ORDER BY amount DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS NTH
FROM (SELECT MONTH(paymentDate) AS paymentmonth, customernumber,  SUM(amount) amountFROM paymentsWHERE YEAR(paymentDate) = 2015GROUP BY customernumber, paymentmonth) T1

11. 測試:查詢出每年連續下單的客戶和連續的年份
方法1

使用 lag 取上一年的年份,計算差值是1的,就是這兩年是連續的;然后對customerName進行group by。

SELECT customerName, max(orderYear), min(previousYear), SUM(gap)+1
FROM (SELECT customerName,?orderYear,?lag(orderYear) over(partition by customerName order by orderYear) AS previousYear,orderYear - lag(orderYear) over(partition by customerName order by orderYear) ?gapFROM (SELECT?customerName,YEAR(orderDate) AS orderYearFROM ordersINNER JOIN customers USING (customerNumber)GROUP BY customerName, orderYear?) T1) T2
WHERE gap =1
GROUP BY customerName

方法2

用Year 減去row_number, 取得gap,gap相同的,就是年份連續的。

SELECT customerName, minYear, maxYear, max(nb)
FROM (SELECT customerName,gap,orderYear,?min(orderYear) OVER (partition by customerName,gap ORDER BY customerName,gap) minYear,?max(orderYear)OVER (partition by customerName,gap ORDER BY customerName,gap) maxYear,ROW_NUMBER() OVER (partition by customerName,gap ORDER BY customerName,gap) nbFROM(SELECT customerName, orderYear, orderYear-nbbycustomer as gapFROM (SELECT?customerName,YEAR(orderDate) AS orderYear,ROW_NUMBER() OVER (PARTITION BY customerName ORDER BY YEAR(orderDate)) nbbycustomerFROM ordersINNER JOIN customers USING (customerNumber)GROUP BY customerName,orderYear)T1) T2
) T3
WHERE minYear <> maxYear
GROUP BY customerName, minYear, maxYear;
12. 其它有趣的函數

使用rand() 獲取隨機10行數據。

select * from customers order by rand() limit 10;

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

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

相關文章

對象池模式-Object Pool Pattern

原文地址:https://jaune162.blog/design-pattern/object-pool-pattern/ 原文中可下載高清SVG矢量類圖 引言 對象池模式(Object Pool Pattern)是一種創建一組可重用對象的設計模式。它通過維護一個預分配的對象集合,避免了頻繁地創建和銷毀對象所帶來的性能開銷。在需要使用…

力扣_字符串11—實現前綴樹(字典樹、Trie樹)

題目 方法 對于每一個節點&#xff0c;初始化一個長度為26的數組&#xff0c;用來存儲對應字母子節點的地址對于每一個節點&#xff0c;初始化一個 b o o l bool bool 變量用來表示是否為葉子節點 代碼 class Trie { private:vector<Trie*> children vector<Trie…

LeetCode //C - 901. Online Stock Span

901. Online Stock Span Design an algorithm that collects daily price quotes for some stock and returns the span of that stock’s price for the current day. The span of the stock’s price in one day is the maximum number of consecutive days (starting from…

ESP8266智能家居(1)——開發環境的搭建

1.前期介紹 本次打算使用esp8266的開發板——NodeMCU&#xff0c;進行物聯網相關項目的學習。開發環境使用Arduino軟件。 NodeMCU實物圖為&#xff1a; 開發環境截圖為&#xff1a; 2.軟件下載 我使用的arduino版本為1.8.5&#xff0c;其安裝包如下&#xff1a; 【免費】ar…

vue3 #跨組件通信

//爺爺組件中 import { provide , ref } from vue const money ref (100) //定義數據 provide( money , money ) //提供數據給孫子組件 const changeMoney ( m:number ) > { //定義函數 if (money) { money.value money.value - m } } provide(&quo…

Python系列(19)—— 條件語句

一、條件語句的基本概念 條件語句&#xff0c;也稱為選擇語句&#xff0c;允許程序根據條件的結果來執行不同的代碼塊。Python中最常用的條件語句是if語句&#xff0c;其基本語法如下&#xff1a; if condition:# 當條件為真時執行的代碼塊如果條件為真&#xff08;即非零或非…

學習總結22

解題思路 簡單模擬。 代碼 #include <bits/stdc.h> using namespace std; long long g[2000000]; long long n; int main() {long long x,y,z,sum0,k0;scanf("%lld",&n);for(x1;x<n;x)scanf("%lld",&g[x]);for(x1;x<n;x){scanf(&qu…

GEE必須會教程—時間都去哪了(Date參數類型)

時間和空間是世界存在的兩種基本屬性&#xff0c;大部分的數據都有特有的通道存儲時間信息&#xff0c;用戶需要通過獲取數據存儲的信息&#xff0c;來判斷數據的可用性&#xff0c;以及數據在時間上發生的變化。在遙感上&#xff0c;空間數據集合中&#xff0c;時間信息顯得更…

django配置視圖并與模版進行數據交互

目錄 安裝django 創建一個django項目 項目結構 創建視圖層views.py 寫入視圖函數 創建對應視圖的路由 創建模版層 配置項目中的模版路徑 創建模版html文件 啟動項目 瀏覽器訪問結果 安裝django pip install django 創建一個django項目 這里最好用命令行完成&#xf…

SQL注入之DNSLog外帶注入

一、認識&#xff1a; 什么是dnslog呢&#xff1f; DNS就是域名解析服務&#xff0c;把一個域名轉換成對應的IP地址&#xff0c;轉換完成之后&#xff0c;DNS服務器就會有一個日志記錄本次轉換的時間、域名、域名對應的ip、請求方的一些信息&#xff0c;這個日志就叫DNSLog。…

漢諾塔問題—java詳解(附源碼)

來源及應用 相傳在古印度圣廟中&#xff0c;有一種被稱為漢諾塔(Hanoi)的游戲。該游戲是在一塊銅板裝置上&#xff0c;有三根桿(編號A、B、C)&#xff0c;在A桿自下而上、由大到小按順序放置64個金盤(如圖1)。游戲的目標&#xff1a;把A桿上的金盤全部移到C桿上&#xff0c;并仍…

【Nacos】構建云原生應用的動態服務發現、配置管理和服務管理平臺【企業級生產環境集群搭建應用】

基礎描述 一個更易于構建云原生應用的動態服務發現、配置管理和服務管理平臺Nacos 致力于幫助您發現、配置和管理微服務。Nacos 提供了一組簡單易用的特性集&#xff0c;幫助您快速實現動態服務發現、服務配置、服務元數據及流量管理。Nacos 幫助您更敏捷和容易地構建、交付和…

貓頭虎分享已解決Bug || Spring Error: Request method ‘POST‘ not supported

博主貓頭虎的技術世界 &#x1f31f; 歡迎來到貓頭虎的博客 — 探索技術的無限可能&#xff01; 專欄鏈接&#xff1a; &#x1f517; 精選專欄&#xff1a; 《面試題大全》 — 面試準備的寶典&#xff01;《IDEA開發秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鴻蒙》 …

海思3559 yolov5 wk模型部署筆記

文章目錄 安裝3559工具鏈編譯opencv編譯項目總結 安裝3559工具鏈 將3559工具鏈copy到虛擬機上&#xff0c;并解壓得到安裝包 解壓&#xff1a; tar -zxvf aarch64-himix100-linux.tgz解壓后會得到安裝包文件夾&#xff1a; 安裝工具鏈&#xff1a; sudo ./aarch64-himix100…

代碼隨想錄算法訓練營第17天—二叉樹06 | ● *654.最大二叉樹 ● 617.合并二叉樹 ● 700.二叉搜索樹中的搜索 ● *98.驗證二叉搜索樹

*654.最大二叉樹 題目鏈接/文章講解&#xff1a;https://programmercarl.com/0654.%E6%9C%80%E5%A4%A7%E4%BA%8C%E5%8F%89%E6%A0%91.html 視頻講解&#xff1a;https://www.bilibili.com/video/BV1MG411G7ox 考點 前序遍歷構建二叉樹 我的思路 參考了力扣題目里的提示遞歸三要…

【大數據面試題】008 談一談 Flink資源如何配置

【大數據面試題】008 談一談 Flink 資源如何配置 并行度 Parallelism 概念作用Slot 概念作用如何設置TaskManager 任務管理器Flink submit 腳本 一步一個腳印&#xff0c;一天一道面試題 該文章有較多引用文章 https://zhuanlan.zhihu.com/p/572170629?utm_id0 并行度 Paralle…

Unity2023.1.19沒有PBR Graph?

Unity2023.1.19沒有PBR Graph? 關于Unity2023.1.19沒有PBR graph的說法,我沒看見管方給出的答案,百度則提到了Unity2020版之后Shader Graph的“全新更新”,之前也沒太注意版本的區別,以后項目盡量都留心一下。 之前文章說過,孿生智慧項目推薦使用URP渲染管線,以上的截…

安裝sklearn遇到ImportError: dlopen: cannot load any more object with static TLS

1.看https://blog.csdn.net/Go_ahead_forever/article/details/133755918 知不能 pip install sklearn&#xff0c;而是 pip install scikit-learn2.網上說調換import的順序就能解決。 但是我不知道調換哪個&#xff0c;索性重新開了anaconda環境&#xff0c;一個個安裝缺什么…

Stable Diffusion 繪畫入門教程(webui)-ControlNet(線稿約束)

上篇文章介紹了openpose&#xff0c;本篇文章介紹下線稿約束&#xff0c;關于線稿約束有好幾個處理器都屬于此類型&#xff0c;但是有一些區別。 包含&#xff1a; 1、Canny(硬邊緣&#xff09;&#xff1a;識別線條比較多比較細&#xff0c;一般用于更大程度得還原照片 2、ML…

在docker中運行vins-fusion

文章目錄 VINS-fusion拉取鏡像創建容器在vscode中運行代碼運行效果VINS-fusion VINS-Fusion 是一個開源的實時多傳感器狀態估計庫,主要由香港科技大學的沈邵劼教授領導的研究團隊開發。它是 VINS-Mono(單目視覺慣性系統)的擴展,支持多種傳感器組合,如雙目、立體相機和IMU…