Keeping track of purchase counts using a trigger - sql-server

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)

Related

Update when value is different but do not update when value is already null SQL

Table Name - NUMBER EMPLOYEES
Columns - COMPANY ID, DIRECT, LASTUPDATEDDATE
Trigger - updateDateDETrig
I have a trigger which store the updated date in the LASTUPDATEDDATE column when ever DIRECT column is updated.
But i want to save the date:
Only when the DIRECT value is different.
If DIRECT value is already NULL then it should not update anything and will not save any last updated date.
If DIRECT’s value is not NULL other value is present then it should be able to update with NULL value, in that case it should store the date too.
Trigger query -
CREATE TRIGGER [dbo].[updateDateDETrig]
ON [WWWSCM].[dbo].[NumberEmployees]
AFTER INSERT, UPDATE
AS
IF ( UPDATE ([Direct]))
BEGIN
UPDATE [WWWSCM].[dbo].[NumberEmployees] SET [UpdatedDateDirectEmployees] = GETDATE ()
FROM [WWWSCM].[dbo].[NumberEmployees] t
INNER JOIN inserted i
ON t.[CompanyID] = i.[CompanyID]
END
GO
Update query :
update [WWWSCM].[dbo].[NumberEmployees]
set Direct = #Direct where CompanyID = #CompanyID AND (Direct<> #Direct OR Direct is NULL)
For me the first point is working fine , but the last 2 points are not working. Can this be done through SQL server script?

SQL Server : I'm trying to create a trigger that when inserted data in table Reservations it updates only specific row but not all of them

I'm kinda new to SQL Server and I have this task from school I'm trying to solve. I have 3 tables Flight, number_seats and reservations.
I'm trying to create a trigger so when data is inserted into table Reservations, it subtract 1 seat from the table Number_Seats in column Total_Number_Seats.
The problem I'm having is that my WHERE targets all of the rows so when I insert data into table Reservations, it affects all rows and not just the particular row with same FLIGHT_ID.
I realise my WHERE clause is not specific enough but I can't figure out how to write it so it targets specific row that got inserted. So please help if you can :).
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[ajSad]
ON [dbo].[Reservations]
AFTER INSERT
AS
BEGIN
UPDATE Number_Seats
SET Total_Number_Seats = Total_Number_Seats - 1
FROM Number_Seats
JOIN Flights ON Number_Seats.FLIGHT_ID = FLIGHTS.FLIGHT_ID
JOIN Reservations ON Flights.Flight_ID = Reservations.Flight_ID
WHERE Reservations.FLIGHT_ID = Number_Seats.Flight_ID
END
INSERT INTO reservations (ID_Rezervacije, ID_Klijenta, FLIGHT_ID)
VALUES (5, 5, 5);
Your trigger needs to use the inserted virtual table to only update the row(s) for the relevant flight_Id(s)
The inserted table in the context of the trigger will contain all the rows that were inserted in a single batch - this could be one or many and you need to assume it can be more than one.
You need to count the number of new reservations (presumably it's 1 row per reservation) and group by each flight_Id and then decrement the total number for each flight_Id
with t as (
select flight_Id, Count(*) tot
from inserted
group by flight_Id
)
update ns set
total_number_seats -= tot
from t
join number_seats ns on ns.flight_Id=t.flight_Id

Writing a SQL Server trigger - error

I have three tables:
Bus_Driver (drNo,drName,salary,StationNo,experience)
Station (StationNo,address,district,Salary_Commission)
Cleaner (Cleaner_No, Cname, StationNo)
The question is to write a trigger. It states that if a bus driver's salary is increased by 20% more than the original salary then 0.05% of the increased value will be transferred to his Station as Salary commission.
I managed to write the trigger halfway, but got stuck when I have to transfer the amount to the other table.
My code is:
CREATE TRIGGER tr_1
ON Bus_Driver
AFTER INSERT
AS
BEGIN
DECLARE #salary MONEY
SET #Salary = 0
SELECT #Salary= salary
FROM Inserted
WHERE #Salary > (120 / 100 * #Salary)
Can anyone help me how to write the next steps please
The trigger you wrote is wrong.
First, it's a trigger for insert, while the question states that the salary is raised, meaning it should be a trigger for update.
Second, your trigger assumes only a single row will be in the inserted table. However, this assumption is wrong. Triggers in SQL server are fired per statement, not per row, meaning that the inserted (and deleted) tables might contain zero, one, or many rows.
A solution for this question will be to write a trigger for update, that will, in turn, update the station table. Something like this:
CREATE TRIGGER tr_Bus_Driver_Update ON Bus_Driver
FOR UPDATE
AS
UPDATE s
SET Salary_Commission = Salary_Commission -
(0.0005 * D.Salary) + -- Remove old salary of the driver(s) from salary_commition.
(0.0005 * I.Salary) -- add new salary of the driver(s) to salary_commition
FROM Station s
INNER JOIN Inserted I ON s.StationNo = I.StationNo
INNER JOIN Deleted D ON I.drNo = D.drNo -- assuming drNo is unique in Bus_Driver table
WHERE I.Salary >= D.Salady * 1.2 -- You might need to cast to a floating point data type if the Salary is an integer data type
Note you might need to cast the salary to a floating point data type if the Salary is an integer data type whenever it's used in this trigger.
You need to stop and start again from scratch.
First of all, you need to catch the AFTER UPDATE event - not the insert - since you want to do something when the salary is updated (an existing value is replaced with a higher one).
Secondly, the trigger will be called once per UPDATE statement and if that UPDATE affects more than one row, the Deleted and Inserted pseudo tables will contain multiple rows of data - so your SELECT #Salary = salary FROM Inserted statement is doomed - it will fetch one arbitrary row and ignore all others that might be also affected.
In an UPDATE case, Inserted will have the new values (after the update), while Deleted has the old values (before the update) - so the difference between these two pseudo tables can be used to figure out if the salary increase was more than 20%:
CREATE TRIGGER trBusDriverSalaryIncrease
ON dbo.Bus_Driver
AFTER UPDATE
AS
BEGIN
-- declare a table variable to hold all revelant values
DECLARE #RelevantIncreases TABLE (drNo INT, StationNo INT, SalaryIncrease DECIMAL(18,2))
-- find those bus drivers who have had a more than 20% increase in their salary
INSERT INTO #relevantIncreases (drNo, StationNo, SalaryIncrease)
SELECT
i.drNo, i.StationNo, -- Driver and Station No
(i.Salary - d.Salary) -- Salary increase in absolute numbers
FROM
Deleted d
INNER JOIN
Inserted i ON d.drNo = i.drNo
WHERE
-- Salary increased by more than 20%
i.Salary > 1.2 * d.Salary
-- now that we have all the relevant bus drivers and their salary increase
-- insert this into the Station.Salary_Commission column
UPDATE s
SET Salary_Commission = s.Salary_Commission + ri.SalaryIncrease * 0.0005
FROM dbo.Station s
INNER JOIN #RelevantIncreases ri ON ri.StationNo = s.StationNo
END

How to store existing column value in new table using trigger

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

sql server trigger to increment a column when another column decrements

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.

Resources