【问题标题】:Audit trigger inserting multiple rows into audit table审计触发器将多行插入审计表
【发布时间】:2021-09-05 11:14:32
【问题描述】:

我编写了一个触发器,当我更新基表中的值时,我在审计表中获得了多个记录。我只期待一个。这是我的触发器:

CREATE TRIGGER dbo.SOP10100_TRDISAMT
ON dbo.SOP10100
AFTER INSERT, UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    IF (select TRDISAMT from inserted) = 0
        BEGIN
            RETURN
        END
    ELSE
        BEGIN
            DECLARE @SOPTYPE smallint = (select soptype from inserted)
            DECLARE @SOPNUMBE char(21) = (select sopnumbe from inserted)
            DECLARE @MSTRNUMB int = (select mstrnumb from inserted)
            DECLARE @DOCID char(15) = (select docid from inserted)
            DECLARE @SUBTOTAL numeric(19,5) = (select subtotal from inserted)
            DECLARE @MISCAMT numeric(19,5) = (select MISCAMNT from inserted)
            DECLARE @TRDISAMT numeric(19,5) = (select TRDISAMT from inserted)
            DECLARE @TRDISAMT_B4 numeric(19,5) = (select TRDISAMT from deleted)
            DECLARE @FRTAMNT numeric(19,5) = (select FRTAMNT from inserted)
            DECLARE @TAXAMNT numeric(19,5) = (select TAXAMNT from inserted)
            DECLARE @DOCAMNT numeric(19,5) = (select DOCAMNT from inserted)
            DECLARE @USERNAME nvarchar(128) = (select SUSER_SNAME())
            DECLARE @TheTime datetime = (select GETDATE())

            INSERT INTO SOP10100_TRDISAMT_AUDIT (soptype,sopnumbe,MSTRNUMB,DOCID,SUBTOTAL,MISCAMT,TRDISAMT,TRDISAMT_B4,FRTAMNT,TAXAMNT,DOCAMNT,USERNAME,TheTime)
            VALUES (@SOPTYPE,@SOPNUMBE,@MSTRNUMB,@DOCID,@SUBTOTAL,@MISCAMT,@TRDISAMT,@TRDISAMT_B4,@FRTAMNT,@TAXAMNT,@DOCAMNT,@USERNAME,@TheTime)
        END
    END

这是我运行来更新值的:

update SOP10100 set TRDISAMT = 35 where SOPTYPE = 1 and SOPNUMBE = '126535'

这导致两条记录被插入到我的审计表中。想法?

【问题讨论】:

  • 您的触发器有缺陷,它假定INSERT/UPDATE 只影响1 行;这是不正确的。一个触发器可以影响 0+ 行。
  • 以上也不会INSERT 2 rows, on;y 1.
  • The Silent Bug I Find in Most Triggers 您没有考虑inserted 表中的多行。并且您的特定示例只有在您执行两次更新时才会重现。但是你想做什么:如果有人将一行更新为相同的值会发生什么?或者更新行但不更新TRDISAMT 列?

标签: sql sql-server tsql triggers


【解决方案1】:

您的查询存在致命缺陷,因为它没有考虑插入或更新的多个(或零个)行。

您的触发器应该如下所示:

CREATE TRIGGER dbo.SOP10100_TRDISAMT
ON dbo.SOP10100
AFTER INSERT, UPDATE
AS 

INSERT INTO SOP10100_TRDISAMT_AUDIT
    (soptype, sopnumbe, MSTRNUMB, DOCID, SUBTOTAL, MISCAMT, TRDISAMT,
    TRDISAMT_B4, FRTAMNT, TAXAMNT, DOCAMNT, USERNAME, TheTime)
SELECT i.soptype, i.sopnumbe, i.mstrnumb, i.docid, i.subtotal, i.MISCAMNT, i.TRDISAMT,
    i.TRDISAMT, i.FRTAMNT, i.TAXAMNT, i.DOCAMNT, SUSER_SNAME(), GETDATE()
FROM inserted i
WHERE i.TRDISAMT <> 0;

GO
  • 如果你想排除那些值没有被UPDATE语句改变的行,你需要添加
EXCEPT
SELECT d.soptype, d.sopnumbe.....
FROM deleted d
  • 我注意到char 是一种不常见的数据类型,只能在值固定为该长度的情况下使用,否则会出现尾随空格。

【讨论】:

    猜你喜欢
    • 2020-11-07
    • 2014-04-19
    • 2010-10-10
    • 1970-01-01
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多