sql >> Databasteknik >  >> RDS >> Sqlserver

Hur man förhindrar uppdateringar av en tabell, med undantag för en situation

Varför inte använda en INSTEAD OF utlösa? Det kräver lite mer arbete (nämligen en upprepad UPDATE uttalande) men varje gång du kan förhindra arbete, istället för att låta det hända och sedan rulla tillbaka det, kommer du att ha det bättre.

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

Det här passar inte perfekt. Kriterierna jag har utelämnat utelämnas av en anledning:det kan vara komplicerat att avgöra om ett kolumnvärde har ändrats, eftersom det beror på datatypen, om kolumnen kan vara NULL, etc. AFAIK den inbyggda triggern fungerar kan bara avgöra om en viss kolumn angavs, inte om värdet faktiskt ändrades från tidigare.

REDIGERA med tanke på att du bara är orolig för de andra kolumnerna som uppdateras på grund av efterutlösaren, tror jag följande INSTEAD OF trigger kan ersätta båda dina befintliga triggers och även hantera flera rader uppdaterade samtidigt (vissa utan att uppfylla dina kriterier):

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



  1. MySQL Fråga för att välja data från förra veckan?

  2. Få kuvert, dvs överlappande tidsintervall

  3. Fråga för att ta bort unik eller primär nyckel från MYsql-tabellen

  4. MySQL-funktion för att hitta antalet arbetsdagar mellan två datum