You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server 按最新修改优先级拆分重叠的员工任职日期记录

员工重叠任职记录清洗方案

问题背景

需要处理一批维护质量较差的员工任职日期表,表中存储员工在指定时间段内的任职岗位信息,目前存在大量日期重叠的任职记录:即同一员工同一时间被记录持有多个岗位,不符合业务实际逻辑。
当前数据校正规则:修改时间越晚的记录优先级越高,视为对旧数据的修正。需要消除任意时间区间内的重复任职记录,在岗位记录对应的起止日期范围内,仅保留最新修改的记录作为有效数据,结果无需返回修改时间字段。

示例数据

脏数据说明

脏数据示意图:
脏数据示意图

测试表构造SQL

DROP TABLE IF EXISTS #Test;
CREATE TABLE #Test
( Id INT IDENTITY(1,1)
 ,Person    INT
 ,Job       INT
 ,JobStart  DATE
 ,JobEnd    DATE
 ,Modified  DATE
);

INSERT #Test
VALUES
 (1,1,'2020-01-10','2020-01-20',GETDATE())
,(1,2,'2020-01-03','2020-01-10',DATEADD(DAY,-1,GETDATE()))
,(1,3,'2020-01-03','2020-01-13',DATEADD(DAY,-2,GETDATE()))
,(1,4,'2020-01-11','2020-01-20',DATEADD(DAY,-3,GETDATE()))
,(1,5,'2020-01-15','2020-01-25',DATEADD(DAY,-4,GETDATE()))
,(1,6,'2020-01-01','2020-01-30',DATEADD(DAY,-5,GETDATE()))

预期输出效果

清洗后数据示意图:
清洗后数据示意图
预期输出结果:

记录序号员工ID岗位ID任职开始日期任职结束日期
1162020-01-012020-01-03
2122020-01-032020-01-10
3112020-01-102020-01-20
4152020-01-202020-01-25
5162020-01-252020-01-30

可行解决方案

之前使用日期表的思路是正确的,问题出在对同岗位多段区间的分组逻辑缺失,补充间断识别+分组合并的逻辑即可解决问题,完整SQL如下:

-- 第一步:如果没有现成的日期维度表,先生成临时日期表覆盖所有任职日期范围
DECLARE @MinDate DATE, @MaxDate DATE;
SELECT @MinDate = MIN(JobStart), @MaxDate = MAX(JobEnd) FROM #Test;

DROP TABLE IF EXISTS #ListOfDates;
CREATE TABLE #ListOfDates ([Date] DATE PRIMARY KEY);

WITH Dates_CTE AS (
    SELECT @MinDate AS [Date]
    UNION ALL
    SELECT DATEADD(DAY, 1, [Date])
    FROM Dates_CTE
    WHERE [Date] < @MaxDate
)
INSERT INTO #ListOfDates ([Date])
SELECT [Date] FROM Dates_CTE OPTION (MAXRECURSION 0);

-- 第二步:计算每个日期下优先级最高的岗位
WITH DailyTopJob AS (
    SELECT
        t.Person,
        d.[Date],
        t.Job,
        ROW_NUMBER() OVER (PARTITION BY t.Person, d.[Date] ORDER BY t.Modified DESC) AS rn
    FROM #Test t
    INNER JOIN #ListOfDates d 
        ON d.[Date] BETWEEN t.JobStart AND t.JobEnd
),
-- 第三步:过滤出每个日期的最高优先级岗位,生成间断标记
DailyValidJob AS (
    SELECT
        Person,
        [Date],
        Job,
        -- 同员工同岗位日期不连续时,标记为新分组起点
        CASE WHEN LAG(Job) OVER (PARTITION BY Person ORDER BY [Date]) = Job THEN 0 ELSE 1 END AS IsNewGroup
    FROM DailyTopJob
    WHERE rn = 1
),
-- 第四步:对连续的同岗位日期分组
JobGroups AS (
    SELECT
        Person,
        [Date],
        Job,
        SUM(IsNewGroup) OVER (PARTITION BY Person ORDER BY [Date] ROWS UNBOUNDED PRECEDING) AS GroupId
    FROM DailyValidJob
)
-- 第五步:按分组合并日期区间得到最终结果
SELECT
    ROW_NUMBER() OVER (ORDER BY MIN([Date])) AS 记录序号,
    Person AS 员工ID,
    Job AS 岗位ID,
    MIN([Date]) AS 任职开始日期,
    MAX([Date]) AS 任职结束日期
FROM JobGroups
GROUP BY Person, Job, GroupId
ORDER BY 任职开始日期;

-- 清理临时表
DROP TABLE IF EXISTS #ListOfDates;
DROP TABLE IF EXISTS #Test;

方案说明

  • 先通过日期维度表把所有任职区间拆分为单日维度,按修改时间倒序取每日优先级最高的岗位,解决重叠记录的优先级判断问题
  • 新增间断识别逻辑:通过LAG窗口函数判断当前日期的岗位和前一天是否一致,不一致则标记为新分组的起点
  • 对同员工同岗位的连续日期分组后合并起止日期,即可自动拆分出同岗位的多段不连续任职区间,完美适配岗位6需要分两段返回的场景
  • 兼容SQL Server 2012及以上版本,适配V13.0.4(SQL Server 2016)版本使用

内容的提问来源于stack exchange,提问作者High Plains Grifter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 16:27:02