SQL Server遍历日期并排除7天内重复日期的实现方法
SQL Server 实现日期间隔7天内仅保留最早记录的方案
假设你的数据表结构类似 CustomerVisits,包含 CustomerName(客户名称)和 VisitDate(访问日期)两个核心字段,以下提供两种可行的实现方案:
方案1:使用LAG窗口函数标记需排除的记录
利用窗口函数 LAG() 获取同一客户的上一条访问日期,通过计算日期差判断是否保留当前记录,逻辑简单高效:
WITH RankedVisits AS ( SELECT CustomerName, VisitDate, -- 获取同一客户的上一条访问日期 LAG(VisitDate) OVER (PARTITION BY CustomerName ORDER BY VisitDate) AS PreviousVisitDate, -- 标记是否保留:第一条记录默认保留,后续记录与上一条间隔≥7天则保留 CASE WHEN LAG(VisitDate) OVER (PARTITION BY CustomerName ORDER BY VisitDate) IS NULL THEN 1 WHEN DATEDIFF(day, LAG(VisitDate) OVER (PARTITION BY CustomerName ORDER BY VisitDate), VisitDate) >= 7 THEN 1 ELSE 0 END AS KeepFlag FROM CustomerVisits ) -- 输出所有记录及标记,如需仅保留有效记录可添加 WHERE KeepFlag = 1 SELECT CustomerName, VisitDate, KeepFlag FROM RankedVisits ORDER BY CustomerName, VisitDate;
逻辑说明:
- 按客户分组、访问日期升序排序后,
LAG()函数会返回当前记录的上一条同客户记录的日期 - 第一条记录因无前置记录,直接标记为保留(
KeepFlag=1) - 后续记录若与上一条的间隔≥7天则保留,否则标记为排除(
KeepFlag=0)
方案2:递归CTE筛选所有符合条件的保留记录
如果需要跳过所有7天内的中间记录,直接筛选出所有间隔≥7天的有效记录(比如客户有2023/10/22、2023/10/25、2023/11/1三条记录,仅保留2023/10/22和2023/11/1),可以用递归CTE实现:
WITH CustomerFirstVisit AS ( -- 先获取每个客户的最早访问日期 SELECT CustomerName, MIN(VisitDate) AS VisitDate FROM CustomerVisits GROUP BY CustomerName ), RecursiveVisits AS ( -- 递归起始点:每个客户的最早记录 SELECT CustomerName, VisitDate FROM CustomerFirstVisit UNION ALL -- 递归查找下一条与当前记录间隔≥7天的最早日期 SELECT cv.CustomerName, MIN(cv.VisitDate) AS VisitDate FROM CustomerVisits cv JOIN RecursiveVisits rv ON cv.CustomerName = rv.CustomerName WHERE cv.VisitDate > rv.VisitDate AND DATEDIFF(day, rv.VisitDate, cv.VisitDate) >= 7 GROUP BY cv.CustomerName ) -- 关联原表标记所有记录的保留状态 SELECT cv.CustomerName, cv.VisitDate, CASE WHEN rv.VisitDate IS NOT NULL THEN 1 ELSE 0 END AS KeepFlag FROM CustomerVisits cv LEFT JOIN RecursiveVisits rv ON cv.CustomerName = rv.CustomerName AND cv.VisitDate = rv.VisitDate ORDER BY cv.CustomerName, cv.VisitDate;
逻辑说明:
- 首先获取每个客户的最早访问日期作为递归起点
- 递归阶段不断查找当前保留记录之后、间隔≥7天的最早访问日期,直到没有符合条件的记录为止
- 最后通过左关联原表,标记哪些记录是需要保留的
内容的提问来源于stack exchange,提问作者Aqua
相关产品推荐
相关产品推荐

