SQL Trigger to update multiple columns in a View - sql

I have this trigger that updates the value format of a column, But I would like to make it update on more then one column in a view instead of a table.
The trigger;
CREATE TRIGGER [dbo].[TriigerName]
ON [dbo].[Table]
AFTER INSERT
AS
BEGIN
UPDATE
t
SET
t.ColName = dbo.FunctionName(i.ColName)
FROM
dbo.table t
INNER JOIN
inserted i
ON
i.PrimaryId = t.PrimaryId
END
I have tried adding a second t.colName = dbo.FunctionName(i.colName) under SET but that did not work. The query ran, but did not update the value in the second column.
How can I modify this trigger to make it run on a view?
Thanks
EDIT 1:
I get this error ; View or function 't' is not updatable because the modification affects multiple base tables.
and I also changed AFTER INSERT to INSTEAD OF INSERT.

I think that your error message is normal. I guess your view is based on multiple tables
Any INSERT, UPDATE, or DELETE operation on a join view can modify only one underlying base table at a time.
Check this link:
http://docs.oracle.com/cd/B10501_01/server.920/a96521/views.htm#391

As user3238101 said, you cannot update 2 different tables with one statement, so you need to make 2 statements.
CREATE TRIGGER [dbo].[TriigerName]
ON [dbo].[Table]
AFTER INSERT
AS
BEGIN
UPDATE
t
SET
t.ColName = dbo.FunctionName(i.ColName)
FROM
dbo.table t
INNER JOIN
inserted i
ON
i.PrimaryId = t.PrimaryId
UPDATE
t
SET
t.ColName2 = dbo.FunctionName2(i.ColName2)
FROM
dbo.table t
INNER JOIN
inserted i
ON
i.PrimaryId = t.PrimaryId
END

Related

Trigger for update base on parent table condition

Hi I use SQL SERVER 2012 and I have two table named tbcustomer and tbcustomerdetail. Both tables have column customerID.
I manage only tbcustomerdetail. If I update tbcustomerdetail where customerID='001' then I need the trigger to update tbcustomer where customerID='001'
I try this but not found spelling.
CREATE TRIGGER Deletecustomer
ON tbcustomerdetail
FOR UPDATE
AS
BEGIN
update tbcustomer tbcustomer.status=0 where tbcustomer.customerID=updated.customerID;
END
//updated.customerID is the ID on column tbcustomerdetail where customerID is '001'.
I also tried AFTER UPDATE but it doesn't work.
Updated does not exist, in a trigger you have two views Deleted which contains previous data and Inserted contains the new one
As I mentioned they are views, and contains data for all the rows affected by the statement, so, you need to use them in a join
CREATE TRIGGER Deletecustomer
ON tbcustomerdetail
FOR UPDATE
AS
BEGIN
UPDATE C
SET Status = 0
FROM tbCustomer C
JOIN Inserted I ON C.CustomerID = I.CustomerID
END

SQL Server : make update trigger don't activate with no changing value

I want to track the update changes in a table via a trigger:
CREATE TABLE dbo.TrackTable(...columns same as target table)
GO
CREATE TRIGGER dboTrackTable
ON dbo.TargetTable
AFTER UPDATE
AS
INSERT INTO dbo.TrackTable (...columns)
SELECT (...columns)
FROM Inserted
However in real production some of the update queries select rows with vague conditions and update them all regardless of whether they are actually changed, like
UPDATE Targettable
SET customer_type = 'VIP'
WHERE 1 = 1
--or is_obsolete = 0 or register_date < '20160101' something
But due to table size and to analyze, I only want to choose those actually modified data for tracking. How to achieve this goal?
My track table has many columns (so I do not prefer checking inserted and deleted column one by one) but it seldom changes structure.
I guess the following code will be useful.
CREATE TABLE dbo.TrackTable(...columns same as target table)
GO
CREATE TRIGGER dboTrackTable
ON dbo.TargetTable
AFTER UPDATE
AS
INSERT INTO dbo.TrackTable (...columns)
SELECT *
FROM Inserted
EXCEPT
SELECT *
FROM Deleted
I realize this post is a couple months old now, but for anyone looking for a well-rounded answer:
To exit the trigger if no rows were affected on SQL Server 2016 and up, Microsoft recommends using the built-in ROWCOUNT_BIG() function in the Optimizing DML Triggers section of the Create Trigger documentation.
Usage:
IF ROWCOUNT_BIG() = 0
RETURN;
To ensure you are excluding rows that were not changed, you'll need to do a compare of the inserted and deleted tables inside the trigger. Taking your example code:
INSERT INTO dbo.TrackTable (...columns)
SELECT (...columns)
FROM Inserted i
INNER JOIN deleted d
ON d.[SomePrimaryKeyCol]=i.[SomePrimaryKeyCol] AND
i.customer_type<>d.customer_type
Microsoft documentation and w3schools are great resources for learning how to leverage various types of queries and trigger best practices.
Prevent trigger from doing anything if no rows changed.
Writing-triggers-the-right-way
CREATE TRIGGER the_trigger on dbo.Data
after update
as
begin
if ##ROWCOUNT = 0
return
set nocount on
/* Some Code Here */
end
Get a list of rows that changed:
CREATE TRIGGER the_trigger on dbo.data
AFTER UPDATE
AS
SELECT * from inserted
Previous stack overflow on triggers
#anna - as per #Oded's answer, when an update is performed, the rows are in the deleted table with the old information, and the inserted table with the new information –

After insert trigger for updating a column

I am writing an after insert trigger trying to find a solution to this problem here:
https://stackoverflow.com/questions/19355644/dead-ends-all-around-trying-to-update-geography-column
What I am unsure of is how to write the trigger to take into consideration multiple records as explained here as a potential you need to code for.
So far I had this but it applies only to a single record so if the table had 100 records inserted in a batch 99 would not be updated. This is my understanding so far and may not be correct.
create trigger tri_inserts on [dbo].[Address]
after insert
as
set nocount on
update Address
SET AddyGeoCode = GEOGRAPHY::Point(inserted.AddyLat, inserted.Addylong, 4326)
GO
Would I say join to the inserted table to discover / update all the new records?
In case it is needed my Address table schema is AddyLat & AddyLong decimal(7,4) and AddyGeoCode Geography.
TIA
Yes, you need to join on inserted table.
UPDATE a
SET a.AddyGeoCode = GEOGRAPHY::Point(a.AddyLat, a.Addylong, 4326) --you can use AddyLat&Long from either a or i
FROM Address a
INNER JOIN inserted i ON a.id = i.id --whatever are your PK columns

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 .....

How to use update trigger to update another table?

I am new to triggers and want to create a trigger on an update of a column and update another table with that value.
I have table1 with a year column and if the application updates that year column I need to update table 2 with the year the same year.
ALTER TRIGGER [dbo].[trig_UpdateAnnualYear]
ON [dbo].[table1]
AFTER UPDATE
AS
if (UPDATE (intAnnualYear))
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
Update table2 set AnnualYear = intAnnualYear where table2.ID = table1.ID
END
You don't reference table1 inside the trigger. Use the inserted pseudo table to get the "after" values. Also remember that an update can affect multiple rows.
So replace your current update statement with
UPDATE table2
SET table2.annualyear = inserted.intannualyear
FROM table2
JOIN inserted
ON table2.id = inserted.id
You only need to update the records in table2 if the column intannualyear is involved. Also, this is an alternative UPDATE syntax across two tables from what Martin has shown
IF UPDATE(intannualyear)
UPDATE table2
SET annualyear = inserted.intannualyear
FROM inserted
WHERE table2.id = inserted.id
According to this question, if there's only one "downstream" table then another option with a properly defined foreign key relation would be Cascaded update.
To supplement the above answers, if you have to check more than one column you can use a INNER JOIN between inserted and deleted, or several UPDATE() calls:
IF ( UPDATE(Col1) OR UPDATE(Col2) ) BEGIN ...