How to prevent updates to a table, with an exception for one situation

前端 未结 1 1028
耶瑟儿~
耶瑟儿~ 2020-12-18 12:16

I have a table that contains records that can become part of a bill. I can tell which ones are already part of a bill because the table has a BillId column that gets updated

相关标签:
1条回答
  • 2020-12-18 13:06

    Why not use an INSTEAD OF trigger? It requires a bit more work (namely a repeated UPDATE statement) but any time you can prevent work, instead of letting it happen and then rolling it back, you're going to be better off.

    CREATE TRIGGER [dbo].[Item_BeforeUpdate_AnyBilled]
    ON [dbo].[Item]
    INSTEAD OF UPDATE
    AS 
    BEGIN
      SET NOCOUNT ON;
    
      IF EXISTS 
      (
         SELECT 1 FROM inserted i
           JOIN deleted AS d ON i.ItemId = d.ItemId
           WHERE d.BillId IS NULL -- it was NULL before, may not be NULL now
      )
      BEGIN
         UPDATE src 
           SET col1 = i.col1 --, ... other columns
              ModifiedDate = CURRENT_TIMESTAMP -- this eliminates need for other trigger
           FROM dbo.Item AS src
           INNER JOIN inserted AS i
           ON i.ItemId = src.ItemId
           AND (criteria to determine if at least one column has changed);
      END
      ELSE
      BEGIN
         RAISERROR(...);
      END
    END
    GO
    

    This doesn't fit perfectly. The criteria I've left out is left out for a reason: it can be complex to determine if a column value has changed, as it depends on the datatype, whether the column can be NULL, etc. AFAIK the built-in trigger functions can only tell if a certain column was specified, not whether the value actually changed from before.

    EDIT considering that you're only concerned about the other columns that are updated due to the after trigger, I think the following INSTEAD OF trigger can replace both of your existing triggers and also deal with multiple rows updated at once (some without meeting your criteria):

    CREATE TRIGGER [dbo].[Item_BeforeUpdate_AnyBilled]
    ON [dbo].[Item]
    INSTEAD OF UPDATE
    AS 
    BEGIN
      SET NOCOUNT ON;
    
      UPDATE src SET col1 = i.col1 --, ... other columns,
         ModifiedDate = CURRENT_TIMESTAMP
         FROM dbo.Item AS src
         INNER JOIN inserted AS i
         ON src.ItemID = i.ItemID
         INNER JOIN deleted AS d
         ON i.ItemID = d.ItemID 
         WHERE d.BillID IS NULL; 
    
      IF @@ROWCOUNT = 0
      BEGIN
        RAISERROR(...);
      END
    END
    GO
    
    0 讨论(0)
提交回复
热议问题