SQL Server中如何按指定条件合并连续数据行?
合并SQL Server中Department表的连续部门记录
原始表结构与数据
SQL Server中有一张名为Department的表,包含4列,数据如下:
| staffNumber | department | startDate | endDate |
|---|---|---|---|
| 100 | A | 2016-09-22 18:30:00.000 | 2020-02-06 18:29:00.000 |
| 100 | B | 2020-02-06 18:30:00.000 | 2022-08-21 18:29:00.000 |
| 100 | A | 2022-08-21 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 101 | A | 2018-06-03 18:30:00.000 | 2023-08-20 18:29:00.000 |
| 101 | B | 2023-08-20 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 102 | A | 2022-12-21 18:30:00.000 | 2023-12-29 18:29:00.000 |
| 102 | A | 2023-12-29 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 103 | A | 2016-06-22 18:30:00.000 | 2018-03-05 18:29:00.000 |
| 103 | A | 2018-03-05 18:30:00.000 | 2021-03-05 18:29:00.000 |
| 103 | A | 2021-03-05 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 104 | A | 2016-06-22 18:30:00.000 | 2021-03-05 18:29:00.000 |
| 104 | A | 2021-03-05 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 105 | B | 2016-08-22 18:30:00.000 | 2021-02-07 18:29:00.000 |
| 105 | B | 2021-02-09 18:30:00.000 | 2079-12-31 18:29:00.000 |
合并条件
需要按以下规则合并多行记录:
- 相同的
staffNumber - 相同的
department - 连续记录中当前行的
endDate与下一行的startDate天数差为0
尝试的SQL及问题
我尝试了以下SQL查询,但未得到预期输出:
WITH DeptData_CTE AS ( SELECT staffNumber, department, startDate, endDate, LEAD(startDate) OVER (PARTITION BY staffNumber, department ORDER BY startDate) AS nextstartDate, LAG(endDate) OVER (PARTITION BY staffNumber, department ORDER BY startDate) AS prevendDate FROM department ), MergedData_CTE AS ( SELECT staffNumber, department, MIN(startDate) AS startDate, MAX(endDate) AS endDate FROM DeptData_CTE -- We merge rows where previous expiry date and current effective date are consecutive WHERE prevendDate IS NULL OR DATEDIFF(day, prevendDate, startDate) != 0 GROUP BY staffNumber, department ) -- Final selection of rows SELECT staffNumber, department, startDate, endDate FROM MergedData_CTE ORDER BY staffNumber, department, startDate;
得到的合并行startDate符合预期,但endDate不符合——原查询直接按staffNumber和department分组,会把同一员工同一部门的所有记录(即使中间有断开)都合并成一条,比如员工100的A部门有两段时间,原查询会错误合并。
预期输出
正确的合并结果应该是:
| staffNumber | department | startDate | endDate |
|---|---|---|---|
| 100 | A | 2016-09-22 18:30:00.000 | 2020-02-06 18:29:00.000 |
| 100 | B | 2020-02-06 18:30:00.000 | 2022-08-21 18:29:00.000 |
| 100 | A | 2022-08-21 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 101 | A | 2018-06-03 18:30:00.000 | 2023-08-20 18:29:00.000 |
| 101 | B | 2023-08-20 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 102 | A | 2022-12-21 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 103 | A | 2016-06-22 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 104 | A | 2016-06-22 18:30:00.000 | 2079-12-31 18:29:00.000 |
| 105 | B | 2016-08-22 18:30:00.000 | 2021-02-07 18:29:00.000 |
| 105 | B | 2021-02-09 18:30:00.000 | 2079-12-31 18:29:00.000 |
注:员工105的两条B部门记录日期差为1天,所以不合并。
解决方案SQL
可以通过生成连续分组标识来实现正确合并,具体如下:
WITH DeptGroups AS ( SELECT staffNumber, department, startDate, endDate, -- 生成分组ID:当前记录与前一条不连续时,组号+1 SUM(CASE WHEN LAG(endDate) OVER (PARTITION BY staffNumber, department ORDER BY startDate) IS NULL OR DATEDIFF(day, LAG(endDate) OVER (PARTITION BY staffNumber, department ORDER BY startDate), startDate) != 0 THEN 1 ELSE 0 END) OVER (PARTITION BY staffNumber, department ORDER BY startDate) AS GroupId FROM Department ) SELECT staffNumber, department, MIN(startDate) AS startDate, MAX(endDate) AS endDate FROM DeptGroups GROUP BY staffNumber, department, GroupId ORDER BY staffNumber, department, startDate;
逻辑说明
- 用
LAG窗口函数获取当前记录的上一条同员工同部门记录的endDate - 判断当前记录与上一条是否连续(天数差为0),不连续则生成新的分组ID
- 按
staffNumber、department和GroupId分组,取每组的最小startDate和最大endDate,得到正确的合并结果
内容的提问来源于stack exchange,提问作者Hello World
相关产品推荐
相关产品推荐

