I have a table containing id, user_Name and password. I want to create the trigger which will fire when ever the password changes.
Suppose the table is:
create table reg
(
id int identity(1,1) primary key,
userName varchar(100),
pass varchar(100)
)
and I want to save userName, password, changeDate in to below table
create table regBackUp
(
id int identity(1,1),
regId foreign key references reg(id),
oldPass varchar(100),
changeDate date
)
Well, you need to create after update trigger on reg table.
In that trigger you need to write to table regBackUp records selected from table named deleted. It is special table available in that triggers and it will hold values of reg table just before update.
See MSDN for reference about syntax of create trigger expression.
Use this. TRIGGER
You can get the old values from DELETED table
CREATE TRIGGER trgTest ON regFOR UPDATE
AS
BEGIN
IF UPDATE(pass)
BEGIN
DECLARE #id AS INT
DECLARE #pass AS varchar(100)
SELECT #id = ID, #pass = pass FROM DELETED
INSERT INTO regBackUp (regId, oldPass, changeDate)
VALUES (#id, #pass, GETDATE())
END
END
Use After Update Trigger with Update() function to find out whether column is updated or not. From docs.
indicates whether an INSERT or UPDATE attempt was made on a specified
column of a table or view. UPDATE() is used anywhere inside the body
of a Transact-SQL INSERT or UPDATE trigger to test whether the trigger
should execute certain actions.
Create a After Update trigger like this.
CREATE TRIGGER reg_pass_trg
ON reg
after UPDATE
AS
BEGIN
IF UPDATE(pass) --Works only when pass is mentioned in update statement
INSERT INTO regBackUp
(regId,oldPass,changeDate)
SELECT ID,pass,Getdate()
FROM deleted
END
INSERT INTO namepassback
(username,
pass,
[date])
SELECT username,
pass,
Getdate()
FROM namepass
WHERE id = 1
use above query that will work same without creating trigger
Related
I need to create a new DATETIME column in SQL Server that will always contain the date of when the record was created, and then it needs to automatically update whenever the record is modified. I've heard people say I need a trigger, which is fine, but I don't know how to write it. Could somebody help with the syntax for a trigger to accomplish this?
In MySQL terms, it should do exactly the same as this MySQL statement:
ADD `modstamp` timestamp NULL
DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
Here are a few requirements:
I can't alter my UPDATE statements to set the field when the row is modified, because I don't control the application logic that writes to the records.
Ideally, I would not need to know the names of any other columns in the table (such as the primary key)
It should be short and efficient, because it will happen very often.
SQL Server doesn't have a way to define a default value for UPDATE.
So you need to add a column with default value for inserting:
ADD modstamp DATETIME2 NULL DEFAULT GETDATE()
And add a trigger on that table:
CREATE TRIGGER tgr_modstamp
ON **TABLENAME**
AFTER UPDATE AS
UPDATE **TABLENAME**
SET ModStamp = GETDATE()
WHERE **ID** IN (SELECT DISTINCT **ID** FROM Inserted)
And yes, you need to specify a identity column for each trigger.
CAUTION: take care when inserting columns on tables where you don't know the code of the application. If your app have INSERT VALUES command without column definition, it will raise errors even with default value on new columns.
This is possible since SQL Server 2016 by using PERIOD FOR SYSTEM_TIME.
This is something that was introduced for temporal tables but you don't have to use temporal tables to use this.
An example is below
CREATE TABLE dbo.YourTable
(
FooId INT PRIMARY KEY CLUSTERED,
FooName VARCHAR(50) NOT NULL,
modstamp DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
MaxDateTime2 DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
PERIOD FOR SYSTEM_TIME (modstamp,MaxDateTime2)
)
INSERT INTO dbo.YourTable (FooId, FooName)
VALUES (1,'abc');
SELECT *
FROM dbo.YourTable;
WAITFOR DELAY '00:00:05'
UPDATE dbo.YourTable
SET FooName = 'xyz'
WHERE FooId = 1;
SELECT *
FROM dbo.YourTable;
DROP TABLE dbo.YourTable;
It has some limitations.
The time stored will be updated by the system and always be UTC.
There is a need to declare a second column (MaxDateTime2 above) that is completely superfluous for this use case. But it can be marked as hidden making it easier to ignore.
Okay, I always like to keep track of not only when something happened but who did it!
Lets create a test table in [tempdb] named [dwarfs]. At a prior job, a financial institution, we keep track of inserted (create) date and updated (modify) date.
-- just playing
use tempdb;
go
-- drop table
if object_id('dwarfs') > 0
drop table dwarfs
go
-- create table
create table dwarfs
(
asigned_id int identity(1,1),
full_name varchar(16),
ins_date datetime,
ins_name sysname,
upd_date datetime,
upd_name sysname,
);
go
-- insert/update dates
alter table dwarfs
add constraint [df_ins_date] default (getdate()) for ins_date;
alter table dwarfs
add constraint [df_upd_date] default (getdate()) for upd_date;
-- insert/update names
alter table dwarfs
add constraint [df_ins_name] default (coalesce(suser_sname(),'?')) for ins_name;
alter table dwarfs
add constraint [df_upd_name] default (coalesce(suser_sname(),'?')) for upd_name;
go
For updates, but the inserted and deleted tables exist. I choose to join on the inserted for the update.
-- create the update trigger
create trigger trg_changed_info on dbo.dwarfs
for update
as
begin
-- nothing to do?
if (##rowcount = 0)
return;
update d
set
upd_date = getdate(),
upd_name = (coalesce(suser_sname(),'?'))
from
dwarfs d join inserted i
on
d.asigned_id = i.asigned_id;
end
go
Last but not least, lets test the code. Anyone can type a untested TSQL statement in. However, I always stress testing to my team!
-- remove data
truncate table dwarfs;
go
-- add data
insert into dwarfs (full_name) values
('bilbo baggins'),
('gandalf the grey');
go
-- show the data
select * from dwarfs;
-- update data
update dwarfs
set full_name = 'gandalf'
where asigned_id = 2;
-- show the data
select * from dwarfs;
The output. I only waited 10 seconds between the insert and the delete. Nice thing is that who and when are both captured.
Create trigger tr_somename
On table_name
For update
As
Begin
Set nocount on;
Update t
Set t.field_name = getdate()
From table_name t inner join inserted I
On t.pk_column = I.pk_column
End
ALTER TRIGGER [trg_table_name_Modified]
ON [table_name]
AFTER UPDATE
AS
Begin
UPDATE table_name
SET modified_dt_tm = GETDATE() -- or use SYSDATETIME() for 2008 and newer
FROM Inserted i
WHERE i.ID = table_name.id
end
I need to insert records into a production table. The problem is that one of the fields needs to be the same value as the primary key.
In the example below, the Insert query is dropping '99' into [AlsoMyID]. But that's just a placeholder. It needs to be whatever value is going into [MyID].
How do I write the Insert query so that the system will add the same PK value to both [MyID] and [AlsoMyID]?
Drop table #mylittletable
Create table #Mylittletable (
[MyID] int IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[AlsoMyID] int,
[ActualData] varchar(1))
Select * from #Mylittletable
Insert into #Mylittletable values (99,'x')
Select * from #Mylittletable
If you're interested in the background, the developer is using AlsoMyID as a linking field so any number of records can be linked together using the original primary key value. That said, I have no control over the table structure.
Firstly, you cannot specify the value for identity column unless you use set identity_insert on. so according to your requirement, you need to insert the same value to AlsoMyID as MyID.
You can work it out as flowing:
insert into Mylittletable
select ##IDENTITY+1,'1'
With this trigger on the table you can insert anything on the alsoMyID-column and that will be overwritten with what get's set in the myID-column.
create trigger tr_Mylittletable ON Mylittletable
AFTER INSERT AS
BEGIN
declare #ID int = (select MyID from inserted)
update Mylittletable set AlsoMyID = #ID where MyID = #ID
END
NOTE: This only works when making inserts of one line at a time!
I have a column named htmlContent which stores HTML Content in table EEmailData and a column named EEmailDataID which is unique ID of this table or I can say primary key of this table.
Now what I want to do is I want to create a trigger which would get this primary key from this table and insert this EEmailDataID in column htmlContent on a specific location.
I think this would take place by SUBSTRING function. Can anybody suggest me some other solution?
For this you need to add an idwhere you want to replace the Primary key value
Eg: <a href="localhost:19763/BitBucket/GUEST/... ?GuestInviteFwd=uArAiAd
And use the following trigger
CREATE TRIGGER EEmailData_Trigg ON EEmailData
AFTER INSERT
AS
IF EXISTS (SELECT top(1)*
FROM EEmailData p
JOIN inserted AS i
ON p.EEmailDataID = i.EEmailDataID
)
BEGIN
DECLARE #html VARCHAR(MAX),#id INT
SELECT #html=htmlContent ,#id=EEmailData
FROM EEmailData
WHERE EEmailDataID =(SELECT TOP(1) EEmailDataID FROM inserted)
UPDATE EEmailData
SET htmlContent=REPLACE(#html,'uArAiAd',#id)
WHERE EEmailDataID=#id
END
Now after trigger uArAiAd is replaced by EEmailDataID
also you can achieve this without trigger.
Just do the following after insert.
DECLARE #html VARCHAR(MAX),#id INT
--insert statements
SET #id=SCOPE_IDENTITY()
SELECT #html=htmlContent ,#id=EEmailData
FROM EEmailData
WHERE EEmailDataID =#id
UPDATE EEmailData
SET htmlContent=REPLACE(#html,'uArAiAd',#id)
WHERE EEmailDataID=#id
I want to create a before delete trigger. When I delete a record from a table that record has to be inserted into a history table. How can I do this in SQL Server?
In this situation, you're probably better off doing a regular "after" trigger. This is the most common approach to this type of situation.
Something like
CREATE TRIGGER TRG_AUD_DEL
ON yourTable
FOR DELETE
AS
INSERT INTO my_audit_table (col1, col2, ...)
SELECT col1, col2...
FROM DELETED
What will happen is, when a record (or records!) are deleted from your table, the deleted row will be inserted into my_audit_table The DELETED table is a virtual table that contains the record(s) as they were immediately prior to the delete.
Also, note that the trigger runs as part of the implicit transaction on the delete statement, so if your delete fails and rolls back, the trigger will also rollback.
You could also use INSTEAD OF DELETE
CREATE TRIGGER dbo.SomeTableYouWhatToDeleteFrom
ON dbo.YourTable
INSTEAD OF DELETE
AS
BEGIN
-- Some code you want to do before delete
DELETE YourTable
FROM DELETED D
INNER JOIN dbo.YourTable T ON T.PK_1 = D.PK_1
END
It could be done in following steps for let’s say in this example I am using customer table:
CREATE TABLE CUSTOMERS(
ID INT NOT NULL,
NAME VARCHAR (20) NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR (25) ,
LAST_UPDATED DATETIME,
PRIMARY KEY (ID)
);
Create History:
CREATE TABLE CUSTOMERS_HIST(
ID INT NOT NULL,
NAME VARCHAR (20) NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR (25) ,
LAST_UPDATED DATETIME,
PRIMARY KEY (ID)
);
Trigger on source table like below on delete event:
CREATE TRIGGER TRG_CUSTOMERS_DEL
ON CUSTOMERS
FOR DELETE
AS
INSERT INTO CUSTOMERS_HIST (ID, NAME, AGE, ADDRESS, LAST_UPDATED)
SELECT ID, NAME, AGE, ADDRESS, LAST_UPDATED
FROM DELETED
Try a trigger that executes before the delete and throws an error when the condition is not met.
CREATE TRIGGER [dbo].[TableName_PreventDeleteAndUpdate]
ON dbo.TableName
FOR DELETE, UPDATE -- runs before deletes and updates
AS
BEGIN
IF (APP_NAME() <> 'SomeApp')
BEGIN
RAISERROR ('Only delete/update with SomeApp', 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END
END
I have a simple details table like so:
listid
custid
status
last_changed
The primary key consists of both listid and custid.
Now I'm trying to setup a trigger that sets the last_changed column to the current datetime every time an insert or update happens. I've found lots of info on how to do that with a single PK column, but with multiple PKs it gets confusing on how to correctly specify the PKs from the INSERTED table.
The trigger has to work in SQL Server 2005/2008/R2.
Thanks for a working trigger code!
Bonus would be to also check if the data was actually altered and only update last_changed in that case but for the sake of actually understanding how to correctly code the main question I'd like to see this as a separate code block if at all.
Hmm.... just because the primary key is made up of two columns shouldn't really make a big difference....
CREATE TRIGGER dbo.trgAfterUpdate ON dbo.YourTable
AFTER INSERT, UPDATE
AS
UPDATE dbo.YourTable
SET last_changed = GETDATE()
FROM Inserted i
WHERE dbo.YourTable.listid = i.listid AND dbo.YourTable.custid = i.custid
You just need to establish the JOIN between the two tables (your own data table and the Inserted pseudo table) on both columns...
Are am I missing something?? .....
CREATE TRIGGER dbo.trgAfterUpdate ON dbo.YourTable
AFTER INSERT, UPDATE
AS
UPDATE dbo.YourTable
SET last_changed = GETDATE()
FROM Inserted i
JOIN dbo.YourTable.listid = i.listid AND dbo.YourTable.custid = i.custid
WHERE NOT EXISTS
(SELECT 1 FROM Deleted D Where D.listid=I.listid AND D.custid=i.custid AND (D.status=i.status)
Here i assuming that stasus column is not nullable. If yes, you should add additional code to check if one of columns is NULL
You can check every field in trigger by comparing data from inserted and deleted table like below :
CREATE TRIGGER [dbo].[tr_test] ON [dbo].[table]
AFTER INSERT, UPDATE
AS
BEGIN
DECLARE #old_listid INT
DECLARE #old_custid INT
DECLARE #old_status INT
DECLARE #new_listid INT
DECLARE #new_custid INT
DECLARE #new_status INT
SELECT #old_listid=[listid], #old_custid=[custid], #old_status = [status] FROM [deleted]
SELECT #new_listid=[listid], #new_custid=[custid], #new_status = [status] FROM [inserted]
IF #oldstatus <> #new_status
BEGIN
UPDATE TABLE table SET last_changed = GETDATE() WHERE [listid] = #new_listid AND [custid] = #new_custid
END
END