После триггера для обновления и сбоя вставки - PullRequest
0 голосов
/ 01 мая 2019

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

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

Ответы [ 3 ]

0 голосов
/ 01 мая 2019

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

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 голосов
/ 02 мая 2019
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 голосов
/ 01 мая 2019

Утверждается следующее утверждение:

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 в качестве «базовой» таблицы кажется правильным выбором.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...