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
Related
As the title says, I'm trying to update a specific row and column in one table, based on what a specific column in another table in another table is updated to. I have not been able to find anything on stack overflow specific to what I'm trying to do. So far, it's either updating one table based on the same table, or making an update based on whether the column changed (not looking for a specific value).
That said, I have so far pieced together the following code from my research on stack overflow:
CREATE TRIGGER trUpdateTaskToComplete on [DBName].[dbo].[Projects]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE [DBName].[dbo].[TaskTracker]
SET Complete=1
FROM [DBName].[dbo].[Projects] t
INNER JOIN inserted i on t.id = i.id
AND i.Status='Complete'
END
This does 90% of what I need it to do, with the exception that it updates ALL the rows on the TaskTracker table that is associated with the project ID. How could I get it to only set Complete=1 on the rows where the Task (a column from TaskTracker) has the value of "ProjectIsComplete"? I tried something like this:
UPDATE [DBName].[dbo].[TaskTracker]
SET Complete=1
WHERE Task = "ProjectIsComplete"
FROM [DBName].[dbo].[Projects] t
INNER JOIN inserted i on t.id = i.id
AND i.Status='Complete'
but it seems that SQL Server is not about that life. What can I do to make my trigger work? Note: I only what the field set to complete for rows that have the Task value of "ProjectIsComplete" AND is still for the related ID. Thank you for any advice that can be offered!
Thanks to Sean Lange for the answer. The correct code is as follows:
CREATE TRIGGER trUpdateTaskToComplete on [DBName].[dbo].[Projects]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE [DBName].[dbo].[TaskTracker]
SET Complete=1
FROM [DBName].[dbo].[Projects] t
INNER JOIN inserted i on t.id = i.id
AND i.Status='Complete'
WHERE Task = 'Complete'
END
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 –
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
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
I have a table that looks like the below table:
Every time the user loan a book a new record is inserted.
The data in this table is derived or taken from another table which has no dates.
I need to update this tables based on the records in the other table: Meaning I only need to update this table based on what changes.
Example: Lets say the user return the book Starship Troopers and the book return is indicated to Yes.
How do I update just that column?
What I have tried:
I tried using the MERGE Statement but it works only with unique rows of data, meaning you get an error if the same ID appears more than once.
I also tried using a basic UPDATE Statement and a JOIN but that's not going well.
I am asking because I have ran out of ideas.
Thanks for reading
If you need to update BooksReturn in target table based on the same column in source table
UPDATE t
SET t.booksreturn = s.booksreturn
FROM target t JOIN source s
ON t.userid = s.userid
AND t.booksloaned = s.booksloaned
Here is SQLFiddle demo
You can do this by simple Update & Insert statement.....
Two table A & B
From B you want to insert data into A if not exists other wise Update that data....
,First Insert into temp table....
SELECT *
INTO #MYTEMP
FROM B
WHERE BOOKSLOANED NOT IN (SELECT BOOKSLOANED
FROM A)
,Second Check data and insert into A.
INSERT INTO A
SELECT *
FROM #MYTEMP
And at last write one simple update statement which update all data of A. If any change then it also reflect to that data otherwise data as it is.
You can also update from #MYTEMP table.