使用有关表更新的日志信息创建触发器

时间:2016-12-27 12:36:02

标签: sql-server

我需要创建一个触发器,将有关价格变化的信息插入另一个表中。下面我提出我的解决方案。

CREATE TABLE Production.Products_AUDIT  
(
    auditid     INT         NOT NULL IDENTITY,
    productid   INT         NULL,
    old_price   MONEY       NOT NULL,
    new_price   MONEY       NOT NULL,

    CONSTRAINT PK_Products_AUDIT PRIMARY KEY(auditid),
    CONSTRAINT FK_Products_AUDIT_AUDIT 
        FOREIGN KEY(productid) REFERENCES Production.Products(productid)
);

INSERT INTO Production.Products_AUDIT VALUES (1, 18 , 20)
INSERT INTO Production.Products_AUDIT VALUES (2, 19 , 31)

DELETE FROM Production.Products_AUDIT

SELECT unitprice 
FROM Production.Products_AUDIT as p1 
INNER JOIN Production.Products as p2 on p1.productid = p2.productid 

CREATE TRIGGER trig1
ON Production.Products
FOR UPDATE
AS
    declare @prodId INT 
    declare @oldPrice MONEY
    declare @newPrice MONEY

    SET @prodId = (SELECT i.productid 
                   FROM inserted as i 
                   INNER JOIN  Production.Products as pp on i.productid = pp.productid )
    SET @oldPrice = (SELECT i.unitprice 
                     FROM deleted as i 
                     INNER JOIN Production.Products as pp on i.productid = pp.productid )

    SET @newPrice = (SELECT i.unitprice 
                     FROM inserted as i 
                     INNER JOIN Production.Products as pp on i.productid = pp.productid)

    INSERT INTO Production.Products_AUDIT 
    VALUES(@prodId, @oldPrice, @newPrice)

    UPDATE Production.Products 
    SET unitprice = 45 
    WHERE productid < 2

    SELECT * FROM Production.Products_AUDIT

当我只更新一条记录时,一切都很好。问题是当我尝试更新许多记录时,我看到下面的错误:

  

Msg 512,Level 16,State 1,Procedure trig1,Line 41
  子查询返回的值超过1。当子查询遵循=,!=,&lt;,&lt; =,&gt;,&gt; =或子查询用作表达式时,不允许这样做。该   声明已被终止。

有谁知道如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

问题是触发器是在语句库上触发的,而不是在行基础上触发的。这意味着对语句中更新的所有行触发一次触发器,因此inserteddeleted表可能包含多行。

但是,您的触发器代码不会考虑这一点,从而引发错误。

请改为尝试:

CREATE TRIGGER Products_ForUpdate
ON Production.Products
FOR UPDATE
AS

    INSERT INTO Production.Products_AUDIT 
    SELECT i.productid, d.unitprice, i.unitprice
    FROM inserted as i 
    INNER JOIN  Production.Products as pp on i.productid = pp.productid
    INNER JOIN deleted as d ON pp.productid = d.productid

答案 1 :(得分:2)

为每个Update语句触发触发器,而不是为update语句中的每一行触发。您根本不需要任何这些变量,只需从inserteddeleted表中选择数据(旧的和新的)数据并将其直接插入到审计表中,就像这样...... ...

CREATE TRIGGER trig1
ON Production.Products
FOR UPDATE
as
BEGIN
 SET NOCOUNT ON;

    INSERT INTO Production.Products_AUDIT (productid , Old_Price , New_Price)
    SELECT pp.productid 
         , d.unitprice AS OldPrice
         , i.unitprice AS NewPrice
    FROM Production.Products as pp 
    INNER JOIN inserted i ON i.productid = pp.productid
    INNER JOIN deleted  d ON d.productid = pp.productid 

END