【问题标题】:MS SQL Server 2017 How to Write a Trigger that moves the updated value and the old value to a new tableMS SQL Server 2017 如何编写将更新值和旧值移动到新表的触发器
【发布时间】:2017-11-15 00:45:19
【问题描述】:

当员工表中的工资更新时,我希望将 EmpID、oldrate 和 newrate 移动到 changeLog 表中。

当我运行下面的代码时,它会移动所有员工 ID,并为 oldRate 和一些 newrate 提供 Null

ALTER TRIGGER trg_PayChange
ON Employees 
AFTER Update
AS
    IF NOT UPDATE(pay)
       DECLARE @oldRate VARCHAR(100)

    DECLARE @newRate VARCHAR(100)

    BEGIN
        INSERT INTO ChangeLog (EmpID)
            SELECT EmployeeID 
            FROM Employees

        INSERT INTO ChangeLog (OldRate)
            SELECT OldRate = (SELECT Pay FROM Deleted)

        INSERT INTO ChangeLog (NewRate)
            SELECT NewRate = (SELECT Pay FROM Inserted)
END
GO

【问题讨论】:

  • 也许存储过程更合适?输入端是什么样的?我会在按钮提交时执行一个存储过程。在参数中设置新值,从表中选择员工及其旧值并将其插入到参数旁边的表中,然后更新原始表。或者这是在触发器上设置的?
  • 您可能想要指定您正在使用的数据库引擎。例如,在 MySQL 上,您可能可以在这里找到答案:stackoverflow.com/a/6298881/4206925
  • 这种语法看起来像 Transact-SQL (Microsoft SQL Server) 而不是 MySQL。也许这应该被标记为 sql-server 而不是 mysql
  • 你是对的。我修好了,谢谢 spencer7593。这是一个赋值,必须使用触发器。

标签: sql sql-server triggers sql-update sql-delete


【解决方案1】:

假设EmployeeIdEmployees 表上的PRIMARY KEY 或唯一键,并且EmployeeId 的值没有更新:

IF NOT UPDATE(EmployeeId)

   INSERT INTO ChangeLog (EmpId, OldRate, NewRate)
   SELECT d.EmployeeId
        , d.Pay
        , i.Pay
     FROM deleted d
     JOIN inserted i
       ON i.EmployeeId = d.EmployeeId
   ;

请注意,如果 EmployeeId 的值发生更改,则此插入不一定会在 ChangeLog 表中插入一行。考虑以下形式的查询:

UPDATE Employees SET Pay = 7, EmployeeId = 757 WHERE EmployeeId = 42

如果成功,我们预计deleted 表将包含

EmployeeId  Pay  somecol ...
----------  ---  ------- ---
        42    4  someval

插入的表将包含

EmployeeId  Pay  somecol ... 
----------  ---  ------- ---
       757    7  someval ... 

使用反连接模式的几个查询将获取我们的第一个查询会遗漏的那些更改...

  -- deleted with no matching inserted
  INSERT INTO ChangeLog (EmpId, OldRate, NewRate)
  SELECT d.EmployeeId
       , d.Pay
       , NULL
    FROM deleted d
    LEFT
    JOIN inserted i
      ON i.EmployeeId = d.EmployeeId
   WHERE i.EmployeeId IS NULL
  ;

  -- inserted with no matching deleted
  INSERT INTO ChangeLog (EmpId, OldRate, NewRate)
  SELECT i.EmployeeId
       , NULL
       , i.Pay
    FROM inserted i
    LEFT
    JOIN deleted d
      ON d.EmployeeId = i.EmployeeId
   WHERE d.EmployeeId IS NULL
  ;

但是......如果我们“交换” EmployeeId 值,它就会下降。假设表中存在 EmployeeId 值为 757 和 42 的行,我们发出如下语句:

 UPDATE Employees
    SET EmployeeId = CASE WHEN EmployeeId = 42  THEN 757 
                          WHEN EmployeeId = 757 THEN 42
                     END
      , Pay        = CASE WHEN EmployeeId = 42  THEN 4
                          WHEN EmployeeId = 757 THEN 7
                     END
 WHERE EmployeeId IN (42,757)

这样,inserteddeleted 表中的行将“交叉连接”... EmployeeId 值将匹配,但将匹配不同的行。所以我们可能想测试一条 UPDATE 语句是否试图为 EmployeeId 列分配一个新值,以便我们采取适当的行动。


我们最好只记录更改...

INSERT INTO ChangeLog (action, empid, pay )
SELECT 'update old', EmployeeId, Pay
  FROM deleted
;
INSERT INTO ChangeLog (action, empid, pay )
SELECT 'update new', EmployeeId, Pay 
  FROM inserted
;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    • 1970-01-01
    • 1970-01-01
    • 2020-09-07
    • 1970-01-01
    相关资源
    最近更新 更多