如何将满足60天间隔条件的同名多行访问许可记录合并为单行
访问许可区间合并解法
这个需求属于典型的相邻区间分组合并场景,可通过窗口函数实现,支持所有支持窗口函数的主流数据库(MySQL 8.0+、PostgreSQL、SQL Server等),具体实现逻辑如下:
实现步骤
- 第一步:按
Name分组,将同一个用户的所有许可记录按Visitlicensedate升序排序,取每条记录上一行的对应对比日期值(按需求可选择上一条的许可颁发日期或许可到期日期) - 第二步:判断当前记录的
Visitlicensedate与上一条对比日期的间隔,间隔超过60天则标记为1(表示新分组的起点),否则标记为0 - 第三步:对每个用户的标记值做累加,得到每个用户内的分组ID,最后按
Name和分组ID聚合,Visitlicensedate取分组最小值,LicenseExpiredate取分组最大值即可
示例SQL代码
以下代码按「当前许可颁发时间距上一条许可颁发时间不超过60天则合并」的规则实现,完全匹配你的示例输出:
WITH step1 AS ( -- 第一步:取同用户上一条许可的颁发日期 SELECT Name, Visitlicensedate, LicenseExpiredate, LAG(Visitlicensedate) OVER (PARTITION BY Name ORDER BY Visitlicensedate) AS prev_license_date FROM 你的表名 ), step2 AS ( -- 第二步:打新分组标记,第一条记录默认归属第一个分组 SELECT Name, Visitlicensedate, LicenseExpiredate, CASE WHEN prev_license_date IS NULL OR DATEDIFF(Visitlicensedate, prev_license_date) > 60 THEN 1 ELSE 0 END AS is_new_group FROM step1 ), step3 AS ( -- 第三步:累加标记生成用户内的分组ID SELECT Name, Visitlicensedate, LicenseExpiredate, SUM(is_new_group) OVER (PARTITION BY Name ORDER BY Visitlicensedate) AS group_id FROM step2 ) -- 聚合得到最终合并结果 SELECT Name, MIN(Visitlicensedate) AS Visitlicensedate, MAX(LicenseExpiredate) AS LicenseExpiredate FROM step3 GROUP BY Name, group_id ORDER BY Name, Visitlicensedate;
注意事项
- 不同数据库的日期差函数可能有差异:PostgreSQL中可用
(Visitlicensedate - prev_license_date) > 60代替DATEDIFF,Oracle用TRUNC(Visitlicensedate) - TRUNC(prev_license_date) > 60即可 - 如果你的间隔规则是按「当前许可颁发时间距上一条许可到期时间」判断,只需要把step1中
LAG的字段换成LicenseExpiredate即可
内容的提问来源于stack exchange,提问作者smoove
相关产品推荐
相关产品推荐

