我一直在编写脚本来创建 Type2 DimEmployee 表。我希望它在每次员工详细信息发生变化时创建一个新记录。
我相信这部分工作正常。我坚持的是正确更新已更改记录的 EndDate。
如果记录没有改变 EndDate 是 NULL 它也适用于记录,一个月是这个,然后下个月是那个(它插入正确的 EndDate 值)。
然而,当 Staging_Employees 中有多个相同的记录然后发生变化时,它不起作用。它没有使用正确的 EndDate 值。
P.S 登台表中的日期字段充当快照日期
有人能帮我吗?
谢谢
例如:
如您所见,DimEmployee 表中第一条记录的 EndDate 现在是 28/02/2023,这是在 StaffNo 4078 出现不同记录之前最后一条相同记录的日期。对于第二条记录,EndDate 仍然为 NULL,因为StaffNo 4078 之后就没有记录了
使用代码:
BEGIN TRY
TRUNCATE TABLE DimEmployee;
END TRY
BEGIN CATCH
CREATE TABLE DimEmployee (
DimEmployeeID INT IDENTITY(1,1) PRIMARY KEY,
StructureID INT,
StaffNo INT NOT NULL,
EmployeeID INT,
Position varchar(20),
JobTitle VARCHAR(100),
ContractType VARCHAR(50),
AverageHoursPerWeek DECIMAL(5,2),
WeeksPeryr DECIMAL(5,2),
HoursPerWeek DECIMAL(5,2),
PublicHolidayZone VARCHAR(50),
FTE DECIMAL(5,2),
AnalysisGroup VARCHAR(50),
EffectiveDate DATE,
EndDate DATE
);
END CATCH;
-- Insert new records with changes in the specified fields
WITH ChangedRecords AS (
SELECT
s.StaffNo,
RANK() OVER (ORDER BY s.StaffNo) AS EmployeeID,
s.Position,
s.JobTitle,
s.ContractType,
s.AverageHoursPerWeek,
s.WeeksPeryr,
s.HoursPerWeek,
s.PublicHolidayZone,
s.FTE,
s.AnalysisGroup,
d.StructureID,
s.Date,
LAG(d.StructureID) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousStructureID,
LAG(s.Position) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousPosition,
LAG(s.JobTitle) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousJobTitle,
LAG(s.ContractType) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousContractType,
LAG(s.AverageHoursPerWeek) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousAverageHoursPerWeek,
LAG(s.WeeksPeryr) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousWeeksPeryr,
LAG(s.HoursPerWeek) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousHoursPerWeek,
LAG(s.PublicHolidayZone) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousPublicHolidayZone,
LAG(s.FTE) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousFTE,
LAG(s.AnalysisGroup) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousAnalysisGroup,
ROW_NUMBER() OVER (PARTITION BY s.StaffNo, YEAR(s.Date), MONTH(s.Date), DAY(s.Date) ORDER BY s.Date) AS RowNum
FROM Staging_Employees AS s
JOIN DimStructure AS d ON
s.Directorate = d.Directorate AND
s.Service = d.Service AND
s.Section = d.Section AND
s.Team = d.Team
)
INSERT INTO DimEmployee (StructureID, StaffNo, EmployeeID, Position, JobTitle, ContractType, AverageHoursPerWeek, WeeksPeryr, HoursPerWeek, PublicHolidayZone, FTE, AnalysisGroup, EffectiveDate, EndDate)
SELECT StructureID, StaffNo, EmployeeID, Position, JobTitle, ContractType, AverageHoursPerWeek, WeeksPeryr, HoursPerWeek, PublicHolidayZone, FTE, AnalysisGroup, Date, NULL
FROM ChangedRecords
WHERE (PreviousStructureID IS NULL OR PreviousStructureID <> StructureID
OR PreviousPosition <> Position
OR PreviousJobTitle <> JobTitle
OR PreviousContractType <> ContractType
OR PreviousAverageHoursPerWeek <> AverageHoursPerWeek
OR PreviousWeeksPeryr <> WeeksPeryr
OR PreviousHoursPerWeek <> HoursPerWeek
OR PreviousPublicHolidayZone <> PublicHolidayZone
OR PreviousFTE <> FTE
OR PreviousAnalysisGroup <> AnalysisGroup);
-- Update EndDate for old records with changes in the specified fields
WITH ChangedRecords AS (
SELECT
s.StaffNo,
RANK() OVER (ORDER BY s.StaffNo) AS EmployeeID,
s.Position,
s.JobTitle,
s.ContractType,
s.AverageHoursPerWeek,
s.WeeksPeryr,
s.HoursPerWeek,
s.PublicHolidayZone,
s.FTE,
s.AnalysisGroup,
d.StructureID,
s.Date,
LAG(d.StructureID) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousStructureID,
LAG(s.Position) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousPosition,
LAG(s.JobTitle) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousJobTitle,
LAG(s.ContractType) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousContractType,
LAG(s.AverageHoursPerWeek) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousAverageHoursPerWeek,
LAG(s.WeeksPeryr) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousWeeksPeryr,
LAG(s.HoursPerWeek) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousHoursPerWeek,
LAG(s.PublicHolidayZone) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousPublicHolidayZone,
LAG(s.FTE) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousFTE,
LAG(s.AnalysisGroup) OVER (PARTITION BY s.StaffNo ORDER BY s.Date) AS PreviousAnalysisGroup
FROM Staging_Employees AS s
JOIN DimStructure AS d ON
s.Directorate = d.Directorate AND
s.Service = d.Service AND
s.Section = d.Section AND
s.Team = d.Team
)
UPDATE de
SET EndDate = (
SELECT MAX(se.Date)
FROM Staging_Employees se
WHERE de.StaffNo = se.StaffNo
AND se.Date <= de.EffectiveDate
)
FROM DimEmployee de
WHERE de.EndDate IS NULL
AND EXISTS (
SELECT 1
FROM ChangedRecords cr
WHERE cr.StaffNo = de.StaffNo
AND cr.EmployeeID = de.EmployeeID
AND cr.Date > de.EffectiveDate
AND (
cr.PreviousStructureID <> cr.StructureID
OR cr.PreviousPosition <> cr.Position
OR cr.PreviousJobTitle <> cr.JobTitle
OR cr.PreviousContractType <> cr.ContractType
OR cr.PreviousAverageHoursPerWeek <> cr.AverageHoursPerWeek
OR cr.PreviousWeeksPeryr <> cr.WeeksPeryr
OR cr.PreviousHoursPerWeek <> cr.HoursPerWeek
OR cr.PreviousPublicHolidayZone <> cr.PublicHolidayZone
OR cr.PreviousFTE <> cr.FTE
OR cr.PreviousAnalysisGroup <> cr.AnalysisGroup
)
);