After insert, update trigger not running - sql

I have two triggers After Insert or Update and Instead of Insert. It appears that the after trigger is not running or sending the correct data.
I have verified the correct operation of Z_UpdateStageTable stored procedure and the Instead of Insert trigger. Removing the Instead of Insert trigger doesn't have any affect. The After Insert, Update trigger was working correctly at one time, I haven't made any changes to it. I have tried deleting it and adding it, but it still doesn't run or have the correct data.
Any Ideas?
Instead of Insert:
ALTER TRIGGER [DeleteExistingFilter]
ON [dbo].[Z_MobileSyncFilters]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM Z_MobileSyncFilters WHERE UserID = (SELECT UserID FROM INSERTED);
INSERT INTO Z_MobileSyncFilters
SELECT *
FROM INSERTED;
END
After Insert, Update:
TRIGGER [UpdateStageTable]
ON [dbo].[Z_MobileSyncFilters]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #AllWos AS VARCHAR(5000);
DECLARE #PmWos AS VARCHAR(5000);
DECLARE #RepWos AS VARCHAR(5000);
SET #AllWos = (SELECT AllWos FROM INSERTED);
SET #RepWos = (SELECT AllWos FROM INSERTED);
SET #PmWos = (SELECT AllWos FROM INSERTED);
EXEC Z_UpdateStageTable #AllWos;
EXEC Z_UpdateStageTable #RepWos;
EXEC Z_UpdateStageTable #PmWos;
END

Is there a typo in the SET part of the AFTER trigger? You're selecting the same thing into three different variables.
Rather than confirming the behavior of Z_UpdateStageTable, I'd try to replace it with something dirt simple (a parameterless sql statement, say) to test whether the trigger's being called. It's possible that the sproc's not being called with what you think it's being called with.

You can add PRINT statements to the trigger and manually insert from ManagementStudio/Enterprise Manager to see where the trigger fails.
I see a problem when you insert multiple records in a single statement, as the SELECT FROM Inserted will return more than 1 record.
You can also update the SET statement to SELECT #Var = AllWos FROM Inserted

Hold on a second, if userid is your PK then Z_MobileSyncFilters will not have data yet, this is also an instead of trigger
this wholw block doesn't do anything really, why do you need this trigger?
DELETE FROM Z_MobileSyncFilters WHERE UserID = (SELECT UserID FROM INSERTED);
INSERT INTO Z_MobileSyncFilters
SELECT *
FROM INSERTED;
you second trigger is flawed because it will faile if you have a multi row operation
why do you have 2 insert trigger (1 instead 1 after) on this table?

Related

Determine in value change before updating in Sql Server

I am working on updating of table
Table : User(id,name,Dob,createdDate,lastUpdatedDate)
I want to update lastUpdatedDate when there is change in Name column.
firstly I used update trigger but that is execute after updating of records
some helping link suggest me to use instead of Update trigger but if I use that one it will not update my records after trigger.
any solution?
well I found suitable solution for this problem
in after update trigger there are two table sets one is Inserted and other one is Deleted.
so by getting name from both table sets we can campare there values. if there value is same we will not update lastUpdatedDate and if there is any difference in values then we will update lastUdpatedDate
Create TRIGGER [dbo].[User__Update]
ON [dbo].[User]
AFTER Update
AS
BEGIN
SET NOCOUNT ON;
declare #AttributeValue varchar(max)
declare #OldAttributeValue varchar(max)
SELECT #AttributeValue = INSERTED.Name
FROM INSERTED
select #OldAttributeValue=Deleted.Name
FROM Deleted
if(#OldAttributeValue<>#AttributeValue)
BEGIN
IF UPDATE(Name)
BEGIN
update [User] set LastUpdatedDate=GetDate() where name =#AttributeValue
END
END
END

Trigger preventing a column from being updated

I have created a trigger as below:
CREATE TRIGGER InsertUpdateATLastViewedMatch
ON dbo.AT_LastViewedMatch
FOR INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- update statements for trigger here
declare #id1 int, #matchFK int;
select #id1 = i.id from inserted i;
select #matchFK=i.AT_MatchFk from inserted i;
update dbo.AT_LastViewedMatch set matchId = #matchFK where id = #id1;
END
GO
While this trigger works- I am not able to update the value of the matchId column directly from SQLManager:
If I execute
UPDATE AT_LastViewedMatch set matchId='1179619' where id=5762
for example, I am still seeing the old value for matchId. I think the issue is related to the above trigger (since if I drop the trigger, it works). Is there a way to get past this?
From your trigger definition below, you have created it for insert and update
CREATE TRIGGER InsertUpdateATLastViewedMatch
ON dbo.AT_LastViewedMatch
FOR INSERT,UPDATE <-- Here
so essentially, whenever you are running an update statement from SSMS
UPDATE AT_LastViewedMatch set matchId='1179619' where id=5762
Your trigger performing the below line and setting it to old value
update dbo.AT_LastViewedMatch set matchId = #matchFK where id = #id1;
You need to remove that update from your trigger definition
CREATE TRIGGER InsertUpdateATLastViewedMatch
ON dbo.AT_LastViewedMatch
FOR INSERT

Deleted Virtual table in SQL Server is empty ON Delete trigger

I am trying to invoke an ON Delete trigger event, but when I try to select row from the Deleted table, it is empty.
Is there any other way to get Id of row on which delete event has fired?
Code:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER TRIGGER [audit]
ON [dbo].[S_PARTY]
FOR DELETE
AS
-- Insert statements for trigger here
DECLARE #id nvarchar(50)
SET #id = (Select ROW_ID from deleted )
BEGIN
-- Insert statements for trigger here
INSERT INTO [dbo].[S_AMF_AUDIT_ITEM] (ROW_ID)
VALUES (#id);
END
When trigger fires on this, I am getting error as S_AMF_AUDIT_ITEM doesn't allow null values. So can you please help me this to get Id of table on which delete command executes?
Your trigger is broken.
It doesn't take into account that the DELETE statement might affect zero or more than one rows.
The issue with NULL could occur for the statement DELETE FROM [dbo].[S_PARTY] WHERE 1 = 0.
A fixed version would be
ALTER TRIGGER [audit]
ON [dbo].[S_PARTY]
FOR DELETE
AS
BEGIN
INSERT INTO [dbo].[S_AMF_AUDIT_ITEM]
(ROW_ID)
SELECT ROW_ID
FROM deleted;
END
A trigger can fire for 0..N deleted rows. For example:
delete YourTable
where 1=2
Would run a for delete trigger on YourTable. So a trigger has to be able to deal with zero or multiple rows. Consider rewriting your trigger like:
ALTER TRIGGER [audit] ON [dbo].[S_PARTY] FOR DELETE
AS
INSERT dbo.S_AMF_AUDIT_ITEM
(ROW_ID)
SELECT ROW_ID
FROM deleted
That will work for any number of inserted rows.

Can a storeProcecdure insert fire Trigger?

SQL Server 2008
I have trigger defined on
TABLE_A for 'INSTEAD OF INSERT' and TABLE_B for 'INSTEAD OF INSERT'.
Both the triggers perform merge with the inserted table.
TABLE_A insert is done by user/code and is working well, trigger for insert is fired.
I have Stored procedure SP_1 inside TABLE_A TRIGGER.
SP_1 Inserts data from TABLE_A into TABLE_B based on some conditions.
But the problem is when the stored procedure (SP_1) is inserting data, the trigger on TABLE_B is not fired and the data is just inserted as it is.
So can stored procedure inserts fire triggers?
Pseudo-code
ALTER TRIGGER [dbo].[trgtable_AInsert] ON [dbo].[TABLE_A]
Instead of INSERT
AS
BEGIN
SET NOCOUNT ON;
IF exists(SELECT * FROM INSERTED)
BEGIN
MERGE
.......
...........
..............
end
EXEC SP_1 #employee_id
end
ALTER TRIGGER [dbo].[trgtableB_Insert] ON [dbo].[TABLE_B]
Instead of INSERT
AS
BEGIN
SET NOCOUNT ON;
IF exists(SELECT * FROM INSERTED)
BEGIN
MERGE
.......
...........
..............
end
end
ALTER PROCEDURE [dbo].[SP_1] #employeeid int
AS
BEGIN
BEGIN TRANSACTION
insert into TABLE_B
.......
...........
..............
from TABLE_A
where employee_ID is #employeeid
COMMIT TRANSACTION
END
Yes triggers can fired by stored procedure inserts!
But I think the problem is that you should try to use AFTER instead of INSTEAD OF triggers in this case. Becasue I can't see all of your code, but it is possible, that the insert is not done because you overrided it in the Instead Of triggers. With AFTER triggers you should have no problems with firing the second trigger.
This is too big for a comment, and needs formatting, so posting as an "answer".
Yes, triggers will fire in this case. Taking your example and slightly modifying it (note the warnings though):
create table Table_A (ID int not null)
go
create table Table_B (ID int not null)
GO
CREATE PROCEDURE [dbo].[SP_1] #employeeid int
AS
BEGIN
BEGIN TRANSACTION
insert into TABLE_B (ID)
SELECT ID from TABLE_A
where ID = #employeeid
COMMIT TRANSACTION
END
GO
Creating the triggers:
CREATE TRIGGER [dbo].[trgtable_AInsert] ON [dbo].[TABLE_A]
Instead of INSERT
AS
BEGIN
SET NOCOUNT ON;
IF exists(SELECT * FROM INSERTED)
BEGIN
MERGE
into Table_A a
using inserted i on a.id = i.id
when not matched then insert (ID) values (i.id);
end
--Wrong code, just for example
declare #employee_id int
select #employee_id = ID from inserted --BAD CODE, Ignores multiple rows
EXEC SP_1 #employee_id
end
GO
CREATE TRIGGER [dbo].[trgtableB_Insert] ON [dbo].[TABLE_B]
Instead of INSERT
AS
BEGIN
SET NOCOUNT ON;
IF exists(SELECT * FROM INSERTED)
BEGIN
MERGE
into Table_B b
using inserted i on b.id = i.id
when not matched then insert (ID) values (i.id+5);
end
end
GO
And executing a trial insert into Table_A:
insert into Table_A (ID) values (1),(2)
select * from Table_B
On my machine, at the present time, I get a final result of a single row with the value "7". Others may run this sample and get the result "6", because triggers only run once per statement, rather than once per row. But as you can see, both triggers have fired.
As i previously mentioned in the comments #András Ottó
Merge
using(... = "column with possible null values" AND
... = ... AND
... = ...
)
of merge was not working correctly and the records were always inserted.
1 = 1 and E=E and NULL=NULL is not true. (of-course sql 101)
I have overlooked this column and did not place where clause properly to get rid of null values so ended up inserting all the time. Fixing that everything ended up working.
Thanks for the help Every1. Cheers
Apologies.
I'm not going to mark it answered because it is purely my mistake which was not fully mentioned in the question.

how to create before update trigger in sql server 2005

Is there anyway where I can create a trigger which will execute before the update/delete takes place( and then the actual update/delete takes place)? and how can I drop a trigger from a table?
to drop a trigger use:
--SQL Server 2005+, drop the trigger, no error message if it does not exist yet
BEGIN TRY DROP TRIGGER dbo.TrigerYourTable END TRY BEGIN CATCH END CATCH
GO
--drop trigger pre-SQl Server 2005, no error message if it does not exist yet
if exists (select * from sysobjects where id = object_id(N'[dbo].[TrigerYourTable ]') and OBJECTPROPERTY(id, N'IsTrigger') = 1)
drop trigger [dbo].[TrigerYourTable ]
GO
OP said in a comment:
...suppose I have to check childcount of
a perticular user if that is more than
5 do not update the user.how can I do
that using instead of trigger?
You don't really need to prevent the original update, you can let it happen, and then in the trigger check for the problem and rollback if necessary. This is how to enforce the logic for one or many affected rows, when you need to JOIN to determine the childcount of the affected rows:
--create the trigger
CREATE TRIGGER dbo.TrigerYourTable ON dbo.YourTable
AFTER UPDATE
AS
SET NOCOUNT ON
IF EXISTS (SELECT
1
FROM INSERTED i
INNER JOIN YourChildrenTable c ON i.ParentID=c.ParentID
GROUP BY i.ParentID
HAVING COUNT(i.ParentID)>5
)
BEGIN
RAISERROR('Count of children can not exceed 5',16,1)
ROLLBACK
RETURN
END
GO
It will throw the error if there is a violation of the logic, and the original command will be subject to a rollback.
If childcount is a column within the affected table, then use a trigger like this to enforce the logic:
--create the trigger
CREATE TRIGGER dbo.TrigerYourTable ON dbo.YourTable
AFTER UPDATE
AS
SET NOCOUNT ON
IF EXISTS (SELECT 1 FROM INSERTED WHERE childcount>5)
BEGIN
RAISERROR('Count of children can not exceed 5',16,1)
ROLLBACK
RETURN
END
GO
If you just want to ignore the update for any rows that violate the rule try this:
--create the trigger
CREATE TRIGGER dbo.TrigerYourTable ON dbo.YourTable
INSTEAD OF UPDATE
AS
SET NOCOUNT ON
UPDATE y
SET col1=i.col1
,col2=i.col2
,col3=i.col3
,.... --list all columns except the PK column!
FROM dbo.YourTable y
INNER JOIN INSERTED i on y.PK=i.PK
WHERE i.childcount<=5
GO
It will only update rows that have a child count less than 5, ignoring all affected rows that fail the requirement (no error message).
This article from microsoft explains the syntax of creating triggers.
http://msdn.microsoft.com/en-us/library/ms189799.aspx
There isn't really a 'before' trigger, but you can use an INSTEAD OF trigger that allows you to jump in place of whatever action is attempted, then define your own action.
I've used that technique for versioning data.
CREATE TRIGGER [dbo].[Documents_CreateVersion]
ON [dbo].[Documents]
INSTEAD OF UPDATE
AS
BEGIN
DECLARE #DocumentID int
SELECT DocumentID = DocumentID FROM INSERTED
-- do something
END
INSERTED is a bit of a misnomer here, but it contains the details of the action before it occurs you can then define your own action with that data.
Edit:
As per comments below my response, my example can be dangerous if multiple rows are updated at once. My application doesn't allow for this so it's fine in this case. I would agree that the above is a bad practice regardless.
to drop trigger- use database_name
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'tgr_name' AND type = 'TR')
DROP TRIGGER tgr_name
GO
Here's a simple trigger that checks columns values, and fires before updating or inserting, and raises an error.
IF OBJECT_ID ('dbo.MyTableTrigger', 'TR') IS NOT NULL
DROP TRIGGER dbo.MyTableTrigger;
GO
CREATE TRIGGER MyTableTrigger
ON dbo.MyTable
FOR INSERT, UPDATE
AS
DECLARE #Col1ID INT
DECLARE #Col2ID INT
SELECT #Col1ID = Col1ID, #Col2ID = Col2ID FROM inserted
IF ((#Col1ID IS NOT NULL) AND (#Col2ID IS NOT NULL))
BEGIN
RAISERROR ('Col1ID and Col2ID cannot both be in MyTable at the same time.', 16, 10);
END