Сохранить попытки обновления во временной таблице в триггере обновления - PullRequest
2 голосов
/ 01 сентября 2010

Запрос - Ни один пользователь не должен иметь возможность изменять цены на продукты Таблица.Сообщение будет отображаться пользователю.также все попытки изменить цену должны быть сохранены во временной таблице.

Как решить эту проблему, используя триггер обновления в Sql server 2005?Я попробовал, как показано ниже.Он работает как положено, но также показывает ошибку -

Транзакция завершилась в триггере.Пакет был прерван.

ALTER TRIGGER tr_Products_U ON dbo.ProductDemo AFTER UPDATE
AS
    DECLARE @Data VARCHAR(200),
            @sProductName NVARCHAR(40), 
            @mOldPrice MONEY, 
            @mNewPrice MONEY,
            @ProductId int

    IF UPDATE(ListPrice)
    BEGIN
        SELECT 
            @ProductId = d.ProductID,    
            @sProductName = d.Name,
            @mOldPrice = d.ListPrice,
            @mNewPrice = i.ListPrice
        FROM
            inserted i INNER JOIN deleted d ON i.ProductID = d.ProductID 

        SET @Data = 'Tried to update the price of ' + @sProductName 
            + '  [ProductID :' + CONVERT(VARCHAR(10), @ProductId) + '] '
            + ' from '
            + CONVERT(VARCHAR(10), @mOldPrice) 
            + ' to ' + CONVERT(VARCHAR(10), @mNewPrice)

            print 'Can''t Change Price' 
                       ROLLBACK TRAN 

                        INSERT INTO #UpdateLIstPrices  
                        VALUES (@Data);         
     END
    RETURN
GO

Ответы [ 2 ]

2 голосов
/ 01 сентября 2010

Вместо того, чтобы записывать это как триггер AFTER, который пытается откатить плохое изменение, я бы подошел к нему как к триггеру INSTEAD OF, который регистрирует любые попытки обновления цены, но разрешает обновления для других столбцов.

    ALTER TRIGGER tr_Products_U ON dbo.ProductDemo INSTEAD OF UPDATE
    AS   
        IF UPDATE(ListPrice)
        BEGIN    
            PRINT 'Can''t Change Price' 

            INSERT INTO #UpdateLIstPrices  
                SELECT 'Tried to update the price of ' + d.Name 
                       + '  [ProductID :' + CONVERT(VARCHAR(10), d.ProductId) + '] '
                       + ' from '
                       + CONVERT(VARCHAR(10), d.ListPrice) 
                       + ' to ' + CONVERT(VARCHAR(10), i.ListPrice)
                    FROM inserted i
                        INNER JOIN deleted d 
                            ON i.ProductID = d.ProductID   
         END
         ELSE
         BEGIN
             UPDATE pd
                 SET Name = i.Name
                     /*, other columns as needed */
                 FROM inserted i
                     INNER JOIN dbo.ProductDemo pd
                         ON i.ProductID = pd.ProductID
         END
        RETURN
    GO
1 голос
/ 02 сентября 2010

Вы можете избежать сообщения об ошибке, поместив UPDATE в блок TRY / CATCH. Это также позволит вам сообщать об ошибках, которые вы не хотите подавлять. Например, вы можете попробовать это:

BEGIN TRY
    UPDATE ProductDemo
    SET ListPrice = 100.00
    WHERE ProductID = 3
END TRY

BEGIN CATCH
    IF ERROR_NUMBER() <> 3609
    BEGIN
        DECLARE @errormessage nvarchar(500)
        DECLARE @errorstate INT
        DECLARE @errorseverity INT

        SET @errormessage = 'Error ' + CAST(error_number() AS nvarchar) + ':  ' + error_message()
        SET @errorstate = error_state()
        SET @errorseverity = error_severity()

        RAISERROR (@errormessage, @errorseverity, @errorstate)
    END
END CATCH

У вас есть еще одна проблема с триггером. Это не предвидит ситуацию, когда несколько строк обновляются одним оператором UPDATE. Когда вы сохраняете столбцы из таблиц inserted и deleted в переменные, вы потеряете информацию из всех строк, кроме последних строк, возвращенных в наборе результатов. Вы можете избежать этой ситуации, заменив свои операторы SELECT, SET и INSERT одним оператором INSERT INTO... SELECT FROM.

PRINT 'Can''t Change Price' 

INSERT INTO #UpdateLIstPrices  
SELECT 'Tried to update the price of ' + d.Name 
            + '  [ProductID :' + CONVERT(VARCHAR(10), d.ProductId) + '] '
            + ' from '
            + CONVERT(VARCHAR(10), d.ListPrice) 
            + ' to ' + CONVERT(VARCHAR(10), i.ListPrice)
FROM inserted i
INNER JOIN deleted d ON i.ProductID = d.ProductID 
...