【问题标题】:Error trying to insert data using trigger T-SQL尝试使用触发器 T-SQL 插入数据时出错
【发布时间】:2012-09-27 18:27:36
【问题描述】:

下面是在我们的一个 SQL 表上用于任何插入/更新操作的触发器。 99/100 次这个触发器工作得很好,但是我们时不时地收到这个错误消息:

无法将值 NULL 插入到表的“TransactionDate”列中 'AgentResourcesU01.dbo.TransactionLog';列不允许空值。
插入失败。声明已终止。

从插入语句中可以看出,我们的事务日志表中的列是TransactionDate, Operator, TableName, Action, TableStringUserId。我在开始的 SELECT 语句中设置了变量@transDate,所以在我看来,除非是坏数据进入,否则 NULL 应该不会进入那里。

有什么想法吗?

    BEGIN
        SELECT @symetraNumber = SymetraNumber, @lastChangeOperator = LastChangeOperator, @transDate = LastChangeDate, @entityType = EntityType, 
        @firstName = FirstName, @lastName = LastName, @suffix = NameSuffix, @corpName = CorporateName, @controlId = ControlId
        FROM inserted

        IF @firstName IS NULL SET @firstName = 'NULL'
        IF @lastName IS NULL SET @lastName = 'NULL'
        IF @suffix IS NULL SET @suffix = 'NULL'
        IF @corpName IS NULL SET @corpName = 'NULL'
        IF @controlId IS NULL SET @controlId = 'NULL'

        SET @tableString = 'SymNum:' + @symetraNumber + ' EntType:' + @entityType + ' Fname:' + @firstName + ' Lname:' + @lastname + ' Suff:' + @suffix +
            ' CorpName:' + @corpName + ' ctrlId:' + @controlId

        INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId)
        VALUES (@transDate, 'Op', @tableName, @action, @tableString, @lastChangeOperator)
    END

【问题讨论】:

  • 您确认LastChangeDate 不为空吗?
  • 结果如何?
  • 抱歉,LastChangeDate 不为空。
  • 您的主要问题是:您似乎认为Inserted 表只包含一行。这个假设是错误的。触发器每批次触发一次 - 例如如果您一次插入 50 行,您的触发器将触发 一次 并且 Inserted 表将包含 50 行 - 所以您的语句如 SELECT @symetraNumber = SymetraNumber .. FROM inserted 将惨遭失败...... .
  • 不要使用 VALUES 插入,而是使用插入的 SELECT 语句。

标签: sql-server tsql triggers


【解决方案1】:

为了证明 Marc 的观点,您可以以基于集合的方式执行此操作,而无需所有这些讨厌的变量和 IF 检查:

INSERT dbo.TransactionLog
(
  TransactionDate, 
  Operator, 
  TableName, 
  Action,
  TableString,
  UserId
)
SELECT 
  LastChangeDate, 
  'Op',
  @TableName,
  @action, 
     'SymNum:'      + COALESCE(SymetraNumber, 'NULL')
     + ' EntType:'  + COALESCE(EntityType,    'NULL')
     + ' Fname:'    + COALESCE(FirstName,     'NULL')
     + ' Lname:'    + COALESCE(LastName,      'NULL')
     + ' Suff:'     + COALESCE(NameSuffix,    'NULL')
     + ' CorpName:' + COALESCE(CorporateName, 'NULL')
     + ' ctrlId:'   + COALESCE(ControlId,     'NULL'),
  LastChangeOperator
FROM inserted; 

如果基础表中的 LastChangeDate 可以为 NULL,则将其标记为 NOT NULL,修复插入 NULL 的问题,或两者兼而有之。触发器不必知道此约束,但您可以通过执行以下操作来解决它(如果值为 NULL,则立即将其设置为):

...
  UserId
)
SELECT 
  COALESCE(LastChangeDate, CURRENT_TIMESTAMP), 
  'Op',
...

【讨论】:

    【解决方案2】:

    [1] 我假设您有一个 INSERT/UPDATE/DELETE 触发器,当有人尝试从基表中删除行时,来自触发器的 inserted 表将有零行。看这个例子:

    CREATE TABLE MyTableWithTrigger (
        MyID INT IDENTITY PRIMARY KEY,
        LastUpdateDate DATETIME NOT NULL
    );
    GO
    
    CREATE TABLE TransactionLog (
        TransactionLogID INT IDENTITY PRIMARY KEY,
        CreateDate DATETIME NOT NULL DEFAULT GETDATE(),
        LastUpdateDate DATETIME NOT NULL,
        MyID INT NOT NULL
    );
    GO
    
    CREATE TRIGGER trIUD_MyTableWithTrigger_Audit
    ON MyTableWithTrigger
    AFTER INSERT, UPDATE, DELETE
    AS
    BEGIN
        DECLARE @LastUpdateDate DATETIME, @MyID INT;
        SELECT @LastUpdateDate=i.LastUpdateDate, @MyID=i.MyID
        FROM inserted i;
    
        INSERT TransactionLog (LastUpdateDate, MyID)
        VALUES (@LastUpdateDate, @MyID) 
    END;
    GO
    
    PRINT 'Test 1'
    INSERT  MyTableWithTrigger (LastUpdateDate)
    VALUES  ('2011-01-01');
    DELETE MyTableWithTrigger;
    SELECT * FROM MyTableWithTrigger;
    SELECT * FROM TransactionLog;
    

    输出:

    Msg 515, Level 16, State 2, Procedure trIUD_MyTableWithTrigger_Audit, Line 10
    Cannot insert the value NULL into column 'LastUpdateDate', table 'Test.dbo.TransactionLog'; column does not allow nulls. INSERT fails.
    The statement has been terminated.
    

    [2] 要更正您的触发器(请参阅 Marc 的评论),请阅读 Alex Kuznetsov 的书(使用 SQL Server 进行防御性数据库编程:AmazonRed Gate - PDF)的第 192 - 199 页。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多