update column after insert using a trigger - sql-server

I'm trying to update a column using a trigger in SQL Server 2014 after I insert row in the competition table.
I need to update the judge_Id in the competition table from NULL to a judges_ID in the judges table.
The judges_ID needs to be a swimming judge in the expertise table (it's a swimming contest).
Then I need to insert the competition.judges_ID with a count from the competition.judges_ID with a judges ID that has the lowest count. (i.e allocating a relevant judges workload evenly between the judges)
this is what I've tried.
I know it's not right because I'm not sure how to put Joins in.
CREATE TRIGGER [dbo].[trg_insertJudge]
ON [dbo].[competition]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[competition.judges_ID]
WITH [dbo].[judges.judges_ID]
SELECT
FROM [dbo].[judges.judges_ID]
WHERE [dbo].[judges.judges_ID] = [judges2expertise.judges_ID]
AND
[dbo].[judges2expertise.expertiseType] = 3
SELECT
FROM [dbo].[judges.judges_ID]
WHERE
COUNT [dbo].[competition.judges_ID]
FROM [dbo.competition.judgesID]
SELECT MIN [dbo.competition.judgesID]
END

Related

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

Recording info in SQL Server trigger

I have a table called dsReplicated.matDB and a column fee_earner. When that column is updated, I want to record two pieces of information:
dsReplicated.matDB.mt_code
dsReplicated.matDB.fee_earner
from the row where fee_earner has been updated.
I've got the basic syntax for doing something when the column is updated but need a hand with the above to get this over the line.
ALTER TRIGGER [dsReplicated].[tr_mfeModified]
ON [dsReplicated].[matdb]
AFTER UPDATE
AS
BEGIN
IF (UPDATE(fee_earner))
BEGIN
print 'Matter fee earner changed to '
END
END
The problem with triggers in SQL server is that they are called one per SQL statement - not once per row. So if your UPDATE statement updates 10 rows, your trigger is called once, and the Inserted and Deleted pseudo tables inside the trigger each contain 10 rows of data.
In order to see if fee_earner has changed, I'd recommend using this approach instead of the UPDATE() function:
ALTER TRIGGER [dsReplicated].[tr_mfeModified]
ON [dsReplicated].[matdb]
AFTER UPDATE
AS
BEGIN
-- I'm just *speculating* here what you want to do with that information - adapt as needed!
INSERT INTO dbo.AuditTable (Id, TriggerTimeStamp, Mt_Code, Old_Fee_Earner, New_Fee_Earner)
SELECT
i.PrimaryKey, SYSDATETIME(), i.Mt_Code, d.fee_earner, i.fee_earner
FROM Inserted i
-- use the two pseudo tables to detect if the column "fee_earner" has
-- changed with the UPDATE operation
INNER JOIN Deleted d ON i.PrimaryKey = d.PrimaryKey
AND d.fee_earner <> i.fee_earner
END
The Deleted pseudo table contains the values before the UPDATE - so that's why I take the d.fee_earner as the value for the Old_Fee_Earner column in the audit table.
The Inserted pseudo table contains the values after the UPDATE - so that's why I take the other values from that Inserted pseudo-table to insert into the audit table.
Note that you really must have an unchangeable primary key in that table in order for this trigger to work. This is a recommended best practice for any data table in SQL Server anyway.

Logging deletion of rows in table sql server

I have been searching for a way to log the deletion of rows from a table.
Tried this Log record changes in SQL server in an audit table but it didn't help me.
I have a song list database, the log table has the columns: Title / Artist / Year / Position / SentinDate .
There is a list with songs from the years 1999 to 2014, and every year has 2000 songs (top2000 is what it is called in The Netherlands).
Basically what the log table should look like once a certain Year has been deleted:
I need a basic way trigger-log when someone deletes a certain year from the list of 1999-2014.
I hope to have informed enough for you to understand, if not I will try to explain in more detail.
A trigger rejects or accepts each data modification transaction as a whole.
Using a correlated subquery in a trigger can force the trigger to examine the modified rows one by one.
Examples
A. Use an AFTER INSERT trigger
The following example assumes the existence of a table called newsale in the pubs database. This the CREATE statement for newsale:
CREATE TABLE newsale
(stor_id char(4),
ord_num varchar(20),
date datetime,
qty smallint,
payterms varchar(12),
title_id tid)
If you want to examine each of the records you are trying to insert, the trigger conditionalinsert analyzes the insert row by row, and then deletes the rows that do not have a title_id in titles.
CREATE TRIGGER conditionalinsert
ON sales
AFTER INSERT AS
IF
(SELECT COUNT(*) FROM titles, inserted
WHERE titles.title_id = inserted.title_id) <> ##ROWCOUNT
BEGIN
DELETE sales FROM sales, inserted
WHERE sales.title_id = inserted.title_id AND
inserted.title_id NOT IN
(SELECT title_id
FROM titles)
PRINT 'Only sales records with matching title_ids added.'
END
When unacceptable titles have been inserted, the transaction is not rolled back; instead, the trigger deletes the unwanted rows. This ability to delete rows that have been inserted relies on the order in which processing occurs when triggers are fired. First, rows are inserted into the sales table and the inserted table, and then the trigger fires.
Simply create an INSTEAD OF DELETE trigger ! In that trigger, you have a "virtual" table called deletedwhich contains all records which are to be deleted.
So in the trigger, you can just insert all records contained in deleted to your log table, and then you delete the records from our table. (this will then be a DELETE statement with a join to the deleted table)

SQL Server decrementing inventory

I am using SQL Server 2008. I have a table where orders with SKU are recorded, a table for inventory that has counts and a table where the relationship between the SKU sold and inventory items is recorded.
In the end, I got the report like this
Inventory CurrentQuantity OpenedOrder
SKU1 300 50
SKU2 100 10
Each order will be processed individually. How can I have the database automatically update the inventory tablet after each order is processed?
i.e
If the order has 2 SKU1 in it got processed, the the inventory table will automatically show 298.
Thanks
I would use a Stored Procedure, and perform the order insert and quantity update in one hit:
CREATE PROC dbo.ProcessOrder
#Item int,
#Quantity int
AS
BEGIN
--Update order table here
INSERT INTO dbo.Orders(ItemID,Quantity)
VALUES (#ItemID, #Quantity)
--Update Inventory here
UPDATE dbo.Inventory
SET CurrentQuantity = CurrentQuantity - Quantity
WHERE ItemID = #ItemID
END
I think what you are looking for is a trigger
Basically, set up a trigger that will update the appropriate columns using the inserted/updated data given. Without a full schema set, that is the best answer I can give at this time
I wouldn't be looking at a trigger myself for this.
My check out process
Start a transaction
Check stock level.
If OK, (optional validation / authorisation)
Add a check out record
Reduce the stock
Possibly add some record to invoice teh recipent etc.
Commit the transaction
While you could do it with triggers, I simply fail to see the point, a nice simple clear and all in one place SP_CheckOut stored procedure is where I'd be going.
I would normally advise to use a trigger but stock manipulation is that kind of operation that's usually done a lot of times, sometimes on batches and this is not the best scenario for triggers to be honest.
I think PKG's idea is very good, but you should never forget to add transaction control to it, otherwise you can endup with non-matching stocks:
CREATE PROC dbo.ProcessOrder
#Item int,
#Quantity int
AS
BEGIN
begin transaction my_tran
begin try
--Update order table here
INSERT INTO dbo.Orders(ItemID,Quantity)
VALUES (#ItemID, #Quantity)
--Update Inventory here
UPDATE dbo.Inventory
SET CurrentQuantity = CurrentQuantity - Quantity
WHERE ItemID = #ItemID
commit transaction
end try
begin catch
rollback transaction
--raise error if necessary
end catch
END
you can use the trigger,also use the procedure,and the specific steps on the top,use the procedure need to open the atuo exec feature in mastaer DB.

SQL Server 2005 insert trigger not inserting enough records

I have a table in a SQL Server 2005 database with a trigger that is supposed to add a record to a different table whenever a new record is inserted. It seems to work fine, but if I execute an Insert Into on the master table that uses a subquery as the source of the values, the trigger only inserts one record in the other table, even though multiple records were added to the master. I want the trigger to fire for each new record added to the master table. Is that possible in 2005?
The insert I'm doing is:
INSERT INTO [tblMenuItems] ([ID], [MenuID], [SortOrder], [ItemReference], [MenuReference], [ConcurrencyID]) SELECT [ID], [MenuID], [SortOrder], [ItemReference], [MenuReference], [ConcurrencyID] FROM [IVEEtblMenuItems]
Here is what the trigger looks like:
CREATE TRIGGER [dbo].[tblMenuItemInsertSecurity] ON [dbo].[tblMenuItems]
FOR INSERT
AS
Declare #iRoleID int
Declare #iMenuItemID int
Select #iMenuItemID = [ID] from Inserted
DECLARE tblUserRoles CURSOR FASTFORWARD FOR SELECT [ID] from tblUserRoles
OPEN tblUserRoles
FETCH NEXT FROM tblUserRoles INTO #iRoleID
WHILE (##FetchStatus = 0)
BEGIN
INSERT INTO tblRestrictedMenuItems(
[RoleID],
[MenuItemID],
[RestrictLevel])
VALUES(
#iRoleID,
#iMenuItemID,
1)
FETCH NEXT FROM tblUserRoles INTO #iRoleID
END
CLOSE tblUserRoles
Deallocate tblUserRoles
Your trigger is only using the first row from 'Inserted'. This is a common misunderstanding when dealing with SQL triggers for the first time. The trigger fires per update not per row.
For example if you do the following:-
update products
set title = 'geoff de geoff'
this would update all the products, but a trigger on the product table would only fire once.
The Inserted 'table' you get in trigger would contain all the rows. You must either loop through Inserted with a cursor, or better join Inserted to the table you are updating.
Please lookup multi row consideration for triggers
What is with the cursor inside a trigger? Learn how to program set based, cursors are Evil in T-SQL and should only be used to defragment/update stats/other maintanance a bunch of tables
The trigger only fires once for each INSERT statment executed - not once for each record inserted.
In your trigger you can access the 'virtual' table called inserted for details of the records inserted.
ie:
SELECT COUNT(*) FROM inserted
Will return the number of inserted records.
I just want to second #Gordon Bell on his answer...
"Catch" the values the very moment they are being inserted. You do not really need the cursor in this situation (or maybe you have a reason?).
A simple TRIGGER might be all you need:
http://dbalink.wordpress.com/2008/06/20/how-to-sql-server-trigger-101/

Resources