SQL触发器 - 已删除或已更新?或者别的什么?

Mad*_* Zu 0 sql sql-server triggers sqltransaction

我想弄清楚我需要在这里使用:删除,插入或更新.

基本上.

当主表更新时,我需要将一些数据写入历史表,并且只有当状态从某些内容更改为挂起或活动时才需要.

这就是我现在拥有的:

ALTER TRIGGER [dbo].[trg_SourceHistory]  ON [dbo].[tblSource]
FOR UPDATE AS  
    DECLARE @statusOldValue char(1) 
    DECLARE @statusNewValue char(1)

    SELECT @statusOldValue = statusCode FROM deleted 
    SELECT @statusNewValue= statusCode FROM updated

    IF (@statusOldValue <> @statusNewValue) AND 
       (@statusOldValue = 'P' or @statusOldValue = 'A')
    BEGIN TRY
       INSERT * INTO tblHistoryTable)  
           select * from [DELETED]
Run Code Online (Sandbox Code Playgroud)

所以我希望新数据保留在主表中,历史表将被覆盖的内容更新...现在它只是复制相同的信息.所以更新后,我的两个表都有相同的数据.

mar*_*c_s 7

只有InsertedDeleted伪表 - 没有Updated.

对于a UPDATE,Inserted包含新值(更新后),同时Deleted包含更新前的旧值.

还要注意,每个批次触发一次触发器- 每行不触发一次.所以两个伪表都可能包含多行!不要只假设一行并将其分配给变量 - 这个

SELECT @statusOldValue = statusCode FROM deleted 
SELECT @statusNewValue= statusCode FROM updated
Run Code Online (Sandbox Code Playgroud)

如果你有多行会失败!你需要写你的触发器以这样的方式,他们一起工作多行InsertedDeleted!

更新:是的-有IS写这一个更好的方法:

ALTER TRIGGER [dbo].[trg_SourceHistory]  ON [dbo].[tblSource]
FOR UPDATE 
AS  
   INSERT INTO dbo.tblHistoryTable(Col1, Col2, Col3, ...., ColN)
      SELECT Col1, COl2, Col3, ..... ColN
        FROM Deleted d
        INNER JOIN Inserted i ON i.PrimaryKey = d.PrimaryKey
        WHERE i.statusCode <> d.statusCode
          AND d.statusCode IN ('A', 'P')
Run Code Online (Sandbox Code Playgroud)

基本上:

  • 显式指定要插入的列 - 在INSERT语句中以及SELECT检索要插入的数据的语句 - 以避免任何令人讨厌的意外

  • 创建一个INNER JOINbetween 表InsertedDeleted伪表来获取所有已更新的行

  • 中指定所有其他条件(不同的状态码等)WHERE的条款SELECT

此解决方案适用于正在更新的批量行 - 它不会在多行更新中失败....

  • 是的,一百万次是的,一个写得不好的触发器可能会造成可怕的数据完整性问题. (2认同)

Mat*_*lie 5

您需要同时使用inserteddeleted表来检查以下记录:
1.已经存在(检查它不是插入)
2.仍然存在(检查它不是删除)
3.状态字段已更改

您还需要确保以基于集合的方法执行此操作,根据marc_s的答案,触发器不是单个记录进程.

INSERT INTO
  tblHistoryTable
SELECT
  deleted.*
FROM
  inserted
INNER JOIN
  deleted
    ON inserted.PrimaryKey = deleted.PrimaryKey
WHERE
  inserted.StatusCode <> deleted.StatusCode
  AND (inserted.StatusCode = 'P' OR inserted.StatusCode = 'A')
Run Code Online (Sandbox Code Playgroud)
  • inserted =新值
  • 删除=旧值