Database After Update Trigger From Inserted But Not Inserted? [SQL Server] - sql

I'm trying to create a SQL Server trigger that when an update on table 1 happens in the val2 column, it takes that value and updates table2. I'm struggling to understand how to do this properly on something that sounds easy.
Image of tables
I believe my issue is trying to set a value that is not actually from inserted. (The only value getting updated is val2). I don't know how I can pair where to do the update other than grabbing the ID also on the updated row to compare to the place I want to update. Any help/advice on this would be greatly appreciated. Below is my current trigger that does not work.
CREATE TRIGGER Pull_ID on table1
AFTER UPDATE
AS
BEGIN
#id_ = id from inserted
#val2_ = val2 from inserted
UPDATE table2
SET val2 = #val2_
FROM
WHERE table2.id = #id_
END

You need to build your trigger so that it can handle multiple rows - always.
So you a proper set-based approach, not relying on the false assumption that you only get one row.
Try this:
CREATE TRIGGER Pull_ID on table1
AFTER UPDATE
AS
UPDATE table2
SET val2 = i.val2
FROM Inserted i
WHERE table2.id = i.id
The Inserted pseudo table contains all the rows that have been updated - their new values after the UPDATE. Join that table with your Table2 based on the primary key column (assuming that's the Id) and use a proper, set-based, multi-row capable single UPDATE statement - and you're done!

Related

Interbase SQL trigger

Interbase, Sql, trigger. Can't really understand how to write a trigger of this kind: I have several tables. Each one has a document type, status and an unique number. One table in which i wish to create a trigger is a table that holds a file i post, a status of posting, a doctype corresponding to a table and a unique number linking to a record in the corresponding table. I want to change document status in the corresponding table based on the unique number to a certain status depending on the post result (status) that i change after posting. How can I do it?
Trigger T1 will be executed after update on TABLE1.
Trigger checks if TABLE1.StatusOfPosting changed to some value and depending on result updates TABLE2.DocumentStatus.
Depending on bussienes logic, maybe you will need and BEFORE DELETE trigger.
CREATE TRIGGER T1 FOR TABLE1 AFTER UPDATE POSITION 0
AS
BEGIN
IF (NEW.StatusOfPosting <> OLD.StatusOfPosting and NEW.StatusOfPosting=1) THEN
UPDATE TABLE2
SET TABLE2.DocumentStatus=1
WHERE TABLE2.UniqueNumber = TABLE1.UniqueNumber;
END

Does my trigger updates all the records

I have written a simple trigger which sets a column value with the id column value.
This is my trigger.
CREATE TRIGGER SubSectionsPrioritytrigger
ON SubSections
AFTER INSERT
AS
UPDATE dbo.SubSections
SET Priority = Id
After writing this trigger that, does this updates all the records after each insert. Or the only created new row.
Could some one provide any info on this.
Thanks.
To Update just the inserted row, you can do this:
UPDATE dbo.SubSections
SET SubSections.Priority = SubSections.Id
FROM INSERTED
WHERE INSERTED.Id = dbo.SubSections.Id
It does exactly what you wrote
UPDATE dbo.SubSections
SET Priority = Id
Any row will be updated.
You can change this to
UPDATE dbo.SubSections
SET SubSections.Priority = Inserted.Id
FROM INSERTED
WHERE INSERTED.id = SubSections.id
this will affect only the inserted rows.
to update just the last inserted row to what ever value you want you need to specify that row id which makes that row unique, from other rows.
and in your trigger you have not specified a where clause which causes all rows in the table to be updated.
whenever a any operation/event occurs on the table which has trigger associated with it mean a new record is inserted/updated or deleted an magic table is created in memory of SQL Server and we can access that magic table with the keyword "Inserted" in case of insert or Update and "Deleted" in case of delete.
so your query should be like this.
UPDATE dbo.SubSections
SET SubSections.Priority = SubSections.Id
FROM INSERTED
WHERE INSERTED.Id = dbo.SubSections.Id

SQL Server insert trigger not working

This is my first time using triggers.
My trigger is not being triggered please help.
CREATE TRIGGER sbhack_autoban
ON LOG_CONNECT201211
FOR INSERT
AS
BEGIN
/* query to run if single or multiple data is
inserted into LOG_CONNECT201211 table */
UPDATE login.dbo.USER_CHECK_LOGIN
SET login.dbo.USER_CHECK_LOGIN.CHECKLOGIN = 2
WHERE login.dbo.USER_CHECK_LOGIN.USER_KEY IN
(SELECT e.USER_KEY
FROM game.dbo.CHAR_DATA0 AS e
INNER JOIN gamelogs.dbo.LOG_USING_DEPOT201211 AS p
ON e.CHAR_KEY = p.CHAR_KEY
WHERE p.GATENUM = 150)
AND login.dbo.USER_CHECK_LOGIN.CHECKLOGIN = 0
AND login.dbo.USER_CHECK_LOGIN.USER_KEY != 51;
END
This is suppose to run the query inside the BEGIN : END if an entry is inserted into the LOG_CONNECT201211 table. But nothing is happening even when I have inserted multiple data into LOG_CONNECT201211.
When your INSERT trigger fires - then at least one new row has been inserted! That's a fact.
Now the question is: given that a single or multiple new rows have been inserted - what do you want to do with this knowledge??
Typically, you could e.g. set a column to a value you cannot specify as a default constraint - or you could insert the fact that the row has been inserted into an audit table or something....
So you'd have something like this:
CREATE TRIGGER sbhack_autoban
ON LOG_CONNECT201211
FOR INSERT
AS
INSERT INTO LogAudit(InsertedDate, UserKey)
SELECT
GETDATE(), i.User_Key
FROM
Inserted i
or something like that....
Update: ok, so you want to run that UPDATE statement when the rows have been inserted - not 100% clear, what columns/values from the inserted rows you want to use - looks like the e.UserKey column only - correct?
Then the UPDATE would be:
UPDATE login.dbo.USER_CHECK_LOGIN
SET login.dbo.USER_CHECK_LOGIN.CHECKLOGIN = 2
WHERE
login.dbo.USER_CHECK_LOGIN.USER_KEY IN
(SELECT USER_KEY FROM Inserted)
AND login.dbo.USER_CHECK_LOGIN.CHECKLOGIN = 0
AND login.dbo.USER_CHECK_LOGIN.USER_KEY != 51;
Update #2:
The point I still don't understand is : why do you want to run an update that uses the USER_CHECK_LOGIN, CHAR_DATA0 and LOG_USING_DEPOT201211 tables, when some rows are getting inserted into a totally separate, unrelated table LOG_CONNECT201211 ??
A trigger is used when you want to do something because rows have been inserted into that table - but in that case, you typically want to do something with the rows and their values that have been inserted...
I just don't see any connection between the rows being inserted into LOG_CONNECT201211 event, and the tables you are then querying from and updating. Where's the link?? WHY do you need to run *this UPDATE when data is inserted into LOG_CONNECT201211 ?? It would make sense if data where inserted into one of the tables involved in the UPDATE - but like this, it just totally doesn't make any sense .....

SQL Triggers - Deleted or Updated? or maybe something else?

I am trying to figure out which i need to use here: deleted, inserted or updated.
basically.
I need to write some data to the history table, when the main table is updated, and only if the status changes from something to either pending or active.
This is what I have now:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE AS
DECLARE #statusOldValue char(1)
DECLARE #statusNewValue char(1)
SELECT #statusOldValue = statusCode FROM deleted
SELECT #statusNewValue= statusCode FROM updated
IF (#statusOldValue <> #statusNewValue) AND
(#statusOldValue = 'P' or #statusOldValue = 'A')
BEGIN TRY
INSERT * INTO tblHistoryTable)
select * from [DELETED]
so I want the new data to stay in the main table, the the history table to be updated with what is being overwritten... right now it just copies the same info over. so after update, both my tables have the same data.
There are only the Inserted and Deleted pseudo tables - there's no Updated.
For an UPDATE, Inserted contains the new values (after the update) while Deleted contains the old values before the update.
Also be aware that the triggers is fired once per batch - not once for each row. So both pseudo tables will potentially contain multiple rows! Don't just assume a single row and assign this to a variable - this
SELECT #statusOldValue = statusCode FROM deleted
SELECT #statusNewValue= statusCode FROM updated
will fail if you have multiple rows ! You need to write your triggers in such a fashion that they work with multiple rows in Inserted and Deleted !
Update: yes - there IS a much better way to write this:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE
AS
INSERT INTO dbo.tblHistoryTable(Col1, Col2, Col3, ...., ColN)
SELECT Col1, COl2, Col3, ..... ColN
FROM Deleted d
INNER JOIN Inserted i ON i.PrimaryKey = d.PrimaryKey
WHERE i.statusCode <> d.statusCode
AND d.statusCode IN ('A', 'P')
Basically:
explicitly specify the columns you want to insert - both in the INSERT statement as well as the SELECT statement retrieving the data to insert - to avoid any nasty surprises
create an INNER JOIN between Inserted and Deleted pseudo-tables to get all rows that were updated
specify all other conditions (different status codes etc.) in the WHERE clause of the SELECT
This solution works for batches of rows being updated - it won't fail on a multi-row update....
You need to use both the inserted and deleted tables together to check for records that:
1. Already existed (to check it's not an insert)
2. Still exists (to check it's not a delete)
3. The Status field changed
You also need to make sure you do that in a set based approach, as per marc_s's answer, triggers are not single record processes.
INSERT INTO
tblHistoryTable
SELECT
deleted.*
FROM
inserted
INNER JOIN
deleted
ON inserted.PrimaryKey = deleted.PrimaryKey
WHERE
inserted.StatusCode <> deleted.StatusCode
AND (inserted.StatusCode = 'P' OR inserted.StatusCode = 'A')
inserted = the new values
deleted = the old values
There is no updated table, you are looking for inserted.

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.