I have a movies table with columns id, title, inventory and I added a column rental_count. I've found solutions online to increment rental_count after the row is updated but would it be possible to increment the rental count only when the inventory gets decremented (when someone rents something)?
Create trigger trigUpdateRentalCount
On Movies for Update
As
if Exists( Select * from inserted I
Join deleted d
On d.pk = i.pk
Where i.inventory = d.inventory - 1)
Update m Set rental_count += 1
From Movies m
join (inserted i Join deleted d
on i.pk = d.Pk
and i.inventory = d.inventory - 1)
on i.PK = m.PK
EDIT to explain trigger. In any trigger, the user has access to the set of rows being deleted or updated(with the old values) by the sql statement that caused the trigger to fire. This set can be accessed using the keyword deleted.
It also has access to all the rows being inserted or updated (with the new updated values), using the keyword inserted.
So if there exists any rows in the deleted table which match to a row in the inserted table, where the new inserted value for inventory is one less than the old value, then, for each such row, you want to update(increment) the rental_count field.
The trigger relies on an If Exists statement to determine if any such rows exist in inserted and deleted. Then if there are any, it increments the rental_count value in the matching row in the Movies table.
Related
I am creating a trigger whenever a purchase event gets inserted or updated in the PurchaseEvent table below.
The actual product count (completed purchases) is currently not tracked in a table, it is dynamically calculated each time by performing a SUM on the PurchaseEvent table like:
SELECT SUM(Quantity) FROM PurchaseEvent WHERE ProductID = #ProductID and PurchaseStatus = 'COMPLETED'
Below is the main PurchaseEvent table and the new table I just created:
PurchaseEvent
- PurchaseEventID
- ProductID
- Quantity
- PurchaseStatus ( COMPLETED, CANCELLED)
ProductCount
- ProductID
- ProductCount
I am creating a trigger to handle the insert or update events.
A row can be updated to change the PurchaseStatus.
CREATE TRIGGER trg_UpdateProductCount
ON PurchaseEvent
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON
// TODO
END
Since a trigger can be run for a single record or multiple, what is the best way to handle this?
I was thinking:
UPDATE pc
SET rc.PurchaseCount = rc.PurchaseCount + SUM(i.ProductID)
FROM PurchaseCount pc
INNER JOIN Inserted i ON i.ProductID = pc.ProductID
WHERE i.PurchaseStatus = 'COMPLETED'
But then I have to somehow handle the CANCELLED records also?
Is it possible to just increment/decrement the PurchaseCount table or is the only
way to do this accurately is to SUM the original table each and every time a record is updated/inserted? (and just ignore the records in the INSERTED table)
I am using SQL Management Studio 2012.
I would like to update a field from a table that is not within the Target/Source relationship in a Store Procedure using a TRIGGER to update records from a View ([dbo].ActivityView tv) to an editable table ([dbo].ActivityTracker t). Records fall in and out of the View based on a [COMPLETION] date field. If the [COMPLETION] date value is past the end of the Quarter, it drops out of the View but triggers a "Won't Be Complete" in the Target's [COMPLETION] column. However, when this happens, I can't see when that update timestamp to the [COMPLETION] field took place since it is no longer within the View. The value exists in "THISOTHERTABLE" the View is based off.
Therefore, I would like to update the field in the Target from "THISOTHERTABLE" if possible.
MERGE [dbo].[ActivityTracker] t --TARGET
USING [dbo].[ActivityView] tv --SOURCE
on tv.ID = t.ID
WHEN MATCHED THEN
UPDATE
SET t.ID = tv.ID,
Do Stuff...
WHEN NOT MATCHED BY TARGET THEN
Do Stuff...
WHEN NOT MATCHED BY SOURCE THEN
Set t.TIMESTAMP = (select distinct o.TIMESTAMP from [dbp].THISOTHERTABLE o where t.ID = o.ID) END
"THISOTHERTABLE" has multiple records for the ID field, so I would have to select distinct TIMESTAMP to get only a single value for the unique ID in the TARGET table. However, THISOTHERTABLE already has only the MAX(TIMESTAMP) for TIMESTAMP so no need to do the MAX. The TARGET table has only one unique record for each ID. Is it possible to write an UPDATE subquery like I have shown in the last line of example code?
I'm having problems trying to use the UPDATE query in SQL server.
this is my query:
UPDATE THEATER
SET SeatsAvailable = SeatsAvailable - 1
FROM THEATER
INNER JOIN CINEMA_SESSION ON CINEMA_SESSION.tid = THEATER.tid
WHERE THEATER.tid = 2 AND CINEMA_SESSION.sid = 2
-tid is the pk for THEATER
-sid is the pk for CINEMA_SESSION
When I use a SELECT statement to search for the SeatsAvailable in CINEMA_SESSION.sid = 3, which also has .tid=2, it also comes with the updated value for the CINEMA_SESSION.sid = 2.
The statement that I'm using is this simple Select statement:
SELECT THEATER.SeatsAvailable as SeatsAvailable FROM THEATER
INNER JOIN CINEMA_SESSION ON CINEMA_SESSION.tid = THEATER.tid
WHERE CINEMA_SESSION.sid = 3 AND THEATER.tid = 2
Here I want to specify the THEATER.tid which is the same in the UPDATE query but in a different CINEMA_SESSION.sid in which the SeatsAvailable should have remained the same.
The update statement is decrementing the value of SeatsAvailable on the Theatre table for tid=2 (the AND CINEMA_SESSION.sid = 2 is immaterial - you are updating the row on the THEATER table). Since tid is the primary key for theatre, there is only one record with that value, and that record is updated.
Your select for session sid=3 joins to theatre by the tid column, and it's matching the row where tid=2, which is why you're seeing the new value - it is matching the record that you just updated.
This may make more sense if you just look at the contents of the THEATER table (without any joins).
If you are trying to indicate that a seat has been booked for a particular session, then I would suggest you need to be updating a field on a different table. I'll leave that to you to work out. Hope this helps.
I have two tables
Customer
CustomerUpdate
Structure of both tables are like this
Customer table's structure
CustomerName | CustomerId
CustomerUpdate table's structure
NewCustomerName | NewCustomerId | OldCustomerName
I have few values inserted in the Customer table. Whenever I should update the data in this table I want that the existing as well as new data should be triggered into new table CustomerUpdate.
For this I created a trigger but this is only pulling the updated data, it's not pulling the existing data..
CREATE TRIGGER trgAfterUpdate
ON [dbo].Customer
FOR UPDATE
AS
SET NOCOUNT ON
declare #NewCustomerName nchar(20);
declare #NewCustomerId nchar(20);
declare #OldCustomerName nchar(20);
declare #audit_action varchar(100);
select #NewCustomerName = i.CustomerName from inserted i;
select #NewCustomerId = i.CustomerId from inserted i;
select #OldCustomerName = c.CustomerName
from Customer c
where CustomerId = #NewCustomerId;
if update(CustomerName)
set #audit_action='Updated Record -- After Update Trigger.';
if update(CustomerId)
set #audit_action='Updated Record -- After Update Trigger.';
insert into CustomerUpdate(NewCustomerName, NewCustomerId, OldCustomername)
values(#NewCustomerName, #NewCustomerId, #OldCustomerName);
PRINT 'AFTER UPDATE Trigger fired.'
GO
Please help me out
First, selecting from the table being modified when an update trigger is executing will get the new value. These are AFTER triggers (rather than INSTEAD triggers) and therefore the update has already happened by the time the trigger fires (although it can be rolled back). If you need the old value, you should select from the DELETED pseudo-table.
Second, as pointed out by #marc_s in comments, your trigger has the hidden assumption that only one row is affected by each update. This may very well be a valid assumption for your environment, if your application only ever updates one row at a time, but in the general case, every trigger should be ready to handle the case where many rows are affected by a single update. Writing your triggers to handle multiple rows is good practice.
Third, all of your sequentially executing code is pretty much unnecessary. The old value and the new value can be retrieved and inserted all at once:
CREATE TRIGGER trgAfterUpdate
ON [dbo].Customer
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
insert into CustomerUpdate(NewCustomerName, NewCustomerId, OldCustomername)
-- case 1: ID unchanged
SELECT I.CustomerName, I.CustomerID, D.CustomerName
FROM Inserted I
JOIN Deleted D on I.CustomerID=D.CustomerID
UNION ALL
-- case 2: ID changed, Name unchanged
SELECT I.CustomerName, I.CustomerID, D.CustomerName
FROM Inserted I
JOIN Deleted D on I.CustomerName=D.CustomerName
WHERE I.CustomerID<>D.CustomerID
UNION ALL
--case 3: ID changed, Name changed
SELECT I.CustomerName, I.CustomerID, D.CustomerName
FROM Inserted I
LEFT JOIN Deleted D on I.CustomerID=D.CustomerID OR I.CustomerName=D.CustomerName
WHERE D.CustomerID IS NULL;
END
Given the following question based on the database below.
a) Create a trigger that will automatically update the quantity on hand each time that a product is sold as listed as a row in the LINE table. In other words, a line row is inserted as part of an invoice. Each line is linked to a product. Decrement the quantity on hand (P_QOH) by the number ordered.
http://i.stack.imgur.com/wWX17.png
You'll have to create insert trigger on table Line
CREATE TRIGGER [dbo].[TriggerUpdateQty] ON [dbo].[Line]
AFTER INSERT
AS
...
then you'll need to run an update Product table joining with inserted table. inserted table represents data inserted that triggered the trigger.
Update Product set Product.P_QOH = (Product.P_QOH - inserted.Line_units)
from Prduct inner join inserted on Product.P_Code = inserted.P_Code