SQL窗口函数:如何在满足指定条件的行后终止计算?
问题描述
大家好!
我有一张表,此前已为每条采购记录添加了rang字段,数据如下:
| id | date | time | title | rang |
|---|---|---|---|---|
| 1 | 2023-03-03 | 2023-03-03 10:00 | A | 1 |
| 1 | 2023-03-03 | 2023-03-03 10:10 | B | 2 |
| 1 | 2023-03-03 | 2023-03-03 10:20 | BUY C | 3 |
| 1 | 2023-03-03 | 2023-03-03 10:20 | D | 4 |
| 1 | 2023-03-03 | 2023-03-03 10:30 | E | 5 |
| 1 | 2023-03-03 | 2023-03-03 10:40 | BUY F | 6 |
| 1 | 2023-03-03 | 2023-03-03 10:50 | G | 7 |
| 2 | 2023-03-03 | 2023-03-03 12:00 | A_1 | 1 |
| 2 | 2023-03-03 | 2023-03-03 12:20 | BUY B_1 | 2 |
| 2 | 2023-03-03 | 2023-03-03 12:20 | C_1 | 3 |
我希望在遇到title字段包含“BUY”的行后,让后续行重新开始窗口函数的计数,但尝试以下语句后未得到预期效果:
RANK() OVER (PARTITION BY id ORDER BY time ASC RESET WHEN title LIKE '%BUY%')
执行后所有数据均在首次出现“BUY”的行处终止计数,结果如下:
| id | date | time | title | rang |
|---|---|---|---|---|
| 1 | 2023-03-03 | 2023-03-03 10:00 | A | 1 |
| 1 | 2023-03-03 | 2023-03-03 10:10 | B | 2 |
| 1 | 2023-03-03 | 2023-03-03 10:20 | BUY C | 3 |
| 2 | 2023-03-03 | 2023-03-03 12:00 | A_1 | 1 |
| 2 | 2023-03-03 | 2023-03-03 12:20 | BUY B_1 | 2 |
解决方案
标准SQL中并没有RESET WHEN这类窗口函数语法,你可以通过构造分组标识实现需求:
实现代码
SELECT id, date, time, title, ROW_NUMBER() OVER ( PARTITION BY id, buy_group ORDER BY time ASC ) AS rang FROM ( SELECT *, SUM(CASE WHEN title LIKE '%BUY%' THEN 1 ELSE 0 END) OVER (PARTITION BY id ORDER BY time ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS buy_group FROM your_table ) t
逻辑说明
- 内层查询通过
SUM()窗口函数,为每个id分区内的行计算截至当前行的“BUY”累计数量,这个值作为新的分组标识buy_group——每遇到一个含“BUY”的行,分组标识就会+1。 - 外层查询基于
id和buy_group双重分区,用ROW_NUMBER()重新计算rang,这样每个“BUY”行之后的记录会进入新分组,重新开始计数。
预期结果
| id | date | time | title | rang |
|---|---|---|---|---|
| 1 | 2023-03-03 | 2023-03-03 10:00 | A | 1 |
| 1 | 2023-03-03 | 2023-03-03 10:10 | B | 2 |
| 1 | 2023-03-03 | 2023-03-03 10:20 | BUY C | 3 |
| 1 | 2023-03-03 | 2023-03-03 10:20 | D | 1 |
| 1 | 2023-03-03 | 2023-03-03 10:30 | E | 2 |
| 1 | 2023-03-03 | 2023-03-03 10:40 | BUY F | 3 |
| 1 | 2023-03-03 | 2023-03-03 10:50 | G | 1 |
| 2 | 2023-03-03 | 2023-03-03 12:00 | A_1 | 1 |
| 2 | 2023-03-03 | 2023-03-03 12:20 | BUY B_1 | 2 |
| 2 | 2023-03-03 | 2023-03-03 12:20 | C_1 | 1 |
内容的提问来源于stack exchange,提问作者Mike Silver
相关产品推荐
相关产品推荐

