SQL偏移類窗口函數(shù) LAG、LEAD的用法小結(jié)
在 SQL 中,偏移類窗口函數(shù) LAG() 和 LEAD() 用于訪問當(dāng)前行的前幾行或后幾行的值。
1.LAG()函數(shù)

LAG() 函數(shù)返回當(dāng)前行的前幾行的數(shù)據(jù)。
LAG(Expression, OffSetValue, DefaultVar) OVER (
PARTITION BY [Expression]
ORDER BY Expression [ASC|DESC]
);
- expression??: 你想要獲取的列或表達(dá)式。
- offset?? (可選): 你希望向前偏移的行數(shù)。默認(rèn)是 1,表示獲取前一行的數(shù)據(jù)。
- default_value?? (可選): 如果當(dāng)前行之前沒有足夠的行,返回的默認(rèn)值。默認(rèn)是
NULL,如果沒有設(shè)置default_value,且當(dāng)前行是窗口的第一行或沒有前幾行數(shù)據(jù)時(shí),返回NULL。 - PARTITION BY?? (可選): 按某列分組計(jì)算窗口函數(shù),類似于
GROUP BY。如果沒有此項(xiàng),整個(gè)數(shù)據(jù)集視為一個(gè)窗口。 - ORDER BY??: 按照某列排序,確定偏移的順序。
Demo????????????:
表格數(shù)據(jù)??
sales 表,表結(jié)構(gòu)和數(shù)據(jù)如下:
| id | month | revenue |
|---|---|---|
| 1 | Jan | 100 |
| 2 | Feb | 150 |
| 3 | Mar | 200 |
Demo????:基礎(chǔ)用法
使用 LAG() 函數(shù)來獲取按月排序后的“revenue”列的前一行的值。
SELECT id, month, revenue, LAG(revenue) OVER (ORDER BY month) AS prev_revenue FROM sales;
| id | month | revenue | prev_revenue |
|---|---|---|---|
| 1 | Jan | 100 | NULL |
| 2 | Feb | 150 | 100 |
| 3 | Mar | 200 | 150 |
Tips????:
- 第一行沒有前一行,所以
prev_revenue為NULL。 - 第二行的
prev_revenue為第一行的revenue值(100)。 - 第三行的
prev_revenue為第二行的revenue值(150)。
Demo????:帶偏移量的LAG()函數(shù)
使用 LAG() 函數(shù),并指定偏移量為 2,獲取兩行之前的“revenue”值。
SELECT id, month, revenue, LAG(revenue, 2) OVER (ORDER BY month) AS prev_revenue FROM sales;
| id | month | revenue | prev_revenue |
|---|---|---|---|
| 1 | Jan | 100 | NULL |
| 2 | Feb | 150 | NULL |
| 3 | Mar | 200 | 100 |
Tips????:
- 第一行和第二行都沒有兩行之前的記錄,所以
prev_revenue為NULL。 - 第三行的
prev_revenue為第一行的revenue值(100)。
Demo????:帶默認(rèn)值的LAG()函數(shù)
使用 LAG() 函數(shù),并指定默認(rèn)值為 0,當(dāng)無法獲取前一行的值時(shí)返回默認(rèn)值。
SELECT id, month, revenue, LAG(revenue, 1, 0) OVER (ORDER BY month) AS prev_revenue FROM sales;
| id | month | revenue | prev_revenue |
|---|---|---|---|
| 1 | Jan | 100 | 0 |
| 2 | Feb | 150 | 100 |
| 3 | Mar | 200 | 150 |
Tips????:
- 使用 LAG(revenue, 1, 0) 來獲取前一行的“revenue”值,如果沒有前一行則返回默認(rèn)值 0。
- 第一行沒有前一行,所以 prev_revenue 為 0。
- 第二行的 prev_revenue 為第一行的 revenue 值(100)。
- 第三行的 prev_revenue 為第二行的 revenue 值(150)。
Demo????:LAG()函數(shù),比較每一天的銷售額與前一天的銷售額的差異。
SELECT
sale_date,
amount,
LAG(amount, 1, 0) OVER (ORDER BY sale_date) AS previous_day_amount,
amount - LAG(amount, 1, 0) OVER (ORDER BY sale_date) AS difference
FROM sales;
LAG(amount, 1, 0):這行的LAG函數(shù)表示獲取前一天(前一行)的amount列的值,如果前一天沒有數(shù)據(jù)(例如第一行),則返回0。- 通過
ORDER BY sale_date,確保按日期順序排列數(shù)據(jù)。
| sale_date | amount | previous_day_amount | difference |
|---|---|---|---|
| 2025-01-01 | 100 | 0 | 100 |
| 2025-01-02 | 150 | 100 | 50 |
| 2025-01-03 | 200 | 150 | 50 |
| 2025-01-04 | 180 | 200 | -20 |
2.LEAD()函數(shù)

LEAD() 函數(shù)與 LAG() 類似,但它返回的是當(dāng)前行的后幾行的數(shù)據(jù)。
LEAD(Expression, OffSetValue, DefaultVar) OVER (
PARTITION BY [Expression]
ORDER BY Expression [ASC|DESC]
);
- expression??: 你想要獲取的列或表達(dá)式。
- offset?? (可選): 你希望向前偏移的行數(shù)。默認(rèn)是 1,表示獲取前一行的數(shù)據(jù)。
- default_value?? (可選): 如果當(dāng)前行之前沒有足夠的行,返回的默認(rèn)值。默認(rèn)是
NULL,如果沒有設(shè)置default_value,且當(dāng)前行是窗口的第一行或沒有前幾行數(shù)據(jù)時(shí),返回NULL。 - PARTITION BY?? (可選): 按某列分組計(jì)算窗口函數(shù),類似于
GROUP BY。如果沒有此項(xiàng),整個(gè)數(shù)據(jù)集視為一個(gè)窗口。 - ORDER BY??: 按照某列排序,確定偏移的順序。
Demo????:基礎(chǔ)用法
使用 LEAD() 函數(shù)來獲取按月排序后的“revenue”列的后一行的值。
SELECT id, month, revenue, LEAD(revenue) OVER (ORDER BY month) AS next_revenue FROM sales;
| id | month | revenue | next_revenue |
|---|---|---|---|
| 1 | Jan | 100 | 150 |
| 2 | Feb | 150 | 200 |
| 3 | Mar | 200 | NULL |
Tips????:
- 第一行的
next_revenue為第二行的revenue值(150)。 - 第二行的
next_revenue為第三行的revenue值(200)。 - 第三行沒有后續(xù)行,所以 next_revenue 為 NULL。
Demo????:帶偏移量的LEAD()函數(shù)
使用 LEAD() 函數(shù),并指定偏移量為 2,獲取兩行之后的“revenue”值。
SELECT id, month, revenue, LEAD(revenue, 2) OVER (ORDER BY month) AS next_revenue FROM sales;
| id | month | revenue | next_revenue |
|---|---|---|---|
| 1 | Jan | 100 | 200 |
| 2 | Feb | 150 | NULL |
| 3 | Mar | 200 | NULL |
Tips????:
- 使用 LEAD(revenue, 2) 來獲取兩行之后的“revenue”值。
- 第一行的 next_revenue 為第三行的 revenue 值(200)。
- 第二行和第三行都沒有兩行之后的記錄,所以 next_revenue 為 NULL。
Demo????:帶默認(rèn)值的LEAD()函數(shù)
使用 LEAD() 函數(shù),并指定默認(rèn)值為 0,當(dāng)無法獲取后一行的值時(shí)返回默認(rèn)值。
SELECT id, month, revenue, LEAD(revenue, 1, 0) OVER (ORDER BY month) AS next_revenue FROM sales;
| id | month | revenue | next_revenue |
|---|---|---|---|
| 1 | Jan | 100 | 150 |
| 2 | Feb | 150 | 200 |
| 3 | Mar | 200 | 0 |
Tips????:
- 使用 LEAD(revenue, 1, 0) 來獲取后一行的“revenue”值,如果沒有后一行則返回默認(rèn)值 0。
- 第一行的 next_revenue 為第二行的 revenue 值(150)。
- 第二行的 next_revenue 為第三行的 revenue 值(200)。
- 第三行沒有后一行,所以 next_revenue 為 0。
Demo????:LEAD()函數(shù),比較每一天的銷售額與下一天的銷售額的差異。
SELECT
sale_date,
amount,
LEAD(amount, 1, 0) OVER (ORDER BY sale_date) AS next_day_amount,
LEAD(amount, 1, 0) OVER (ORDER BY sale_date) - amount AS difference
FROM sales;
LEAD(amount, 1, 0):這行的LEAD函數(shù)表示獲取下一天(下一行)的amount列的值。如果下一天沒有數(shù)據(jù)(例如最后一行),則返回0。- 通過
ORDER BY sale_date,確保按日期順序排列數(shù)據(jù)。
| sale_date | amount | next_day_amount | difference |
|---|---|---|---|
| 2025-01-01 | 100 | 150 | 50 |
| 2025-01-02 | 150 | 200 | 50 |
| 2025-01-03 | 200 | 180 | -20 |
| 2025-01-04 | 180 | 0 | -180 |
最后再來一個(gè)小練習(xí)(lc會(huì)員題):查找電影院所有連續(xù)可用的座位。


WITH t1 AS (
SELECT
seat_id, -- 選擇座位ID
free, -- 選擇當(dāng)前座位的空閑狀態(tài)
lag(free, 1, 999) OVER() AS pre, -- 獲取當(dāng)前座位前一個(gè)座位的空閑狀態(tài),默認(rèn)值為 999
lead(free, 1, 999) OVER() AS next -- 獲取當(dāng)前座位后一個(gè)座位的空閑狀態(tài),默認(rèn)值為 999
FROM Cinema -- 從 Cinema 表中選擇數(shù)據(jù)
)
SELECT
seat_id -- 返回座位ID
FROM t1 -- 從 t1 子查詢中選擇數(shù)據(jù)
WHERE
free = 1 -- 當(dāng)前座位為空閑
AND (pre = 1 OR next = 1) -- 前一個(gè)座位或后一個(gè)座位為空閑
ORDER BY seat_id; -- 按座位ID升序排序
思路:
lag(free, 1, 999) 和 lead(free, 1, 999):
lag(free, 1, 999)用于獲取當(dāng)前座位前一個(gè)座位的free值(默認(rèn)為 999,表示沒有前一個(gè)座位)。lead(free, 1, 999)用于獲取當(dāng)前座位后一個(gè)座位的free值(默認(rèn)為 999,表示沒有后一個(gè)座位)。
free = 1 和 (pre = 1 OR next = 1):
- 只選擇當(dāng)前座位是空閑的 (
free = 1)。 - 選擇那些前一個(gè)或后一個(gè)座位也是空閑的 (
pre = 1 OR next = 1),表示這些座位是連續(xù)空閑的。
- 只選擇當(dāng)前座位是空閑的 (
ORDER BY seat_id:
- 確保最終返回的結(jié)果按座位 ID 升序排序。
| seat_id | free |
|---|---|
| 1 | 1 |
| 2 | 0 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
通過執(zhí)行查詢,得到的 t1 子查詢結(jié)果:
| seat_id | free | pre | next |
|---|---|---|---|
| 1 | 1 | 999 | 0 |
| 2 | 0 | 1 | 1 |
| 3 | 1 | 0 | 1 |
| 4 | 1 | 1 | 1 |
| 5 | 1 | 1 | 999 |
從 t1 中篩選出滿足 free = 1 且 (pre = 1 OR next = 1) 的行,得到的結(jié)果:
| seat_id |
|---|
| 3 |
| 4 |
| 5 |
到此這篇關(guān)于SQL偏移類窗口函數(shù) LAG、LEAD的用法小結(jié)的文章就介紹到這了,更多相關(guān)SQL偏移類窗口函數(shù) 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
CMD命令操作MSSQL2005數(shù)據(jù)庫(命令整理)
創(chuàng)建數(shù)據(jù)庫、創(chuàng)建用戶、修改數(shù)據(jù)的所有者、設(shè)置READ_COMMITTED_SNAPSHOT以及備份、日志扥等等,感興趣的朋友可以參考下2013-05-05
SQL Server數(shù)據(jù)庫的死鎖詳細(xì)說明
死鎖是指在一組進(jìn)程中的各個(gè)進(jìn)程均占有不會(huì)釋放的資源,但因互相申請被其他進(jìn)程所站用不會(huì)釋放的資源而處于的一種永久等待,下面這篇文章主要給大家介紹了關(guān)于SQL Server死鎖的相關(guān)資料,需要的朋友可以參考下2024-07-07
sqlserver 字段值拼接的實(shí)現(xiàn)示例
拼接字段可以通過多種方法實(shí)現(xiàn),本文主要介紹了sqlserver字段值拼接的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07
SQLSERVER 語句交錯(cuò)引發(fā)的死鎖問題案例詳解
這篇文章主要介紹了SQLSERVER 語句交錯(cuò)引發(fā)的死鎖研究,要解決死鎖問題,個(gè)人感覺需要非常熟知各種隔離級(jí)別,尤其是 可提交讀 模式下的 CURD 加解鎖過程,這一篇我們就來好好聊一聊2023-02-02

