SQL Server中如何在窗口函数中运用日期范围筛选数据?
解决SQL Server中按每个ID的最新日期筛选前30天数据的问题
你需要从给定的数据表中,为每个id筛选出其最新日期往前30天内的所有记录,由于数据存在日期缺失,且SQL Server不支持窗口函数中的日期范围逻辑(比如RANGE BETWEEN INTERVAL '30 day' PRECEDING AND CURRENT ROW这类语法),这里提供一个可行的解决方案。
先把你的示例数据表整理成清晰的格式:
| id | date | item |
|---|---|---|
| 123 | 07/01/2018 | anf |
| 123 | 31/12/2017 | sh |
| 123 | 01/01/2018 | ab |
| 123 | 12/03/2018 | fhy |
| 123 | 02/01/2018 | fg |
| 124 | 10/12/2017 | ab |
| 124 | 03/03/2017 | sh |
| 125 | 21/11/2017 | ab |
| 125 | 31/12/2017 | sh |
| 125 | 01/03/2017 | ab |
| 126 | 31/12/2017 | ab |
方案思路
核心思路是先获取每个id的最新日期,再将这个最新日期与原表关联,筛选出该id下所有日期在「最新日期 - 30天」范围内的记录。这种方法不需要依赖窗口函数的日期范围特性,完全兼容SQL Server。
具体SQL代码
可以用CTE(公共表表达式)来实现,代码清晰易读:
WITH IdLatestDates AS ( -- 第一步:获取每个id的最新日期 SELECT id, MAX(CONVERT(DATE, date, 103)) AS latest_date -- 转换dd/mm/yyyy格式为DATE类型 FROM your_table_name GROUP BY id ) -- 第二步:关联原表,筛选符合日期范围的记录 SELECT t.id, t.date, t.item FROM your_table_name t JOIN IdLatestDates ld ON t.id = ld.id WHERE CONVERT(DATE, t.date, 103) >= DATEADD(DAY, -30, ld.latest_date) ORDER BY t.id, CONVERT(DATE, t.date, 103) DESC;
代码解释
- CTE部分:
IdLatestDates通过GROUP BY id和MAX()函数,得到每个id对应的最晚日期。这里用CONVERT(DATE, date, 103)是因为你的日期格式是dd/mm/yyyy,103是SQL Server对应欧洲日期格式的转换代码,如果你的date字段本身就是DATE类型,可以直接去掉转换。 - 关联筛选部分:将原表与CTE通过
id关联,用DATEADD(DAY, -30, ld.latest_date)计算出每个id的筛选起始日期,然后保留原表中日期大于等于该起始日期的记录。 - 排序:最后按
id和日期降序排列,方便查看每个id的最新记录在前。
补充说明
如果你的date字段是标准的DATE或DATETIME类型,直接简化代码即可:
WITH IdLatestDates AS ( SELECT id, MAX(date) AS latest_date FROM your_table_name GROUP BY id ) SELECT t.id, t.date, t.item FROM your_table_name t JOIN IdLatestDates ld ON t.id = ld.id WHERE t.date >= DATEADD(DAY, -30, ld.latest_date) ORDER BY t.id, t.date DESC;
这样就能准确筛选出每个id从最新日期往前30天内的所有数据,即使存在日期缺失也不受影响。
内容的提问来源于stack exchange,提问作者user123




