SQL - триггер вставки только тогда, когда пользователь сделал обновление - PullRequest
0 голосов
/ 11 июня 2019

У меня есть таблица customers_accounts, которая отслеживает основную информацию о клиенте в учетной записи.Когда файл клиента открывается, я синхронизирую информацию из внешней системы, чтобы наш пользователь получал самую последнюю информацию.

UPDATE 
    customers_accounts
SET
    first_name = 'bob',
    last_name = 'burger'
WHERE 
    account_number = '12345'

Когда пользователь обновляет учетную запись, я делаю тот же запрос, но я обновляю столбец с указанием последнего пользователя, который внес изменение

UPDATE 
    customers_accounts
SET
    first_name = 'bob',
    last_name = 'burger',
    updated_by = 'H Jon Benjamin',
    updated_on = GETDATE()
WHERE 
    account_number = '12345'

Вот проблема, которую япытаясь решить.Я хочу отслеживать изменения в таблице истории, но регистрировать изменения только в том случае, если они сделаны пользователем, а не из внешней системы.Поэтому я планировал создать триггер, который вставит строку, если пользовательский столбец не пустой на вставке (так как updated_by неявно равен нулю выше в первом обновлении)

Я попробовал следующее:

ALTER trigger [dbo].[Accounts_Customers_LogUpdate] 
ON [dbo].[Accounts_Customers]
AFTER UPDATE
AS
    DECLARE @Now AS DATETIME = GETDATE()
    DECLARE @User AS NVARCHAR(150)

    SELECT @User = (SELECT [updated_by] FROM INSERTED)

    IF (@User IS NOT NULL)
    BEGIN
        SET NOCOUNT ON

        INSERT INTO [dbo].[Accounts_Customers-History]
            SELECT *, @User, @Now
            FROM inserted
    END

Accounts_Customers-History - точная копия таблицы с двумя дополнительными столбцами, change_made_by и change_made_on

Однако, она не ведет себя так, как я ожидал.Он вставляет любое значение в updated_by в change_made_by, независимо от значения updated_by в запросе.Поэтому я получаю зарегистрированную активность, инициированную как пользователем, так и импортом.

1 Ответ

2 голосов
/ 11 июня 2019

Используйте UPDATE() для этого:

Возвращает логическое значение, указывающее, была ли предпринята попытка INSERT или UPDATE для указанного столбца таблицы или представления. UPDATE () используется в любом месте тела триггера INSERT Transact-SQL или UPDATE, чтобы проверить, должен ли триггер выполнять определенные действия.

Это означает, что функция update вернет false для первого оператора обновления в вопросе и true для второго оператора обновления - это именно то, что вам нужно.

Также обратите внимание, что вы всегда должны указывать список столбцов в операторе вставки, а также всегда указывайте список столбцов в операторе выбора. ( Почему? )

Пересмотренная версия вашего триггера может выглядеть примерно так:

ALTER TRIGGER [dbo].[Accounts_Customers_LogUpdate] 
ON [dbo].[Accounts_Customers]
AFTER UPDATE

AS

DECLARE @Now as DateTime = GetDate()
IF UPDATE(updated_by)
BEGIN

    -- Always specify the columns list in an insert statement!
    insert into [dbo].[Accounts_Customers-History] (<Columns list>)
    -- Always specify the columns list in a select statement!
    select <columns list>,  @Now
    from inserted

END

Обратите внимание, что функция UPDATE() не дает никаких указаний на то, что оператор вставки или обновления, вызвавший срабатывание триггера, была успешной, а также не дает указание на то, что значение столбца действительно изменилось - оно только указывает был ли этот столбец частью оператора вставки или обновления, который вызвал триггер - как вы можете прочитать в последнем абзаце раздела примечаний:

Если к столбцу применяется триггер, значение UPDATED будет возвращаться как true или 1, даже если значение столбца остается неизменным. Это в принципе, и триггер должен реализовывать бизнес-логику, которая определяет, допустима ли операция вставки / обновления / удаления.

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