SQL偏移类窗口函数 LAG、LEAD的用法小结
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">1.LAG()函数</a></li><ul class="second_class_ul"><li><a href="#_lab2_0_0">Demo🍕🍕🍕🍕🍕🍕:</a></li><li><a href="#_lab2_0_1">Demo🍕🍕:基础用法</a></li><li><a href="#_lab2_0_2">Demo🍕🍕:带偏移量的LAG()函数</a></li><li><a href="#_lab2_0_3">Demo🍕🍕:带默认值的LAG()函数</a></li><li><a href="#_lab2_0_4">Demo🍕🍕:LAG()函数,比较每一天的销售额与前一天的销售额的差异。</a></li></ul><li><a href="#_label1">2.LEAD()函数</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_5">Demo🍕🍕:基础用法</a></li><li><a href="#_lab2_1_6">Demo🍕🍕:带偏移量的LEAD()函数</a></li><li><a href="#_lab2_1_7">Demo🍕🍕:带默认值的LEAD()函数</a></li><li><a href="#_lab2_1_8">Demo🍕🍕:LEAD()函数,比较每一天的销售额与下一天的销售额的差异。</a></li></ul></ul></div><p>在 SQL 中,偏移类窗口函数 LAG() 和 LEAD() 用于访问当前行的前几行或后几行的值。</p><p class="maodian"><a name="_label0"></a></p><h2>1.LAG()函数</h2>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202508/2025081310330665.png" /></p>
<p><code>LAG()</code> 函数返回当前行的前几行的数据。</p>
<div class="jb51code"><pre class="brush:sql;">LAG(Expression, OffSetValue, DefaultVar) OVER (
PARTITION BY
ORDER BY Expression
);
</pre></div>
<ul><li><strong>expression🍔</strong>: 你想要获取的列或表达式。</li><li><strong>offset🍟</strong> (可选): 你希望向前偏移的行数。默认是 1,表示获取前一行的数据。</li><li><strong>default_value🍿</strong> (可选): 如果当前行之前没有足够的行,返回的默认值。默认是 <code>NULL</code>,如果没有设置 <code>default_value</code>,且当前行是窗口的第一行或没有前几行数据时,返回 <code>NULL</code>。</li><li><strong>PARTITION BY🥓</strong> (可选): 按某列分组计算窗口函数,类似于 <code>GROUP BY</code>。如果没有此项,整个数据集视为一个窗口。</li><li><strong>ORDER BY🥩</strong>: 按照某列排序,确定偏移的顺序。</li></ul>
<p class="maodian"><a name="_lab2_0_0"></a></p><h3>Demo🍕🍕🍕🍕🍕🍕:</h3>
<p>表格数据😎</p>
<p><code>sales</code> 表,表结构和数据如下:</p>
<table><thead><tr><th>id</th><th>month</th><th>revenue</th></tr></thead><tbody><tr><td>1</td><td>Jan</td><td>100</td></tr><tr><td>2</td><td>Feb</td><td>150</td></tr><tr><td>3</td><td>Mar</td><td>200</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_0_1"></a></p><p class="maodian"><a name="_lab2_1_5"></a></p><h3>Demo🍕🍕:基础用法</h3>
<p>使用 <code>LAG()</code> 函数来<strong>获取按月排序后的“revenue”列的前一行的值</strong>。</p>
<div class="jb51code"><pre class="brush:sql;">SELECTid,
month,
revenue,
LAG(revenue) OVER (ORDER BY month) AS prev_revenue
FROM sales;
</pre></div>
<table><thead><tr><th>id</th><th>month</th><th>revenue</th><th>prev_revenue</th></tr></thead><tbody><tr><td>1</td><td>Jan</td><td>100</td><td>NULL</td></tr><tr><td>2</td><td>Feb</td><td>150</td><td>100</td></tr><tr><td>3</td><td>Mar</td><td>200</td><td>150</td></tr></tbody></table>
<p><strong>Tips🍬🍬:</strong></p>
<ul><li>第一行没有前一行,所以 <code>prev_revenue</code> 为 <code>NULL</code>。</li><li>第二行的 <code>prev_revenue</code> 为第一行的 <code>revenue</code> 值(100)。</li><li>第三行的 <code>prev_revenue</code> 为第二行的 <code>revenue</code> 值(150)。</li></ul>
<p class="maodian"><a name="_lab2_0_2"></a></p><h3>Demo🍕🍕:带偏移量的LAG()函数</h3>
<p>使用 <code>LAG()</code> 函数,并<strong>指定偏移量为 2,获取两行之前的“revenue”值。</strong></p>
<div class="jb51code"><pre class="brush:sql;">SELECTid,
month,
revenue,
LAG(revenue, 2) OVER (ORDER BY month) AS prev_revenue
FROM sales;
</pre></div>
<table><thead><tr><th>id</th><th>month</th><th>revenue</th><th>prev_revenue</th></tr></thead><tbody><tr><td>1</td><td>Jan</td><td>100</td><td>NULL</td></tr><tr><td>2</td><td>Feb</td><td>150</td><td>NULL</td></tr><tr><td>3</td><td>Mar</td><td>200</td><td>100</td></tr></tbody></table>
<p><strong>Tips🍬🍬:</strong></p>
<ul><li>第一行和第二行都没有两行之前的记录,所以 <code>prev_revenue</code> 为 <code>NULL</code>。</li><li>第三行的 <code>prev_revenue</code> 为第一行的 <code>revenue</code> 值(100)。</li></ul>
<p class="maodian"><a name="_lab2_0_3"></a></p><h3>Demo🍕🍕:带默认值的LAG()函数</h3>
<p>使用 <code>LAG()</code> 函数,并<strong>指定默认值为 0,当无法获取前一行的值时返回默认值。</strong></p>
<div class="jb51code"><pre class="brush:sql;">SELECTid,
month,
revenue,
LAG(revenue, 1, 0) OVER (ORDER BY month) AS prev_revenue
FROM sales;
</pre></div>
<table><thead><tr><th>id</th><th>month</th><th>revenue</th><th>prev_revenue</th></tr></thead><tbody><tr><td>1</td><td>Jan</td><td>100</td><td>0</td></tr><tr><td>2</td><td>Feb</td><td>150</td><td>100</td></tr><tr><td>3</td><td>Mar</td><td>200</td><td>150</td></tr></tbody></table>
<p>Tips🍬🍬:</p>
<ul><li>使用 LAG(revenue, 1, 0) 来获取前一行的“revenue”值,如果没有前一行则返回默认值 0。</li><li>第一行没有前一行,所以 prev_revenue 为 0。</li><li>第二行的 prev_revenue 为第一行的 revenue 值(100)。</li><li>第三行的 prev_revenue 为第二行的 revenue 值(150)。</li></ul>
<p class="maodian"><a name="_lab2_0_4"></a></p><h3>Demo🍕🍕:LAG()函数,比较每一天的销售额与前一天的销售额的差异。</h3>
<div class="jb51code"><pre class="brush:sql;">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;
</pre></div>
<ul><li><code>LAG(amount, 1, 0)</code>:这行的 <code>LAG</code> 函数表示获取前一天(前一行)的 <code>amount</code> 列的值,如果前一天没有数据(例如第一行),则返回 <code>0</code>。</li><li>通过 <code>ORDER BY sale_date</code>,确保按日期顺序排列数据。</li></ul>
<table><thead><tr><th>sale_date</th><th>amount</th><th>previous_day_amount</th><th>difference</th></tr></thead><tbody><tr><td>2025-01-01</td><td>100</td><td>0</td><td>100</td></tr><tr><td>2025-01-02</td><td>150</td><td>100</td><td>50</td></tr><tr><td>2025-01-03</td><td>200</td><td>150</td><td>50</td></tr><tr><td>2025-01-04</td><td>180</td><td>200</td><td>-20</td></tr></tbody></table>
<p class="maodian"><a name="_label1"></a></p><h2>2.LEAD()函数</h2>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202508/2025081310330690.png" /></p>
<p><code>LEAD()</code> 函数与 <code>LAG()</code> 类似,但它返回的是当前行的后几行的数据。</p>
<div class="jb51code"><pre class="brush:sql;">LEAD(Expression, OffSetValue, DefaultVar) OVER (
PARTITION BY
ORDER BY Expression
);
</pre></div>
<ul><li><strong>expression🍔</strong>: 你想要获取的列或表达式。</li><li><strong>offset🍟</strong> (可选): 你希望向前偏移的行数。默认是 1,表示获取前一行的数据。</li><li><strong>default_value🍿</strong> (可选): 如果当前行之前没有足够的行,返回的默认值。默认是 <code>NULL</code>,如果没有设置 <code>default_value</code>,且当前行是窗口的第一行或没有前几行数据时,返回 <code>NULL</code>。</li><li><strong>PARTITION BY🥓</strong> (可选): 按某列分组计算窗口函数,类似于 <code>GROUP BY</code>。如果没有此项,整个数据集视为一个窗口。</li><li><strong>ORDER BY🥩</strong>: 按照某列排序,确定偏移的顺序。</li></ul>
<h3>Demo🍕🍕:基础用法</h3>
<p>使用 <code>LEAD()</code> 函数来<strong>获取按月排序后的“revenue”列的后一行的值。</strong></p>
<div class="jb51code"><pre class="brush:sql;">SELECTid,
month,
revenue,
LEAD(revenue) OVER (ORDER BY month) AS next_revenue
FROM sales;
</pre></div>
<table><thead><tr><th>id</th><th>month</th><th>revenue</th><th>next_revenue</th></tr></thead><tbody><tr><td>1</td><td>Jan</td><td>100</td><td>150</td></tr><tr><td>2</td><td>Feb</td><td>150</td><td>200</td></tr><tr><td>3</td><td>Mar</td><td>200</td><td>NULL</td></tr></tbody></table>
<p><strong>Tips🍬🍬:</strong></p>
<ul><li>第一行的 <code>next_revenue</code> 为第二行的 <code>revenue</code> 值(150)。</li><li>第二行的 <code>next_revenue</code> 为第三行的 <code>revenue</code> 值(200)。</li><li>第三行没有后续行,所以 next_revenue 为 NULL。</li></ul>
<p class="maodian"><a name="_lab2_1_6"></a></p><h3>Demo🍕🍕:带偏移量的LEAD()函数</h3>
<p>使用 <code>LEAD()</code> 函数,并<strong>指定偏移量为 2,获取两行之后的“revenue”值。</strong></p>
<div class="jb51code"><pre class="brush:sql;">SELECTid,
month,
revenue,
LEAD(revenue, 2) OVER (ORDER BY month) AS next_revenue
FROM sales;
</pre></div>
<table><thead><tr><th>id</th><th>month</th><th>revenue</th><th>next_revenue</th></tr></thead><tbody><tr><td>1</td><td>Jan</td><td>100</td><td>200</td></tr><tr><td>2</td><td>Feb</td><td>150</td><td>NULL</td></tr><tr><td>3</td><td>Mar</td><td>200</td><td>NULL</td></tr></tbody></table>
<p>Tips🍬🍬:</p>
<ul><li>使用 LEAD(revenue, 2) 来获取两行之后的“revenue”值。</li><li>第一行的 next_revenue 为第三行的 revenue 值(200)。</li><li>第二行和第三行都没有两行之后的记录,所以 next_revenue 为 NULL。</li></ul>
<p class="maodian"><a name="_lab2_1_7"></a></p><h3>Demo🍕🍕:带默认值的LEAD()函数</h3>
<p>使用 <code>LEAD()</code> 函数,并指定默认值为 0,当无法获取后一行的值时返回默认值。</p>
<div class="jb51code"><pre class="brush:sql;">SELECT id, month, revenue, LEAD(revenue, 1, 0) OVER (ORDER BY month) AS next_revenue
FROM sales;
</pre></div>
<table><thead><tr><th>id</th><th>month</th><th>revenue</th><th>next_revenue</th></tr></thead><tbody><tr><td>1</td><td>Jan</td><td>100</td><td>150</td></tr><tr><td>2</td><td>Feb</td><td>150</td><td>200</td></tr><tr><td>3</td><td>Mar</td><td>200</td><td>0</td></tr></tbody></table>
<p><strong>Tips🍬🍬:</strong></p>
<ul><li>使用 LEAD(revenue, 1, 0) 来获取后一行的“revenue”值,如果没有后一行则返回默认值 0。</li><li>第一行的 next_revenue 为第二行的 revenue 值(150)。</li><li>第二行的 next_revenue 为第三行的 revenue 值(200)。</li><li>第三行没有后一行,所以 next_revenue 为 0。</li></ul>
<p class="maodian"><a name="_lab2_1_8"></a></p><h3>Demo🍕🍕:LEAD()函数,比较每一天的销售额与下一天的销售额的差异。</h3>
<div class="jb51code"><pre class="brush:sql;">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;
</pre></div>
<ul><li><code>LEAD(amount, 1, 0)</code>:这行的 <code>LEAD</code> 函数表示获取下一天(下一行)的 <code>amount</code> 列的值。如果下一天没有数据(例如最后一行),则返回 <code>0</code>。</li><li>通过 <code>ORDER BY sale_date</code>,确保按日期顺序排列数据。</li></ul>
<table><thead><tr><th>sale_date</th><th>amount</th><th>next_day_amount</th><th>difference</th></tr></thead><tbody><tr><td>2025-01-01</td><td>100</td><td>150</td><td>50</td></tr><tr><td>2025-01-02</td><td>150</td><td>200</td><td>50</td></tr><tr><td>2025-01-03</td><td>200</td><td>180</td><td>-20</td></tr><tr><td>2025-01-04</td><td>180</td><td>0</td><td>-180</td></tr></tbody></table>
<p>最后再来一个小练习(lc会员题):<strong>查找电影院所有连续可用的座位。</strong></p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202508/2025081310330618.png" /></p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202508/2025081310330611.png" /></p>
<div class="jb51code"><pre class="brush:sql;">WITH t1 AS (
SELECT
seat_id,-- 选择座位ID
free,-- 选择当前座位的空闲状态
lag(free, 1, 999) OVER() AS pre,-- 获取当前座位前一个座位的空闲状态,默认值为 999
lead(free, 1, 999) OVER() AS next-- 获取当前座位后一个座位的空闲状态,默认值为 999
FROM Cinema-- 从 Cinema 表中选择数据
)
SELECT
seat_id-- 返回座位ID
FROM t1-- 从 t1 子查询中选择数据
WHERE
free = 1-- 当前座位为空闲
AND (pre = 1 OR next = 1)-- 前一个座位或后一个座位为空闲
ORDER BY seat_id;-- 按座位ID升序排序
</pre></div>
<p>思路:</p>
<ol><li><p>lag(free, 1, 999) 和 lead(free, 1, 999):</p>
<ul><li><code>lag(free, 1, 999)</code> 用于获取当前座位前一个座位的 <code>free</code> 值(默认为 999,表示没有前一个座位)。</li><li><code>lead(free, 1, 999)</code> 用于获取当前座位后一个座位的 <code>free</code> 值(默认为 999,表示没有后一个座位)。</li></ul></li><li><p>free = 1 和 (pre = 1 OR next = 1):</p>
<ul><li>只选择当前座位是空闲的 (<code>free = 1</code>)。</li><li>选择那些前一个或后一个座位也是空闲的 (<code>pre = 1 OR next = 1</code>),表示这些座位是连续空闲的。</li></ul></li><li><p>ORDER BY seat_id:</p>
<ul><li>确保最终返回的结果按座位 ID 升序排序。</li></ul></li></ol>
<table><thead><tr><th>seat_id</th><th>free</th></tr></thead><tbody><tr><td>1</td><td>1</td></tr><tr><td>2</td><td>0</td></tr><tr><td>3</td><td>1</td></tr><tr><td>4</td><td>1</td></tr><tr><td>5</td><td>1</td></tr></tbody></table>
<p>通过执行查询,得到的 t1 子查询结果:</p>
<table><thead><tr><th>seat_id</th><th>free</th><th>pre</th><th>next</th></tr></thead><tbody><tr><td>1</td><td>1</td><td>999</td><td>0</td></tr><tr><td>2</td><td>0</td><td>1</td><td>1</td></tr><tr><td>3</td><td>1</td><td>0</td><td>1</td></tr><tr><td>4</td><td>1</td><td>1</td><td>1</td></tr><tr><td>5</td><td>1</td><td>1</td><td>999</td></tr></tbody></table>
<p>从 t1 中筛选出满足 free = 1 且 (pre = 1 OR next = 1) 的行,得到的结果:</p>
<table><thead><tr><th>seat_id</th></tr></thead><tbody><tr><td>3</td></tr><tr><td>4</td></tr><tr><td>5</td></tr></tbody></table>
<p> 到此这篇关于SQL偏移类窗口函数 LAG、LEAD的用法小结的文章就介绍到这了,更多相关SQL偏移类窗口函数 内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
頁:
[1]