basically i am looking for logic to generate insert or update statement in string variable from trigger. suppose when people just update 'N' of fields like update statement....then my trigger will fire and from that trigger i want build what update statement was issued by user and store in string variable
the same way i want to build insert statement from trigger too but i am not getting logic. so if anyone has any idea or sample code then please share with me to achieve my goal.
ALTER TRIGGER WSContent AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
DECLARE #Action VARCHAR(10)
DECLARE #PKValue INT
DECLARE #TableName VARCHAR(50)
SET #TableName='website_content'
IF EXISTS(SELECT * FROM INSERTED)
BEGIN
IF EXISTS(SELECT * FROM DELETED)
BEGIN
SET #Action ='U';
SELECT #PKValue=ContentNumber from DELETED
END
ELSE
BEGIN
SET #Action ='I';
SELECT #PKValue=ContentNumber from INSERTED
END
END
ELSE
BEGIN
SET #Action = 'D';
SELECT #PKValue=ContentNumber from DELETED
END;
INSERT INTO [ContentChangeLog]([PkValue],[TableName],[Action],ActionDate)
VALUES(#PKValue,#TableName,#Action,GetDate())
SET NOCOUNT OFF;
Like many people, you misunderstand how a trigger works. When you insert, update or delete multiple records, the trigger is called once and the tables deleted/inserted can contain multiple records, not 1 for each record effected. You need to rewrite this assuming you have multiple records in those tables.
INSERT INTO [ContentChangeLog]([PkValue],[TableName],[Action],ActionDate)
SELECT ContentNumber, #TableName, 'I', GETDATE()
FROM INSERTED i
WHERE not exists(SELECT TOP 1 1 FROM DELETED WHERE ContentNumber = i.ContentNumber)
Here is an example of the Inserted records only, you will want to do something similar for your updates and deletes.
Related
I have a merge statement supposed to execute a trigger multiple times.
I first thought my trigger wasn't executing, but with some research I found that triggers are only triggered once per statement (a trigger being one statement).
But all the posts out there are old and I thought that there might be a simple way now to make my trigger execute multiple times.
So is there anything I can add to my trigger or my merge statement to make my trigger do so?
Thanks
TRIGGER
TRIGGER [dbo].[Sofi_TERA_Trigger]
ON [dbo].[ZZ]
AFTER INSERT,UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF EXISTS(SELECT 1 FROM inserted WHERE inserted.Statut LIKE '%CLOT%' OR inserted.Statut LIKE '%CLTT%' OR inserted.Statut LIKE '%CONF%')
BEGIN
DECLARE #Id int;
DECLARE #Matricule varchar(10);
DECLARE #IdAction int;
DECLARE #NumeroOF int;
SELECT #NumeroOF = inserted.Ordre from inserted;
DECLARE OF_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT Id,Log.Matricule,IdAction from Log inner join (select max(Id) as maxID,Matricule from LOG where Log.NumeroOF = #NumeroOF group by Matricule) maxID
on maxID.maxID = Log.Id where Log.NumeroOF = #NumeroOF;
OPEN OF_CURSOR
FETCH NEXT FROM OF_CURSOR INTO #Id,#Matricule,#IdAction
WHILE ##FETCH_STATUS = 0
BEGIN
IF #IdAction!=13
BEGIN
IF #IdAction<=2
BEGIN
insert into Log(NumeroOF,Matricule,IdAction,Date,EstAdmin) values (#NumeroOF,#Matricule,13,GETDATE(),1);
END
ELSE
BEGIN
insert into Log(NumeroOF,Matricule,IdAction,Date,EstAdmin) values (#NumeroOF,#Matricule,2,GETDATE(),1);
insert into Log(NumeroOF,Matricule,IdAction,Date,EstAdmin) values (#NumeroOF,#Matricule,13,GETDATE(),1);
END
END
FETCH NEXT FROM OF_CURSOR INTO #Id,#Matricule,#IdAction
END
CLOSE OF_CURSOR;
DEALLOCATE OF_CURSOR;
END
END
MERGE STATEMENT
Merge ZZ AS TARGET USING ZZTemp AS SOURCE
ON (Target.Operation=Source.Operation AND Target.Ordre=Source.Ordre)
WHEN MATCHED THEN
UPDATE SET TARGET.DateTERA=SOURCE.DateTERA, TARGET.MatTERA=SOURCE.MatTERA, TARGET.MatTERC=SOURCE.MatTERC
WHEN NOT MATCHED THEN
INSERT(Operation,Ordre,ElementOTP,Article,DesignationOF,PosteTravail,ValeurTemps,DHT,Statut,StatutOF,TexteActivite,DateTERA,MatTERA,MatTERC,StatutMat)
VALUES(SOURCE.Operation,SOURCE.Ordre,SOURCE.ElementOTP,SOURCE.Article,SOURCE.DesignationOF,SOURCE.PosteTravail,SOURCE.ValeurTemps,SOURCE.DHT,
SOURCE.Statut,SOURCE.StatutOF,SOURCE.TexteActivite,SOURCE.DateTERA,SOURCE.MatTERA,SOURCE.MatTERC,SOURCE.StatutMat);
Your problem is the cursor is incorrectly written to handle sets of data. Any trigger setting a value form inserted or deleted to a scalar variable is incorrect and for reasons of data integrity MUST be rewritten. This trigger is buggy. Period. There is no getting around that it must be rewritten (and any others that use the same technique).
The code inside your trigger should be something like:
INSERT INTO Log(NumeroOF,Matricule,IdAction,Date,EstAdmin)
SELECT max(Id),l.Matricule,l.IdAction, 13,GETDATE(),1
FROM Log l
JOIN Inserted i ON l.NumeroOF = i.Ordre
WHERE i.Statut LIKE '%CLOT%' OR i.Statut LIKE '%CLTT%' OR i.Statut LIKE '%CONF%'
GROUP BY l.Matricule,l.IdAction
INSERT INTO Log(NumeroOF,Matricule,IdAction,Date,EstAdmin)
SELECT max(Id),l.Matricule,l.IdAction, 2,GETDATE(),1
FROM Log l
JOIN Inserted i ON l.NumeroOF = i.Ordre
WHERE IdAction<=2
WHERE i.Statut LIKE '%CLOT%' OR i.Statut LIKE '%CLTT%' OR i.Statut LIKE '%CONF%'
GROUP BY l.Matricule,l.IdAction
Make sure to test with both single record and multiple record inserts as all triggers should be tested. Then try your MERGE once you are confident the trigger is correct.
Instead of trigger i am planning to write a procedure which we can run using job which will work same way as TRIGGER
with these two tables in the same way.
how can i do that?
here are my tables with column names
1.tblcal
ID(int,not null)
UID(varchar(10),null)
Desc(varchar(200),null)
Date(datetime,null)
avbl(varchar(5),null)
2.tblEvent
ID(int,notnull)
UID(varchar(10),null)
Desc(varchar(200),null)
Date(datetime,null)
Down is my trigger on tblEvent..
ALTER TRIGGER [dbo].[trU] ON [dbo].[tblEvent]
FOR INSERT
AS
Declare #CuID char(6),
#CuDesc char(40),
#CuDate datetime
SET NOCOUNT ON
Select #CuID = i.UID , #CuDesc=i.Desc, #CuDate=i.Date From Inserted i
If(#CuDesc !='available')
Begin
Update tblCal set avbl='Out', Desc=#CurDesc where cadate=#CuDate and UID=#CuID
ENd
SET NOCOUNT OFF
I have another problem with Desc column.Desc which are going to be in and out Basically we need to update tblcal differently for different descriptions;in that case I don't think trigger is that reliable;Means for example for 10 Desc we need to update in and for other 10 we need to update out
Actually every thursday on the tblevent data is loaded once its loaded it fired a trigger and will update in tblcal.
but my client is looking for a procedure which we can schedule as a job after the tblevent entry done on Thursday.
How can i do with stored procedure?
Procedure
CREATE PROCEDURE dbo.usp_UpdateEventData
AS
BEGIN
SET NOCOUNT ON;
UPDATE C
SET c.avbl = 'Out'
,c.[Desc] = e.[Desc]
FROM [dbo].tblCal C
INNER JOIN [dbo].[tblEvent] e ON c.[UID] = e.[UID]
AND c.cadate = e.[Date] --<-- check if you only want
WHERE e.[Desc] <> 'available' -- to join on date not datetime
END -- CAST both columns to DATE
Also if you are keeping your Trigger as it is you will need to modify the trigger definition to handle multiple Inserts, You can use the same logic as in this procedure to update your trigger definition.
Trigger Fix
ALTER TRIGGER [dbo].[trU] ON [dbo].[tblEvent]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE C
SET c.avbl = 'Out'
,c.[Desc] = i.[Desc]
FROM [dbo].tblCal C
INNER JOIN inserted i ON c.[UID] = i.[UID]
AND c.cadate = i.[Date]
WHERE i.[Desc] <> 'available'
END
Whenever INSERT is happened in the CUSTOMER table,I need to call the "StoredProcedure1"and
UPDATE is happend in the CUSTOMER table,I need to call the "StoredProcedure2" in the Trigger.
How to determine if insert or update in the trigger from SQL Server 2008.
Some one can please help me how to solve?
Code:
CREATE TRIGGER Notifications ON CUSTOMER
FOR INSERT,UPDATE
AS
BEGIN
DECLARE #recordId varchar(20);
set #recordId= new.Id;
//if trigger is insert at the time I call to SP1
EXEC StoredProcedure1 #recordId
//if trigger is Upadeted at the time I call to SP2
EXEC StoredProcedure2 #recordId
END
Let SQL Server be SQL Server, and have it do the work for you!
Create separate triggers for each change event (insert,update and/or delete).
Put the logic for each into the trigger that needs it.
No need to have to check for the event type.
And don't call a procedure unless it is quick, fast, and can't block others.
The easiest way to solve this problem would be to have two triggers, one for the insert and one for the update.
CREATE TRIGGER InsertNotifications ON CUSTOMER
FOR INSERT
AS
BEGIN
DECLARE #recordId varchar(20);
set #recordId= new.Id;
//if trigger is insert at the time I call to SP1
EXEC StoredProcedure1 #recordId
END
CREATE TRIGGER UpdateNotifications ON CUSTOMER
FOR UPDATE
AS
BEGIN
DECLARE #recordId varchar(20);
set #recordId= new.Id;
//if trigger is Upadeted at the time I call to SP2
EXEC StoredProcedure2 #recordId
END
Try this code for trigger for INSERT, UPDATE and DELETE. This works fine on Microsoft SQL SERVER 2008
if (Select Count(*) From inserted) > 0 and (Select Count(*) From deleted) = 0
begin
print ('Insert...')
end
if (Select Count(*) From inserted) = 0 and (Select Count(*) From deleted) > 0
begin
print ('Delete...')
end
if (Select Count(*) From inserted) > 0 and (Select Count(*) From deleted) > 0
begin
print ('Update...')
end
On an INSERT, the virtual DELETED table will be empty.
create or replace trigger comp
before
insert or delete or update
on student
referencing old as o new as n
for each row
begin
if deleting then
insert into student_backup values
(:o.studid,:o.studentname,:o.address,:o.contact_no,:o.branch,sysdate);
end if;
if inserting then
insert into student_backup values
(:n.studid,:n.studentname,:n.address,:n.contact_no,:n.branch,sysdate);
end if;
if updating then
insert into student_backup values
(:o.studid,:o.studentname,:o.address,:o.contact_no,:o.branch,sysdate);
end if;
end comp;
Here is my trigger
Create TRIGGER [dbo].[tri_before_update]
ON [dbo].[test]
instead of update
AS
BEGIN
SET NOCOUNT ON;
if update (test_a)
begin
*.. my update & insert query*
end
END
create TRIGGER [dbo].[tri_before_update_price]
ON [dbo].[co_ticket]
instead of update
AS
BEGIN
SET NOCOUNT ON;
if update (t_price)
begin
insert into old_price_log (t_id,insert_time,process_id,old_t_price)
select i.t_id,getdate(),2,t_price
from Inserted i,co_ticket t where i.t_id = t.t_id
update t set t_price = i.t_price
from co_ticket t, inserted i
where t.t_id = i.t_id
end
else
begin
-- if update other then (t_price) then the update comand not execute.
-- example when i update t_cancel_flag or t_quantity and etc. end
END
This trigger execute perfectly when i update on column "test_a". HOWEVER, when i update other than column "test_a" it won't be execute. I know i can put "else" command, but i got a lot of column. sometimes will update two other column , sometimes three or four column. I don't wish to update all column everytime. Is it possible ELSE "then execute original query"?
I tried a lot different way but still can't work. :( Please HELP!
create TRIGGER [dbo].[tri_on_update_price]
ON [dbo].[co_ticket]
AS
BEGIN
SET NOCOUNT ON;
if update (t_price)
begin
insert into old_price_log (t_id,insert_time,process_id,old_t_price)
select d.t_id, getutcdate(),2,d.price
from deleted d
END
end
An ordinary after trigger will do just what you want: insert a log of the price change, if the price was updated. No need for INSTEAD OF. You need to look into the deleted pseudo-table to get the old price. Never store local times in a database.
I have created a table with the following columns: ObservationId, FirstCreatedDate, description, ... ... and LastUpdatedDate in SQL Server 2008 R2. The ObservationId is an identity with increment by 1.
I need to create two triggers, one for INSERT and the other for UPDATE. On new record inserted, the INSERT trigger will update FirstCreatedDate column by getting the current datetime; while on existing record updated, the UPDATE trigger will update LastUpdatedDate colunm by getting the current datetime.
I have failed in doing this as I am guessing the identify might be the problem.
Could anyone give me a hand? Thanks!
Cheers,
Alex
ALTER TRIGGER [dbo].[T_InsertNewObservation] ON [dbo].[GCUR_OBSERVATION]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
UPDATE GCUR_OBSERVATION SET GCUR_OBSERVATION.FirstCreatedDate = getdate()
FROM GCUR_OBSERVATION a INNER JOIN INSERTED ins ON a.ObservationId = ins.ObservationId
END
I think you are mostly correct but are not accessing the INSERTED or DELETED tables correctly.
ALTER TRIGGER [dbo].[T_InsertNewObservation] ON [dbo].[GCUR_OBSERVATION]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- get the last id value of the record inserted or updated
DECLARE #id INT
SELECT #id = [ObservationId]
FROM INSERTED
-- Insert statements for trigger here
UPDATE GCUR_OBSERVATION
SET GCUR_OBSERVATION.FirstCreatedDate = GETDATE()
WHERE [ObservationId] = #id
END
PS. Hopefully this works as I wrote it in notepad and haven't tested it.
The code below is for AFTER UPDATE to modify last changed date column.
Please advice if you see any issue with it. Thanks!
ALTER TRIGGER [dbo].[T_UpdateObservation] ON [dbo].[GCUR_OBSERVATION]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- get the last id value of the record inserted or updated
DECLARE #id INT
SELECT #id = [ObservationId]
FROM DELETED
-- Insert statements for trigger here
UPDATE GCUR_OBSERVATION
SET GCUR_OBSERVATION.LastUpdatedDate = getdate()
WHERE [ObservationId] = #id
END
Create TRIGGER [dbo].[TrigerName] ON [dbo].[TableCreateTriger] FOR INSERT AS
INSERT INTO TableInsertDate SELECT * FROM TableCreateTriger