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

发布于 2024-09-17 20:56:58 字数 1178 浏览 1 评论 0原文

查询是 - 任何用户都不应能够更改产品表的价格。应向用户显示一条消息。此外,所有更改价格的尝试都应保存在临时表中。

如何使用 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

The query is -
No user should be able to change prices of the products Table. A msg shold be displayed to the user. also all attempts to change the price should be saved in temp table.

How to solve this using update trigger in Sql server 2005?
I have tried as below. It is working as expected but also showing an error -

The transaction ended in the trigger. The batch has been aborted.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

只怪假的太真实 2024-09-24 20:56:58

我不会将其编写为尝试回滚错误更改的 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

Rather than writing this as an AFTER trigger that tries to rollback the bad change, I would approach this as an INSTEAD OF trigger that logs any attempted update to price but allows updates to other columns.

    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
心房的律动 2024-09-24 20:56:58

您可以通过将 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 表中的列保存到变量时,您将丢失除结果集中返回的最后一行之外的所有行的信息。您可以通过将 SELECTSETINSERT 语句替换为单个 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 

You can avoid the error message by wrapping your UPDATE in a TRY/CATCH block. This will also allow you to report errors that you do not want to suppress. For example, you may want to try this:

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

You do have another issue with the trigger. It doesn't anticipate the situation where multiple rows are updated with a single UPDATE statement. When you save columns from the inserted and deleted tables to variables, you will lose information from all rows except the last rows returned in the result set. You can avoid this situation by replacing your SELECT, SET and INSERT statements with a single INSERT INTO... SELECT FROM statement.

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 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文