I'm trying to create a trigger that automatically updates a column for an entry in my table when that specific entry is updated.
The table name is "accounts". The column name is "modified" (it is a dateTime that states when this entry was last updated).
I am using SCOPE_IDENTITY() to point to the entry which I wish to update.
The trigger is created successfully, but when I update an entry, the column "modified" does not change. perhaps I'm using SCOPE_IDENTITY() incorrectly? Here is my code:
CREATE TRIGGER trg_UpdateModified
ON dbo.accounts
AFTER UPDATE
AS
UPDATE dbo.accounts
SET modified = GETDATE()
WHERE sysID = SCOPE_IDENTITY()
Thanks!!
Use the inserted table to tell you which row(s) have just been updated:
CREATE TRIGGER trg_UpdateModified
ON dbo.accounts
AFTER UPDATE
AS
IF UPDATE(modified) RETURN; --Don't react recursively
UPDATE dbo.accounts
SET modified = GETDATE()
WHERE sysID in (select sysID from inserted)
Related
I have written a trigger to execute when data is inserted on to a SQL Server table via a SSIS package. I want to insert today's date in to the date column in the table. My trigger is below it doesn't seem to work.
Can some one please help.
ALTER TRIGGER [dbo].[InsertDate]
ON dbo.Debtors
AFTER INSERT
AS
BEGIN
UPDATE dbo.Debtors
SET InsertDate = GETDATE()
FROM inserted
WHERE Debtors.id = inserted.id
END
Use a default value instead:
alter table dbo.Debtors add column InsertDate datetime default getdate();
No need for a trigger at all.
This is the query I used for creating a trigger to update the CreatedDate column of my table "websites"
create trigger [dbo].[trgrforcreateddate] on [dbo].[Websites]
after insert
as
update dbo.websites
set CreatedDate=getdate() from websites w inner join inserted i on w.website=i.website where w.website=i.website
It worked, only one should get updated with Created date (actually, the expected row is updated). But as a result I see
" rows updated"
Why?
For this you should be using a default constraint on CreatedDate instead of a trigger.
alter table dbo.websites add constraint df_websites_CreatedDate default getdate() for CreatedDate;
The trigger is not joining on a unique id, if it was you would see only 1 row affected for each insert. You should also use set nocount on; to prevent extra row result messages from being returned, but in this case it was good that it was not set so that you noticed the error.
alter trigger [dbo].[trgrforcreateddate] on [dbo].[Websites]
after insert
as
begin;
set nocount on;
update w
set w.CreatedDate=getdate()
from dbo.websites w
inner join inserted i
on w.id = i.id;
end;
I'm making a simple table with names, emails etc, but I also have a ModifiedDate. My idea is to use a trigger after both insert and update, and insert the current date. Thus if anyone does anything (except delete) to that column, the date should reflect that.
This is however not working.
CREATE TRIGGER ModDate
ON X
AFTER INSERT, UPDATE
AS
BEGIN
INSERT INTO X (ModifiedDate)
VALUES (GETDATE())
END
Now I have a couple of values that can't be null, and what this seems to do is try and create a new row. I would like it to insert the date into the row that is currently being acted upon, I have no idea how though. Also what if I add 5 rows at once ?
You need to join the inserted virtual table in the trigger to limit the rows that get updated to those actually changed. Try this:
CREATE TRIGGER ModDate
ON TableX
AFTER INSERT, UPDATE
AS
BEGIN
UPDATE X
SET ModifiedDate = GETDATE()
FROM TableX X
JOIN inserted i ON X.key = i.key -- change to whatever key identifies
-- the tuples
END
Like #ZoharPeled correctly pointed out in a comment below there's really not much point in having the trigger update the date on insert - it would be better to use getdate() as the default value on the column (or even as another column InsertedDate if you want to track when records were initially created) and have the trigger only modify the ModifiedDate column after updates.
See the documentation for more information on the inserted and deleted tables.
CREATE TRIGGER ModDate
ON TableX
FOR INSERT, UPDATE
AS
BEGIN
UPDATE TableX
SET ModifiedDate = GETDATE()
WHERE Id = (Select Id from Inserted)
END
If you don't have keys on the insert data and you are not in command of the sql to add a default on the modifieddate column, you can get the insert trigger where the modifieddate column is null:
CREATE TRIGGER ModDate
ON TableX
AFTER INSERT
AS
BEGIN
UPDATE tableX SET ModifiedDate = GETDATE() where modifieddate is null
END
Using Great Plains here and one of our users keeps screwing up customer data so we want to put a trigger on the customer table and so we can find out who it is.
Anyway, I created a table called audit_RM00101 as follows:
DATE nchar(10)
CUSTNMBR char(15)
CUSTNAME char(65)
UPSZONE char(3)
SALSTERR char(15)
USERID nchar(100)
I want to capture those same fields from the table I want to audit so I wrote the trigger as follows:
CREATE TRIGGER CatchCustomerRegionUpdate
ON RM00101
FOR UPDATE
AS
DECLARE #UserID VARCHAR(128)
SELECT #UserID = system_user
INSERT INTO audit_RM00101
SELECT DATE, CUSTNMBR, CUSTNAME, UPSZONE, SALSTERR, #UserID FROM UPDATED
The trigger gets created just fine but when I try to test it by updating a customer record in Great Plains, Great Plains throws up an ugly error and the trigger doesn't get fired.
What am I doing wrong here?
Thanks.
in a trigger, you get the DELETED and INSERTED tables, there is no UPDATED, so replace FROM UPDATED with FROM INSERTED
also try to fix your USERID column, your audit_RM00101.USERID is a nchar(100) while #UserID is a VARCHAR(128).
EDIT based on OPs comment: Ah, so there is no way to audit when a table is updated by using a trigger?
in a trigger when deleting, DELETED is populated, but INSERTED is empty
in a trigger when updating, DELETED is populated with the original value, and INSERTED is populated with the newly updated values
in a trigger when inserting, DELETED is empty, but INSERTED has the newly inserted values
There is no UPDATED in SQL Server; just inserted and deleted.
Also, it makes sense to add IF ##ROWCOUNT = 0 RETURN in the very beginning of triger's body.
When UPDATE takes place, both inserted and deleted tables are not empty. You may add the following code to make sure you handle UPDATE, not insert/delete:
IF EXISTS(SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted)
BEGIN
-- handle update
END ;
It's not really important for your trigger because you specify just FOR UPDATE, it would be important if you had, for instance, FOR UPDATE, INSERT, DELETE.
we have only two magic tables called INSERTED and DELETED
update indirectly is a Delete statement followed by Insert statement. so you have to update the column's value which is present in INSERTED.
CREATE TRIGGER CatchCustomerRegionUpdate
ON RM00101
AFTER UPDATE
AS
BEGIN
DECLARE #INSERTED INT, #DELETED INT
SET #INSERTED = SELECT COUNT(*) FROM INSERTED
SET #DELETED = SELECT COUNT(*) FROM DELETED
IF #INSERTED = 1 AND #DELETED = 1
BEGIN
UPDATE TABLE1
SET COL1 = INSERTED_COL1
WHERE IDCOL = INSERTED_IDCOL
END
END
The information should be 2 date time columns(inserted/updated) with ms precision and should be automatically updated by the server whenever someone inserts, or updates a row.
Add columns to your table
ALTER TABLE yourTable ADD
Inserted datetime NULL,
Updated datetime NULL
GO
Create an Update and Insert Trigger to update the columns
CREATE TRIGGER yourTableInsertTrigger
ON yourTable
AFTER INSERT
AS
BEGIN
Update yourTable Set Inserted = getdate()
from Inserted
Where yourTable.Key = Inserted.Key
END
GO
CREATE TRIGGER yourTableUpdateTrigger
ON yourTable
AFTER UPDATE AS
BEGIN
Update yourTable Set Updated = getdate()
from Updated
Where yourTable.Key = Updated.Key
END
GO
Now if you want to be really clean, you'd make sure that these two columns couldn't be changed/updated by using views instead of direct table access for your other access to the data. Also if your primary keys aren't consistent, and you have many tables I'd suggest you use CodeGeneration to create the sql. MyGeneration would do nicely.
I think the inserted trigger is obsolete. Just add getdate() to the inserted column as a default value instead of null.