By: Daniel Farina
Overview
Continuing with the model from the previous chapter, now we are going to use a trigger that fires when an update statement is executed.
Sample Test Scenario
As you may remember from previous chapters, triggers that handle update statements differ between those that only deal with insert statements, because they make use of deleted pseudo table as well. This is because an update statement can be considered as a delete followed by an insert.
But having both the deleted and inserted tables at your disposal does not mean that you have to always use them. As you will see in the next sample, we will create a trigger that handles update events to disallow updates on items from orders that were already processed. You will find this trigger very similar to the one we made in the previous chapter to handle insert statements.
CREATE TRIGGER TR_U_PurchaseOrderDetail ON dbo.PurchaseOrderDetail FOR UPDATE AS IF EXISTS ( SELECT 0 FROM dbo.PurchaseOrderHeader POH INNER JOIN Inserted I ON I.PurchaseOrderID = POH.PurchaseOrderID WHERE POH.IsProcessed = 'Y') BEGIN ; THROW 51000, 'Purchase Order Items can only be updated before processing order ', 1; END;
Now let's see the actual items on PurchaseOrderHeader and PurchaseOrderDetail tables so we can test our trigger.
Let's see what happens when we try to update an approved purchase order, like order number 1.
UPDATE dbo.PurchaseOrderDetail SET OrderQty = 2 WHERE PurchaseOrderID = 1 AND PurchaseOrderDetailID = 1
As you can see in the image below the update fails with an error message saying that "Purchase Order Items can only be updated before processing order".
Now let's see what happens when we update items on a purchase order that has not been approved yet, like purchase order number 3.
UPDATE dbo.PurchaseOrderDetail SET OrderQty = 2 WHERE PurchaseOrderID = 3 AND PurchaseOrderDetailID = 4
On the image below we can see that there were no errors and one row was affected.
Finally, if we query the PurchaseOrderHeader and PurchaseOrderDetail tables we can see that the quantity for item 4 in order 3 was changed.
Using the deleted table in a UPDATE trigger
Suppose that we have to check that in case an item's price is updated, the new price cannot be lower than 90 percent of the previous price. In other words, only 10 percent discounts are allowed. In order to code this we only need to add an IF block to our trigger.
ALTER TRIGGER TR_U_PurchaseOrderDetail ON dbo.PurchaseOrderDetail FOR UPDATE AS IF EXISTS ( SELECT 0 FROM dbo.PurchaseOrderHeader POH INNER JOIN Inserted I ON I.PurchaseOrderID = POH.PurchaseOrderID WHERE POH.IsProcessed = 'Y' ) BEGIN THROW 51000, 'Purchase Order Items can only be updated before processing order ', 1; END; IF EXISTS ( SELECT 0 FROM Inserted I INNER JOIN Deleted D ON D.PurchaseOrderDetailID = I.PurchaseOrderDetailID WHERE I.UnitPrice < D.UnitPrice * 0.9 ) BEGIN THROW 51000, 'Only up to 10% discount price is allowed', 1; END; GO
In the code you will see that we can join inserted and deleted pseudo tables to compare the change in the data with the execution of the update statement.
Let's try to update the unit price of apples (PurchaseOrderDetailID = 4) in purchase order number 3, which is $20 and try to set it to $5.
UPDATE dbo.PurchaseOrderDetail SET UnitPrice = 5 WHERE PurchaseOrderID = 3 AND PurchaseOrderDetailID = 4;
As you can see in the image below we see an error message telling us that discounts are only allowed up to 10 percent.
Since apples have a unit price of $20, we cannot update the price to a value lower than $18. Let's try to set its price to $19.
UPDATE dbo.PurchaseOrderDetail SET UnitPrice = 19 WHERE PurchaseOrderID = 3 AND PurchaseOrderDetailID = 4;
In the image below we can see that we were able to change the price.
Additional Information
- SQL Server Trigger After Update for a Specific Value
- Create a Simple SQL Server Trigger to Build an Audit Trail
Last Update: 8/2/2021