Я пишу триггер для ведения записи аудита для одной таблицы для записей вставки и обновления.

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 в recordid в таблице applog, может кто-то объяснить или устранить проблему.

0
satish kumar Parida 1 Май 2019 в 13:58

3 ответа

Лучший ответ

Утверждение, которое терпит неудачу, является тем ниже:

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

Это потому, что в вашем Триггере вы используете Persons - это ваша "базовая" таблица и выполняете LEFT JOIN для inserted и 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 всегда будет содержать хотя бы 1 строку для UPDATE или INSERT. inserted не подходит для DELETE, но ваш триггер не сработает в этом событии DML, поэтому использование inserted в качестве «базовой» таблицы кажется правильным выбором.

0
Larnu 1 Май 2019 в 11:15

Следующий код должен работать

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
0
Ketan Kotak 1 Май 2019 в 11:44
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
0
satish kumar Parida 2 Май 2019 в 05:28