0

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

无法将值 NULL 插入到列“TransactionDate”、表“AgentResourcesU01.dbo.TransactionLog”中;列不允许空值。
插入失败。该语句已终止。

从 Insert 语句中可以看出,我们的事务日志表中的列是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
4

2 回答 2

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

...
  UserId
)
SELECT 
  COALESCE(LastChangeDate, CURRENT_TIMESTAMP), 
  'Op',
...
于 2012-09-27T19:06:21.893 回答
0

[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 进行防御性数据库编程:亚马逊Red Gate - PDF)的第 192 - 199 页。

于 2012-09-27T19:21:15.240 回答