SQL Server trigger on update with select then insert into multiple tables - sql

I am trying to create a trigger on update of a column and insert rows into other tables. The data is coming from a SELECT with multiple joins and needs to be inserted into multiple tables.
My question is, is it best practice to insert the values into variables before the insert? I have never created a trigger like this before.
CREATE TRIGGER ship_trigger ON dbo.Orders
FOR UPDATE
AS
SET NOCOUNT ON
IF ( UPDATE(OrderStatusId) AND OrderStatusId == 1)
BEGIN
SELECT
FROM
JOIN
JOIN
WHERE
I am just looking to understand the most efficient way to insert the data into the other tables
Thanks!

Assuming SQL Server (the syntax suggests so), it isn't a best practice to insert the values into variables first, what would be the point of doing that?. And the only way that you could actually do that would be on table variables or if you update only one row, since the triggers gets executed once for all the rows that got affected by your UPDATE, and those rows are available to you on the INSERTED pseudo table. So, your trigger would look something like this:
CREATE TRIGGER ship_trigger ON dbo.Orders
FOR UPDATE
AS
SET NOCOUNT ON
IF ( UPDATE(OrderStatusId) AND OrderStatusId = 1)
BEGIN
INSERT INTO SomeTable(Col1, Col2)
SELECT Col1, Col2
FROM INSERTED
END

Related

SQL trigger to insert data from one table to another if a condition is met

I am miserably failing to build a sql trigger (in background) where I want to insert data from one table to another if a certain condition is met, something like this:
Create trigger on table Invoice
If inv_number starts with inv
Then Insert into Document (var1,var2,var3) values (inv_number, inv_date, inv_amount)
Thanks
If you're using SQL Server (as I said in comments - triggers are highly vendor-specific, so if you're using something else, you'll have to adapt as needed), you can use something like this:
CREATE TRIGGER trgInvoiceInsert
ON dbo.Invoice
AFTER INSERT -- adapt if you need to run this after UPDATE or DELETE, too
AS
BEGIN
/* In SQL Server, if you inserting a bunch of rows
at once using an `INSERT INTO .... SELECT ....`
approach, then this trigger will be called only *ONCE*,
with all the inserted rows in the "Inserted" pseudo table.
Handle it accordingly - in a set-based manner
*/
INSERT INTO dbo.Document (col1, col2, col3)
SELECT i.inv_number, i.inv_date, i.inv_amount)
FROM Inserted i
WHERE i.inv_number LIKE 'inv%'
END
For further details, check out the official Microsoft documentation on SQL Server triggers

Sql Trigger After Insert Update another table with conditions

I am creating After Insert trigger , its working fine, but I have certain conditions before executing the statements inside the trigger
Based on Different CustomerId Run the trigger, I want check which CustomerId got inserted in my LoyaltyDetailsTable, say if last insert
was Customerid=2 then pass that Customerid in where condition then run
the trigger , or if Customerid = 1 then run the trigger for that Id,
so on.
I want to check whether in PriceClaimTable the inserted CustomerId exist or not, If exists then update the details else just insert the
values in LoyaltyDetailsTable only.
Trigger query
CREATE TRIGGER DetailsAfterInsert ON [dbo].[LoyaltyDetailsTable]
FOR INSERT
as
UPDATE PriceClaimTable
SET CurrentPoints =
(
(SELECT SUM(LoayaltyPointsTable.Points) AS RecentPoints FROM LoayaltyPointsTable
join LoyaltyDetailsTable ON LoayaltyPointsTable.LoyaltyPointsId
= LoyaltyDetailsTable.LoyaltyPointsId
WHERE CustomerId=1 and LoyaltyDetailsId= (SELECT MAX(LoyaltyDetailsId)
AS LoyaltyDetailsTable FROM LoyaltyDetailsTable))
+
(SELECT CurrentPoints FROM PriceClaimTable WHERE ClaimCustomerId=1 and
PriceClaimId=(SELECT max(PriceClaimId) FROM PriceClaimTable
))
)
WHERE ClaimCustomerId=1 and PriceClaimId=(SELECT max(PriceClaimId) FROM PriceClaimTable)
This is my first attempt to write a trigger, and here is table structure.
Any help would be great.
What you're looking for here is the inserted table. Every time you issue an UPDATE statement, SQL Server generates two virtual tables called inserted and deleted that store information on the data modifications you're making. These tables are accessible from your trigger. For more information, see here: https://msdn.microsoft.com/en-us/library/ms191300.aspx
You can use inserted to get the IDs you're looking for. So, instead of:
WHERE ClaimCustomerId=1
you can use:
WHERE ClaimCustomerId=inserted.ClaimCustomerId

Merge SQL INSERT with Reference Table

I need to synchronize two tables.
TableA
Id Name
TableB
Id Name RefID --It's a Foreign key, defined as primary key in Table "TableReference"
TableReference
RefID -- Identity Column, auto increment
I need to merge TableA and TableB in such a way that on each insert in TableB, a value should be inserted into TableReference and that inserted value should be copied into RefId column of TableB.
What I am doing?
I am using SSIS hence I need to have a SSIS based solution OR SQL based solution. I know how to merge tables using Merge SQL command but I am not able to insert a value into TableRef and copy it back to TableB. Could not figure out how i can accomplish this. SQL user-defined functions don't allow INSERT so I can't use it.
Merge TabaleB T
Using Table A S
On S.Id=T.Id
WHEN MATCHED THEN
UPDATE
T.ID=S.ID,
T.NAME=S.NAME
WHEN NOT MATCHED BY TARGET THEN
INSERT(S.ID,S.NAME, {Somehow here i need a function call that inserts in TableRef and Returns SCOPE_IDENTITY})
The problem is T-SQL functions don't allow INSERT and a stored procedure can't be called here as Merge doesn't allow any TSQL thing other than INSERT after WHEN NOT MATCHED BY TARGET THEN.
Are you able to add a TRIGGER on your TableB. If so, one option would be to use the INSERTED row and go from there.
Maybe something like this (untested):
CREATE TRIGGER dbo.tr_TableB
ON dbo.TableB
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT TableReference DEFAULT VALUES;
DECLARE #RefId INT;
SELECT #RefId = SCOPE_IDENTITY();
UPDATE t1
SET t1.RefId = #RefId
FROM dbo.TableB AS t1
INNER JOIN INSERTED AS i
ON i.Id= t1.Id
END
GO
Good luck.

SQL Server INSERT trigger how to get data of current row

I've never created a trigger before and I'm trying to read online but am a little confused.
I want to create a trigger on a table that on insert, it will grab some data from different columns and insert it into a few different other tables.
I'm not sure how to write the T-SQL to get the data from the columns..
insert into [othetTable]
values ([col1 from row that was inserted], [col5 from row that was inserted])
What would the syntax be to get those values?
thanks
Use the inserted virtual table that is available to triggers. Note that there could be multiple rows in this table - your trigger could be processing multiple inserts at once.
Therefore, you need to use something like the following syntax:
insert into othertable
select col1, col5
from inserted
This will insert a row into othertable for each inserted row.

Delete and Insert or Select and Update

We have a status table. When the status changes we currently delete the old record and insert a new.
We are wondering if it would be faster to do a select to check if it exists followed by an insert or update.
Although similar to the following question, it is not the same, since we are changing individual records and the other question was doing a total table refresh.
DELETE, INSERT vs UPDATE || INSERT
Since you're talking SQL Server 2008, have you considered MERGE? It's a single statement that allows you to do an update or insert:
create table T1 (
ID int not null,
Val1 varchar(10) not null
)
go
insert into T1 (ID,Val1)
select 1,'abc'
go
merge into T1
using (select 1 as ID,'def' as Val1) upd on T1.ID = upd.ID --<-- These identify the row you want to update/insert and the new value you want to set. They could be #parameters
when matched then update set Val1 = upd.Val1
when not matched then insert (ID,Val1) values (upd.ID,upd.Val1);
What about INSERT ... ON DUPLICATE KEY? First doing a select to check if a record exists and checking in your program the result of that creates a race condition. That might not be important in your case if there is only a single instance of the program however.
INSERT INTO users (username, email) VALUES ('Jo', 'jo#email.com')
ON DUPLICATE KEY UPDATE email = 'jo#email.com'
You can use ##ROWCOUNT and perform UPDATE. If it was 0 rows affected - then perform INSERT after, nothing otherwise.
Your suggestion would mean always two instructions for each status change. The usual way is to do an UPDATE and then check if the operation changed any rows (Most databases have a variable like ROWCOUNT which should be greater than 0 if something changed). If it didn't, do an INSERT.
Search for UPSERT for find patterns for your specific DBMS
Personally, I think the UPDATE method is the best. Instead of doing a SELECT first to check if a record already exists, you can first attempt an UPDATE but if no rows are affected (using ##ROWCOUNT) you can do an INSERT.
The reason for this is that sooner or later you might want to track status changes, and the best way to do this would be to keep an audit trail of all changes using a trigger on the status table.