SQL Server:如何标记同ID过去X天内有关联记录的行?
解决方案:无JOIN实现SQL Server同ID日期范围标记需求
针对你提出的需求——不需要额外JOIN,在SQL Server中实现同ID下当前行日期是否处于某条历史记录过去X天内的标记,我们可以利用窗口函数结合日期计算来完成,完全避免大表JOIN带来的性能问题。
核心思路
我们需要针对每个ID的每一行,统计同ID下满足「历史日期 >= 当前日期 - X天 且 历史日期 < 当前日期」的记录数量:
- 如果统计数大于0,说明存在符合条件的历史记录,标记为1
- 否则标记为0
具体SQL实现
假设我们把X天定义为10天(你可以根据实际需求修改这个数值),SQL语句如下:
SELECT ID, Date, CASE WHEN COUNT(*) OVER ( PARTITION BY ID ORDER BY Date RANGE BETWEEN INTERVAL '10' DAY PRECEDING AND 1 PRECEDING ) > 0 THEN 1 ELSE 0 END AS Marker FROM YourTableName;
代码解释
PARTITION BY ID:将数据按ID分组,只在相同ID的范围内进行计算ORDER BY Date:确保按日期顺序处理每条记录,保证我们只统计当前行之前的历史记录RANGE BETWEEN INTERVAL '10' DAY PRECEDING AND 1 PRECEDING:INTERVAL '10' DAY PRECEDING:表示当前日期往前推10天的时间点1 PRECEDING:表示当前行的前一行(结合RANGE,实际是所有日期小于当前行日期且在过去10天内的记录)
COUNT(*) OVER (...):统计窗口内符合条件的记录数,大于0就标记为1,否则0
验证你的示例数据
假设你的X值设为9天(因为你的示例中2018-01-10和2018-01-01相差9天),代入上述SQL后,会得到你想要的结果:
ID | Date | Marker
1 | 2018-01-01 | 0
1 | 2018-01-10 | 1
1 | 2018-02-02 | 0
因为2018-02-02往前推9天是2018-01-24,而同ID的历史记录最新是2018-01-10,不在这个范围内,所以标记为0,完全符合你的示例要求。
兼容低版本SQL Server的写法
如果你使用的是SQL Server 2012之前的版本,RANGE BETWEEN INTERVAL语法不被支持,可以用日期转天数差的方式实现:
SELECT ID, Date, CASE WHEN COUNT(*) OVER ( PARTITION BY ID ORDER BY Date RANGE BETWEEN DATEDIFF(DAY, '19000101', Date) - 10 AND DATEDIFF(DAY, '19000101', Date) - 1 ) > 0 THEN 1 ELSE 0 END AS Marker FROM YourTableName;
这里通过把日期转换成与基准日的天数差,来实现RANGE范围的计算,原理和上面一致。
内容的提问来源于stack exchange,提问作者Vaidøtas I.
相关产品推荐
相关产品推荐

