使用 IsActive 更新记录

Update record with IsActive

我正在尝试构建一个维度 table,它将通过使用字段 'IsActive' 和 'EffectiveDate'.

来识别当前和历史数据

IsActive of 1 = 活动。

EffectiveDate = 摄取记录的日期。

场景:我有一个包含员工当前视图的现有记录,但是如果有关员工的任何信息发生变化,我想创建一个新的订单项,而不是更新现有记录,更新后的记录变为活跃而之前的记录变为不活跃。

ID Name Surname Age IsActive EffectiveDate
1 John Doe 54 1 2021-01-01

完成对员工数据的更改后,我想按如下方式更新 table:

ID Name Surname Age IsActive EffectiveDate
1 John Doe 54 0 2021-01-01
2 John Doe 64 1 2021-06-25

我正在使用 'Name'、'Surname' 和 'Age' 的组合来识别唯一记录。我使用这三个字段的原因是因为没有提供其他信息来唯一标识员工。

非常感谢任何帮助。

你可以自己做,但我会先 Temporal Tables 试一试,这几乎正是它们的设计目的。您只需要学习稍微不同的查询语法即可找到在某个时间点或范围内“活跃”的行。

与此同时,我可以分享一个非常简单的示例来说明如何自己执行此操作,但我同意以下评论,即姓名 + 姓氏 + 年龄是一个糟糕的主键,因为这三个主键都可能因任何给定而改变员工(年龄绝对会改变——这就是为什么我们通常存储生日)。我们为什么不 假装 我们在某个地方为每个员工分配一个唯一但无意义的 ID(这种 ID 会出现在他们的访问徽章上或 HR 数据库中的数据中)只是使示例保持简单。

假设您的 table 是:

CREATE TABLE dbo.EmployeeHistoryStuff
(
  ID            bigint       NOT NULL IDENTITY(1,1) PRIMARY KEY,
  EmployeeID    int, 
  Name          nvarchar(50), 
  Surname       nvarchar(50),
  Age           tinyint,
  IsActive      bit          NOT NULL DEFAULT (1),
  EffectiveDate datetime2(0) NOT NULL DEFAULT sysutcdatetime()
);

我们可以添加一些示例行:

INSERT dbo.EmployeeHistoryStuff(EmployeeID, Name, Surname, Age) 
VALUES(1, N'Aaron', N'Bertrand', 29),
      (2, N'Teemu', N'Selanne',  31),
      (3, N'Bobby', N'Orr',      62),
      (4, N'Wayne', N'Gretzky',  55);

现在我们可以创建一个触发器来拦截对 IsActive = 1 之前任何行的任何更新并插入一个新行:

CREATE TRIGGER dbo.InsteadOfEmployeeHistoryStuff
ON dbo.EmployeeHistoryStuff
INSTEAD OF UPDATE
AS
BEGIN
  SET NOCOUNT ON;
  DECLARE @now datetime2(0) = sysutcdatetime();
  
  UPDATE old SET IsActive = 0
    FROM inserted AS i
    INNER JOIN dbo.EmployeeHistoryStuff AS old
    ON i.EmployeeID = old.EmployeeID
    WHERE old.IsActive = 1;
  
  INSERT dbo.EmployeeHistoryStuff(EmployeeID, Name, Surname, Age, EffectiveDate)
    SELECT EmployeeID, Name, Surname, Age, DATEADD(SECOND, 1, @now)
      FROM inserted;
END
GO

现在,如果我们因为一些员工过生日而执行更新:

 UPDATE dbo.EmployeeHistoryStuff SET Age += 1 WHERE EmployeeID IN (1,2);
ID EmployeeID Name Surname Age IsActive EffectiveDate
1 1 Aaron Bertrand 29 False 2021-10-22 13:37:24
2 2 Teemu Selanne 31 False 2021-10-22 13:37:24
3 3 Bobby Orr 62 True 2021-10-22 13:37:24
4 4 Wayne Gretzky 55 True 2021-10-22 13:37:24
5 1 Aaron Bertrand 30 True 2021-10-22 13:37:30
6 2 Teemu Selanne 32 True 2021-10-22 13:37:30

然后韦恩想出风头:

 UPDATE dbo.EmployeeHistoryStuff SET Surname = N'Schmetzky' WHERE EmployeeID = 4;
ID EmployeeID Name Surname Age IsActive EffectiveDate
1 1 Aaron Bertrand 29 False 2021-10-22 13:37:24
2 2 Teemu Selanne 31 False 2021-10-22 13:37:24
3 3 Bobby Orr 62 True 2021-10-22 13:37:24
4 4 Wayne Gretzky 55 False 2021-10-22 13:37:24
5 1 Aaron Bertrand 30 True 2021-10-22 13:37:30
6 2 Teemu Selanne 32 True 2021-10-22 13:37:30
7 4 Wayne Schmetzky 55 True 2021-10-22 13:37:35

然后韦恩改变了主意:

UPDATE dbo.EmployeeHistoryStuff SET Surname = N'Gretzky' WHERE EmployeeID = 4;
ID EmployeeID Name Surname Age IsActive EffectiveDate
1 1 Aaron Bertrand 29 False 2021-10-22 13:37:24
2 2 Teemu Selanne 31 False 2021-10-22 13:37:24
3 3 Bobby Orr 62 True 2021-10-22 13:37:24
4 4 Wayne Gretzky 55 False 2021-10-22 13:37:24
5 1 Aaron Bertrand 30 True 2021-10-22 13:37:30
6 2 Teemu Selanne 32 True 2021-10-22 13:37:30
7 4 Wayne Schmetzky 55 False 2021-10-22 13:37:35
8 4 Wayne Gretzky 55 True 2021-10-22 13:37:40
9 4 Wayne Gretzky 55 True 2021-10-22 13:37:40

我的时间有点不对,我会回来修复一下。

您可以使用 Merge 语句作为选项之一,当与源 table (原始 table) 基于条件。

此处要更新现有记录,您不能使用“年龄”列来定义组合中的唯一性,因为新数据集的“年龄”列中的数据发生了变化。

以下是我的复现详情:

  1. 现有维度员工数据:

  1. 源数据:

  1. 代码:

     Create procedure sp_employee
     AS   
    
     SET NOCOUNT ON;  
    
     BEGIN
    
    --update Active flag of existing data
    
     MERGE dim_employee AS Target
     USING employee_data AS Source
     ON Source.Name = Target.Name
     and Source.Surname = Target.Surname
     WHEN MATCHED THEN UPDATE SET
     Target.IsActive = 0;
    
    --Insert new data (assuming the table has only changed data set)
     Insert into dim_employee
     select Name, Surname, Age, IsActive, EffectiveDate from employee_data;
    
    End
    GO
    
  2. 如果源中有旧记录 table 以及新的更改集,您可以使用以下代码仅插入更改数据集。

     Insert into dim_employee
     select Name, Surname, Age, IsActive, EffectiveDate from employee_data
     except
     select distinct a.Name, a.Surname, a.Age, a.IsActive, a.EffectiveDate from employee_data a
     inner join dim_employee b on a.Name = b.Name and a.Surname = b.Surname and a.Age = b.Age;
    
  3. 执行存储过程

     Exec sp_employee;
    
  4. 执行存储过程后:'John Doe' 的 IsActive 列数据已更新为 0,并且从 employee_data table 插入了 'John Doe' 的新记录.