如何在Master-Detail上进行触发

时间:2016-08-03 13:26:14

标签: sql-server tsql sql-server-2014 database-trigger

我有以下情况:

CREATE TABLE dbo.Orders
(  
    OrderID int IDENTITY (1,1) NOT NULL  
  , OrderVersion int DEFAULT(1)
  , Customer varchar(30)
  , ScheduleDate date
  , PaymentOption int
);  

CREATE TABLE dbo.OrdersItems
(  
    OrderItemsID int IDENTITY (1,1) NOT NULL  
  , OrderID  int
  , Product  varchar(100)
  , Qty      int 
  , value    decimal(18,2)
);  

CREATE TABLE dbo.logOrders
(  
    OrderID int NOT NULL  
  , OrderVersion int DEFAULT(1)
  , Customer varchar(30)
  , ScheduleDate date
  , PaymentOption int
);  

CREATE TABLE dbo.logOrdersItems
(  
    OrderItemsID int NOT NULL  
  , OrderID  int
  , Product  varchar(100)
  , Qty      int 
  , value    decimal(18,2)
); 

-- Insert values into the table.  
INSERT INTO dbo.Orders (Customer , ScheduleDate, PaymentOption)  
VALUES ('John', 2016-09-01, 1);  

INSERT INTO dbo.OrdersItems( OrderId, Product, Qty, Value)
VALUES (1, 'Foo', 20, 35.658), 
       (1, 'Bla', 50, 100)
       (1, 'XYZ', 10, 3589)

第一声明

UPDATE Orders set ScheduleDate = 2016-10-05 WHERE OrderId = 1

第二声明

Delete From OrdersItems WHERE OrderItemsID = 2
UPDATE OrdersItems set Qty = 5 WHERE OrderItemsID = 1

第三声明

Update Orders set PaymentOption = 2 WHERE OrderId = 1
Update OrdersItems set Value = 1050 WHERE OrderItemsID = 3

我试图弄清楚如何在日志上的每个语句示例之后触发,在日志表上更改之前的数据。并在表订单上将OrderVersion设置为OrderVersion + 1。 因此,在日志表中,我将在后一个版本之后拥有所有版本。

是否可以制作单个触发器来监视两个表并在UPDATE,DELETE,INSERT语句之前执行获取原始数据以获取原始数据并在logTables上执行INSERT?

这里有一个示例,可以更好地解释我想要的结果。

This is the Initial Data on table Orders and OrdersItems

如果我对订单进行更新(任何列)或在OrdersItems上进行更新,插入,删除,我需要分别在logTables上插入图像上的数据。 有了这个,我将在logOrders和logItems上有原始数据,在订单和项目上有更改的数据。

我希望我能更好地解释我的意思。

1 个答案:

答案 0 :(得分:0)

您需要两个触发器。 Orders表的触发器处理Orders表更新/删除。 OrdersItems表的触发器对OrdersItems执行相同的操作。触发器如下所示:

对于Orders表:

CREATE TRIGGER dbo.Orders_trigger 
   ON  dbo.Orders 
   AFTER DELETE,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    INSERT INTO dbo.logOrders
    SELECT * FROM DELETED;

    INSERT INTO dbo.logOrdersItems
    SELECT oi.* FROM OrdersItems oi
    WHERE oi.OrderID IN (SELECT OrderId FROM DELETED);

END
GO

对于OrdersItems:

CREATE TRIGGER dbo.OrdersItems_trigger 
   ON  dbo.OrdersItems 
   AFTER DELETE,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    --Inerst the changed/deleted OrdersItems into the log
    INSERT INTO dbo.logOrdersItems
    SELECT * FROM DELETED

    --Inserts the unchanged sibling OrdersItems records into the log
    INSERT INTO dbo.logOrdersItems
    SELECT oi.* FROM OrdersItems oi
    WHERE oi.OrderId IN (SELECT DISTINCT OrderId FROM DELETED)
    AND oi.OrderItemsID NOT IN (SELECT DISTINCT OrderItemsID FROM DELETED);

    INSERT INTO dbo.logOrders
    SELECT o.* FROM Orders o
    WHERE o.OrderID IN (SELECT DISTINCT OrderId FROM DELETED);

END
GO

订单触发器非常简单。使用虚拟DELETED表将原始版本的记录插入日志中。然后加入子OrdersItems记录并将它们插入到日志中。这样写的方式,即使您一次更新或删除多个订单记录也会有效。

OrdersItems触发器有点复杂。您需要记录OrdersItems和Orders Records的预先版本。但是你也希望(我认为)记录未更改的“兄弟”OrdersItems记录,以便你有完整的记录图片。

我知道这只是您的示例数据,但您需要在日志表中的记录中添加某种时间戳。否则你最终会得到一堆重复的行,你无法分辨出哪一行。在触发器的开头,您可以创建一个变量来保存更新日期时间,然后将其附加到日志的INSERT语句中。

DECLARE @UpdateDateTime DATETIME;
SET @UpdateDateTime = GETUTCDATE();