触发更新和插入失败后

时间:2019-05-01 10:58:44

标签: sql-server tsql

我正在编写一个触发器,用于为一张表的插入和更新记录保留审计记录。

CREATE TABLE [dbo].[AppLog](
[TableName] [varchar](32) NOT NULL,
[ColumnName] [varchar](32) NOT NULL,
[RecordId] [varchar](20) NOT NULL,
[OldValue] [varchar](2000) NULL,
[NewValue] [varchar](2000) NULL,
[UpdatedBy] [varchar](200) NULL,
[UpdatedOn] [datetime] NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Persons](
[Personid] [int] IDENTITY(1,1) NOT NULL,
[LastName] [varchar](255) NOT NULL,
[FirstName] [varchar](255) NULL,
[Age] [int] NULL
) ON [PRIMARY]
GO

CREATE TRIGGER AuditRecord ON dbo.Persons
AFTER UPDATE, INSERT
AS

INSERT INTO AppLog
    (TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,UpdatedBy ,UpdatedOn )
        SELECT 'Persons', 'LastName', COALESCE(i.Personid,NULL), 
                                    d.LastName, i.LastName, CURRENT_USER, GETDATE()
            FROM Persons pv
            LEFT JOIN INSERTED i ON pv.Personid = i.Personid
            LEFT JOIN DELETED d ON pv.Personid = d.Personid;
GO

INSERT INTO Persons (FirstName,LastName,age)
VALUES ('Satish','Parida',40);

INSERT INTO Persons (FirstName,LastName,age)
VALUES ('SKP','Tada',90);

最后一次插入失败,因为它试图将null插入applog表中的recordid列,有人可以解释或解决此问题。

3 个答案:

答案 0 :(得分:0)

失败的语句如下:

INSERT INTO Persons (FirstName,LastName,age)
VALUES ('SKP','Tada',90); 

这是因为在触发器中,您使用Persons是您的“基本”表,并且对LEFT JOINinserted都执行了deleted。结果,当您尝试执行上述INSERT时,触发器的数据集中也会使用前一个INSERT的值。第二个人'Parida'中没有人inserted出现在表INSERT中,因此COALESCE(i.Personid,NULL)返回NULL;正如我在评论中提到的那样,使用COALESCE返回NULL毫无意义,就好像一个表达式的值求值为NULL时它将返回NULL。由于RecordID(正在插入COALESCE(i.Personid,NULL)的值)不能具有值NULL,因此INSERT将失败,整个交易将回滚。

我怀疑您想要的触发器如下:

CREATE TRIGGER AuditRecord ON dbo.Persons
AFTER UPDATE, INSERT
AS BEGIN
    INSERT INTO AppLog (TableName,
                        ColumnName,
                        RecordId,
                        OldValue,
                        NewValue,
                        UpdatedBy,
                        UpdatedOn)
    SELECT 'Persons',
           'LastName',
           i.Personid,
           d.LastName,
           i.LastName,
           CURRENT_USER,
           GETDATE()
    FROM inserted AS i
         LEFT JOIN deleted AS d ON i.Personid = d.Personid;
END;

inserted对于UPDATEINSERT总是至少有1行。 inserted不能用于DELETE,但是您的触发器不会在该DML事件上触发,因此使用inserted作为“基本”表似乎是正确的选择。

答案 1 :(得分:0)

以下代码应该可以工作

CREATE TABLE [dbo].[AppLog](
[TableName] [varchar](32) NOT NULL,
[ColumnName] [varchar](32) NOT NULL,
[RecordId] [varchar](20) NOT NULL,
[OldValue] [varchar](2000) NULL,
[NewValue] [varchar](2000) NULL,
[UpdatedBy] [varchar](200) NULL,
[UpdatedOn] [datetime] NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Persons](
[Personid] [int] IDENTITY(1,1) NOT NULL,
[LastName] [varchar](255) NOT NULL,
[FirstName] [varchar](255) NULL,
[Age] [int] NULL
) ON [PRIMARY]
GO

CREATE TRIGGER AuditRecord ON dbo.Persons
AFTER UPDATE, INSERT
AS

if exists(SELECT * from inserted) and exists (SELECT * from deleted)
BEGIN

    INSERT INTO AppLog
    (TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,UpdatedBy ,UpdatedOn )
        SELECT 'Persons', 'LastName', COALESCE(i.Personid,NULL), 
                                    d.LastName, i.LastName, CURRENT_USER, GETDATE()
            FROM Persons pv
             INNER JOIN INSERTED i ON pv.Personid = i.Personid
            INNER JOIN DELETED d ON pv.Personid = d.Personid;

END
If exists (Select * from inserted) and not exists(Select * from deleted)
begin


            INSERT INTO AppLog
    (TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,UpdatedBy ,UpdatedOn )
        SELECT
    'Persons', 'LastName',i.Personid,NULL,i.LastName,CURRENT_USER,GETDATE()
FROM
    inserted AS i


END

GO



INSERT INTO Persons (FirstName,LastName,age)
VALUES ('Satish','Parida',40);

INSERT INTO Persons (FirstName,LastName,age)
VALUES ('SKP','Tada',90);

INSERT INTO Persons (FirstName,LastName,age)
VALUES ('abc','def',90);

INSERT INTO Persons (FirstName,LastName,age)
VALUES ('gg','hh',90);

UPDATE dbo.Persons SET LastName='Paridachanged' WHERE Personid=1


SELECT * FROM Persons
SELECT * FROM AppLog

答案 2 :(得分:0)

USE KnockKnockDev;
GO
IF OBJECT_ID('dbo.AuditRecord', 'TR') IS NOT NULL
DROP TRIGGER dbo.AuditRecord;
GO
CREATE TRIGGER AuditRecord ON dbo.Persons
AFTER UPDATE, INSERT, DELETE
AS
DECLARE @Action as char(1)
DECLARE @Count as int
DECLARE @TableName as char(32)
DECLARE @ColumnName as char (32)

SET @TableName = 'Persons'
SET @ColumnName = 'LastName'
SET @Action = 'I'               -- Set Action to 'I'nsert by default.

SELECT @Count = COUNT(*) FROM DELETED

IF @Count > 0 
BEGIN
    SELECT @Count = COUNT(*) FROM INSERTED
    IF @Count > 0
        SET @Action = 'U'       -- Set Action to 'U'pdated.
    ELSE
        SET @Action = 'D'       -- Set Action to 'D'eleted.
END

IF @Action = 'I'
BEGIN
    INSERT INTO AppLog
    (TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,Action ,UpdatedBy ,UpdatedOn )
        SELECT @TableName, @ColumnName, Personid, 
                                    NULL, LastName, @Action, CURRENT_USER, GETDATE()
            FROM INSERTED;
END

ELSE IF @Action = 'D'
BEGIN
    INSERT INTO AppLog
    (TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,Action ,UpdatedBy ,UpdatedOn )
        SELECT @TableName, @ColumnName, Personid, 
                                    LastName, NULL, @Action, CURRENT_USER, GETDATE()
            FROM DELETED;
END

ELSE
BEGIN
    INSERT INTO AppLog
        (TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,Action ,UpdatedBy ,UpdatedOn )
            SELECT @TableName, @ColumnName, i.Personid, 
                                        d.LastName, i.LastName, @Action, CURRENT_USER, GETDATE()
                FROM Persons pv
                INNER JOIN INSERTED i ON pv.Personid = i.Personid
                INNER JOIN DELETED d ON pv.Personid = d.Personid;
END
GO