updating multiple tables with triggers - SQL Server - sql-server

I need to update my tableA based on the insertions in tableB. i have created a trigger which fires when a row is inserted into tableB and simply copies it to tableA (which is exactly what i want). But the problem comes when i update my existing records in tableB, the rows in tableA already exist with the same primary key.
to deal with it, i tried to delete the existing row in tableA where the primary key matches for the updated row and then simply insert the row from the "inserted" table. But, tsql simply does not let me delete me from a trigger and gives an error stating "The multi-part identifier "INSERTED.Id" could not be bound."
Here is what i am trying to accomplish code-wise:
delete from dbo.CurrentItems where dbo.CurrentItems.CurrentItemId = INSERTED.Id
INSERT INTO CurrentItems
SELECT * FROM INSERTED
WHERE IsActive = 1
Any ideas guys?

In the DELETE FROM statement, you have to add the INSERTED pseudo-table to the tables you're operating on (in the FROM clause), like so:
DELETE dbo.CurrentItems
FROM dbo.CurrentItems
, INSERTED
WHERE dbo.CurrentItems.CurrentItemId = INSERTED.Id
INSERT INTO CurrentItems
SELECT * FROM INSERTED
WHERE IsActive = 1
Alternatively, you could use an INNER JOIN:
DELETE dbo.CurrentItems
FROM dbo.CurrentItems CI
INNER JOIN INSERTED I ON CI.CurrentItemId = I.Id

Why can't you just simply update the existing rows in TableA when your rows in TableB get updated?? UPDATE instead of DELETE/INSERT.
You could have a AFTER INSERT trigger which does what you want now, plus an AFTER UPDATE trigger which would be updating rows in TableA (instead of inserting new ones).

You said you have a trigger that fires when "a row is inserted into tableB". So you have the trigger to fire on Inserts. It sounds to me like you also have the trigger to fire on Updates as well. Did you want the trigger to fire on updates as well? If not, remove "Update" from the trigger definition.
Randy

Related

Why trigger is doing unnecessary subtraction after a query in sql?

I have two tables:
Order and
Product.
I want a specific column(OnShelfQuantity) in the Product table to be updated as a new row is added in the Order table. I have used the below query to implement a trigger which will do that. But the problem is that when I insert a row in the Order table and then later check the Product table to see the changes, I notice that the Product table has been updated 3 times. For e.g: Order quantity inserted = 10, then only 10 should be subtracted from Product_TAB.OnShelfQuantity. But 30 gets subtracted. Please help!
create trigger dbo.Trigge
ON dbo.Ordertable
AFTER INSERT
AS
BEGIN
update Product_TAB set OnShelfQuantity= Product_TAB.OnShelfQuantity - Ordertable.Quantity
FROM dbo.Product_TAB
INNER JOIN Ordertable
ON Ordertable.ProductID = Product_TAB.ProductID;
END;
I think, you can use INSERTED table to resolve this Issue.
Inserted table is a table which is used by triggers to store the frequently inserted records in the tables.
So, you can use the same in your update statement to avoid this.
update Product_TAB set OnShelfQuantity= Product_TAB.OnShelfQuantity -
Ordertable.Quantity
FROM dbo.Product_TAB
INNER JOIN Ordertable ON Ordertable.ProductID = Product_TAB.ProductID
INNER JOIN inserted INS ON INS.Order_ID=Ordertable.Order_ID
You can have multiple rows in the inserted table. And, these rows could have the same product. A row in the target table is only updated once in an update statement. Hence, you want to aggregate the data before the update:
create trigger dbo.Trigge
ON dbo.Ordertable
AFTER INSERT
AS
BEGIN
update p
set OnShelfQuantity= p.OnShelfQuantity - i.total_quantity
from dbo.Product_TAB p JOIN
(SELECT i.ProductId, SUM(i.Quantity) as total_quantity
FROM inserted i
GROUP BY i.ProductId
) i
on i.ProductID = p.ProductID;
END;
Note that this only uses inserted and not the original table.
So the issue was that I was inserting new rows but with the same Order ID. This is why it was doing additional subtraction which I didn't require. So now I have to just insert a new row but with unique OrderID. Thanks to everyone who replied above!

Display Results Before Delete SQL Server

I'm so close to getting the answer to this, but I feel like I'm missing the final part.
I've created a DELETE trigger that should display values from the SELECT statement before they are deleted from the table. However, when the trigger is called I get a blank result, but the values (order_id=10001 AND product_id=25) are still deleted from the table.
I've verified the SELECT statement works before I've run the trigger, so I'm confident that part is correct.
I've tried using an INSTEAD OF DELETE trigger, but the values end up not being deleted. I don't believe there is a BEFORE DELETE function for SQL Server? Is there a work around?
Suggestions?
CREATE TRIGGER deleteOrderTrigger
ON order_details
FOR DELETE
AS
SELECT order_details.product_id, products.name,
order_details.quantity AS 'Quantity being deleted from order',
SUM(products.quantity_in_stock) + order_details.quantity AS 'In Stock Quantity after Deletion'
FROM order_details
LEFT JOIN products ON products.product_id = order_details.product_id
WHERE order_details.order_id = 10001 AND products.product_id = 25
GROUP BY order_details.product_id, products.name, order_details.quantity
GO
-- Below is the code that will fire the trigger
DELETE order_details
WHERE order_id = 10001 AND product_id = 25
#JoeC - using a proc is probably the best answer.
If you must use a trigger then remmeber that it must be coded to support sets. If someone executes delete order_details where order_id = 10001 then your trigger will need to return the stock level for every product on the order.
Also, when coding a trigger, you have access to a built in table named deleted. This table contains the records deleted.
So you can do something like this:
CREATE TRIGGER deleteOrderTrigger
ON order_details
FOR DELETE
AS
INSERT INTO deleted_order_products_log
SELECT order_details.product_id
,products.name
,[Quantity being deleted from order] = order_details.quantity
,[In Stock Quantity after Deletion] = SUM(products.quantity_in_stock) + order_details.quantity
FROM order_details
INNER JOIN deleted d
ON order_details.primaryKey = d.primaryKey
LEFT JOIN products
ON products.product_id = order_details.product_id
GROUP BY order_details.product_id
,products.name
,order_details.quantity;
You can then query the log file to get the results of the calculation.
I haven't used triggers a lot, but it seems you have an AFTER trigger, which is not able to read the deleted rows, that's why you get blank result.
The thing with triggers are the inserted and deleted tables, maybe this would help: https://learn.microsoft.com/en-us/sql/relational-databases/triggers/use-the-inserted-and-deleted-tables
You need a INSTEAD OF trigger as you mentioned, but you have to do the delete operation yourself. More on this subject here: https://learn.microsoft.com/en-us/sql/relational-databases/triggers/dml-triggers and one example in here: https://stackoverflow.com/a/3267726/5605866
Put the trigger results into an audit table and you will see the results of the trigger. I have never seen a trigger with a where clause similar to yours.
Do a insert into table x select.... You also want to use the deleted table(there is an inserted table) that is created just for each occurrence of the trigger that will contain any/all of the rows that were just deleted. The delete occurs in the main body of the code. The trigger is then invoked and the deleted table (you can do a delete * from deleted only in the trigger) that will contain the row(s) that were deleted.

Adding modify and delete to insert trigger

I've been tasked with pushing records from one table (T1) to another (T2). I have the insert portion complete as follows:
CREATE TRIGGER [dbo].[CP_to_TW2]
ON [dbo].[TEST_PROJ]
FOR INSERT
AS
BEGIN
INSERT INTO dbo.TEST_TW (PROJECT_ID,PROJECT_DESC,PROJECT_MANAGER)
SELECT PROJ_ID,PROJ_ID+PROJ_NAME,PROJECT_MANAGER FROM inserted
END
TEST_PROJ is T1 and TEST_TW is T2. The PROJECT_ID and PROJ_ID columns store the unique IDs. The trigger fires correct and inserts corresponding rows into T2. However, I am unsure how to get modifications made to T1 to show in T2. For example, if the Project manager is updated in T1 it needs to also update in T2. In addition to this, I am unsure how to make that records in T2 are deleted when they are deleted in T1. Any help would be greatly appreciated.
You can create triggers also for delete or update ops, in update you have deleted table in addition to inserted
CREATE TRIGGER [dbo].[CP_to_TW2]
ON [dbo].[TEST_PROJ]
AFTER UPDATE
AS
BEGIN
UPDATE TEST_TW....
END
CREATE TRIGGER [dbo].[CP_to_TW2]
ON [dbo].[TEST_PROJ]
AFTER DELETE
AS
BEGIN
DELETE FROM dbo.TEST_TW (PROJECT_ID,PROJECT_DESC,PROJECT_MANAGER)
WHERE xxx in (SELECT xxx FROM deleted)
END

update statement inside Trigger not updating all the rows in SQL server 2008

I have two table.table 1 have the update trigge it will update the detail in table. but table have many rows with same key in table1.(key in table1 is primarykey but in table 2 it is foriegn key). Update trigger updating only one row in The table2 not updating the all row having same key.
Update table2 set colu1 = "value" where colu2 = primarykey
Without knowing much about your tables I think you want something like this:
CREATE TRIGGER Table1Trigger ON table1
AFTER UPDATE AS
IF UPDATE(col)
BEGIN
UPDATE table2
SET colu1 = 'value'
FROM table2
INNER JOIN inserted ON table2.colu2 = inserted.[key]
END
This will change the value of colu1 in table2 to 'Value' for all rows that has a key value that corresponds to the key value of the rows that were updated in table1 if the update change column col. You probably have to change the column names to match whatever your table looks like.

How do I make a trigger that only affects the row that was updated/inserted?

I have a table with two columns where I need one (columnB) to be a copy of the other one (columnA). So, if a row is inserted or updated, I want the value from columnA to be copied to columnB.
Here's what I have now:
CREATE TRIGGER tUpdateColB
ON products
FOR INSERT, UPDATE AS
BEGIN
UPDATE table
SET columnB = columnA
END
The problem now is that the query affects all rows, not just the one that was updated or inserted. How would I go about fixing that?
Assuming you have a primary key column, id, (and you should have a primary key), join to the inserted table (making the trigger capable of handling multiple rows):
CREATE TRIGGER tUpdateColB
ON products
FOR INSERT, UPDATE AS
BEGIN
UPDATE table
SET t.columnB = i.columnA
FROM table t INNER JOIN inserted i ON t.id = i.id
END
But if ColumnB is always a copy of ColumnA, why not create a Computed column instead?
Using the inserted and deleted Tables
There is a special inserted table available in triggers that will contain the "after" version of rows impacted by an INSERT or UPDATE operation. Similarly, there is a deleted table that will contain the "before" version of rows impacted by an UPDATE or DELETE operation.
So, for your specific case:
UPDATE t
SET t.columnB = t.columnA
FROM inserted i
INNER JOIN table t
ON i.PrimaryKeyColumn = t.PrimaryKeyColumn

Resources