Reputation: 41
I need to create a trigger which inserts into another table information about price changes. Below I present my solution.
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
Everything is OK when I update only one record. The problem is when I try to update many records, then I see the error below:
Msg 512, Level 16, State 1, Procedure trig1, Line 41
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. The statement has been terminated.
Does anyone know how to fix this problem?
Upvotes: 0
Views: 70
Reputation: 69494
The trigger is fired for each Update statement not for each row in an update statement. You do not need any of these variables at all, just select data (old and New) data from inserted
and deleted
tables and insert it into the audit table directly, something like this........
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
Upvotes: 2
Reputation: 82474
The problem is that Triggers are fired on a statement bases, and not on a row bases. This means that your trigger is fired once for all the rows updated in your statement, so the inserted
and deleted
tables might contain more than one row.
However, your trigger code does not take that into consideration, thus raising an error.
Try this instead:
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
Upvotes: 2