在“更新触发器”中的临时表中保存更新尝试

时间:2010-09-01 07:43:09

标签: sql-server sql-server-2005 triggers

查询是 - 没有用户应该能够更改产品表的价格。向用户显示msg shold。所有改变价格的尝试都应保存在临时表中。

如何使用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 个答案:

答案 0 :(得分:2)

我不会将此写为尝试回滚错误更改的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 :(得分:1)

您可以通过将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语句更新多行的情况。将inserteddeleted表中的列保存到变量时,除了结果集中返回的最后一行之外,您将丢失所有行的信息。您可以使用单个SELECT语句替换SETINSERTINSERT 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