SQL Server:满足指定条件前为连续行分配相同行号
在SQL Server中为连续行分配相同分组ID直至触发条件
嘿,这个需求在SQL Server里其实很好解决,核心思路是用窗口函数+累计求和的组合来给连续行打上分组标记,直到触发你设定的条件为止。我就拿你提供的数据集来一步步说明:
首先,先把你的数据集用SQL表的形式呈现出来(方便测试):
CREATE TABLE YourTable ( ukey INT, id INT, code INT, create_date DATETIME2 ); INSERT INTO YourTable VALUES (1, 1082, 9053, '2018-03-01 23:18:51.0000000'), (2, 1082, 9035, '2018-03-01 23:19:21.0000000'), (3, 1082, 9053, '2018-03-01 23:22:55.0000000'), (4, 1082, 9535, '2018-03-01 23:23:30.0000000'), (5, 1196, 3145, '2018-03-05 07:27:15.0000000'), (6, 1196, 3162, '2018-03-05 07:27:50.0000000'), (7, 1196, 3175, '2018-03-05 07:28:24.0000000'), (8, 1196, 3235, '2018-03-05 07:28:57.0000000'), (9, 1196, 3295, '2018-03-05 07:29:31.0000000'), (10, 1196, 3448, '2018-03-05 07:30:04.0000000'), (11, 1196, 3465, '2018-03-05 07:30:37.0000000');
解法1:当特定code出现时开启新分组
假设你的“触发条件”是当code等于9053时,开启一个新的分组(从你的数据看,id=1082的行里两次出现9053,很像是分组的起点),可以用下面的查询:
SELECT ukey, id, code, create_date, -- 生成分组ID:每次遇到code=9053就加1,后续行继承当前分组ID SUM(CASE WHEN code = 9053 THEN 1 ELSE 0 END) OVER ( PARTITION BY id ORDER BY create_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS group_id FROM YourTable ORDER BY id, create_date;
逻辑解释:
PARTITION BY id:先按id拆分数据集,确保不同id的分组完全独立,不会混在一起ORDER BY create_date:保证行是按时间顺序处理的,符合“连续行”的要求CASE WHEN code = 9053 THEN 1 ELSE 0 END:把触发分组变化的行标记为1,其他行标记为0SUM() OVER(...):从当前id分组的第一行到当前行累计求和,这样每次遇到9053时,总和就会加1,形成新的分组ID;后续的行都会继承这个ID,直到下一个9053出现
查询结果里,id=1082的前两行group_id是1,后两行是2;id=1196的所有行因为没有触发条件,group_id都是1,完全符合连续行分组的需求。
解法2:当时间间隔超过阈值时开启新分组
如果你的触发条件是连续两行的时间间隔超过N分钟(比如3分钟),只需要修改CASE里的判断逻辑即可:
SELECT ukey, id, code, create_date, -- +1是因为第一行没有前一行,默认累计和为0,加1让分组从1开始 SUM(CASE WHEN DATEDIFF(MINUTE, LAG(create_date) OVER(PARTITION BY id ORDER BY create_date), create_date) > 3 THEN 1 ELSE 0 END) OVER ( PARTITION BY id ORDER BY create_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) + 1 AS group_id FROM YourTable ORDER BY id, create_date;
逻辑解释:
LAG(create_date) OVER(...):获取当前行的前一行的create_date值DATEDIFF(MINUTE, ...):计算当前行和前一行的时间间隔(分钟数)- 当间隔超过3分钟时标记为1,累计求和后得到分组ID,加1是为了让第一行的分组ID从1开始,而不是0
通用思路
不管你的触发条件是什么,核心都是:
- 用
CASE语句把触发分组变化的行标记为1,其他行标记为0 - 用
SUM() OVER(PARTITION BY 分组字段 ORDER BY 排序字段)来累计这些标记值,得到连续的分组ID
只要你能把“触发条件”转化为CASE里的判断,就能轻松实现需求。
内容的提问来源于stack exchange,提问作者nmess88
相关产品推荐
相关产品推荐

