Обновление EndDate в таблице DimEmployee

Я работаю над сценарием для создания таблицы DimEmployee Type2. Я хочу, чтобы он создавал новую запись каждый раз, когда происходит изменение сведений о сотрудниках.

Я считаю, что эта часть работает правильно. То, на чем я застрял, правильно обновляет EndDate для записей, которые изменились.

Это работает, если записи не изменились, EndDate равен NULL он также работает для записей, в одном месяце это было так, а в следующем месяце было так (он вставляет правильное значение EndDate).

Однако это не работает, когда в Staging_Employees было несколько идентичных записей, а затем произошли изменения. Он не использует правильное значение EndDate.

P.S. Поле даты в промежуточной таблице действует как дата моментального снимка.

Кто-нибудь может мне с этим помочь?

Спасибо

Например:

Как видите, EndDate для первой записи в таблице DimEmployee теперь 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
    )
);

Можете ли вы объяснить это на примере: «Однако он не работает, когда в Staging_Employees было несколько идентичных записей, а затем произошли изменения. Он не использует правильное значение EndDate». ?

Amira Bedhiafi 16.05.2023 13:37
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
1
77
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Исходя из того, что вы предоставили, проблема с обновлением EndDate для записей, которые менялись несколько раз, может быть связана с подзапросом, который вы используете для получения нового EndDate, поскольку кажется, что он учитывает только максимальную дату из таблицы Staging_Employees, которая меньше больше или равно EffectiveDate обновляемой записи.

Этот подзапрос может не учитывать множественные изменения, которые могли произойти в этом диапазоне.

Чтобы решить эту проблему, вам нужно изменить подзапрос, чтобы учитывать максимальную дату, которая меньше или равна EffectiveDate, а также больше, чем предыдущая EndDate обновляемой записи. Это гарантирует, что вы выбираете правильный EndDate для записей, которые имеют несколько изменений.

 -- Update EndDate for old records with changes in the specified fields
    WITH ChangedRecords AS (
        -- Same as before
    )
    UPDATE de
    SET EndDate = (
        SELECT MAX(se.Date)
        FROM Staging_Employees se
        WHERE de.StaffNo = se.StaffNo
        AND se.Date <= de.EffectiveDate
        AND se.Date > COALESCE(de.EndDate, '1900-01-01') -- Consider dates after the previous EndDate
    )
    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
        )
    );

Другие вопросы по теме