SQL Server: pause a trigger - sql-server

I am working with SQL Server 2005 and I have trigger on a table that will copy an deletions into another table. I cannot remove this trigger completely. My problem is that we have now developed an archiving strategy for this table. I need a way of "pausing" a trigger when the stored proc that does the archiving runs.

A little more detail would be useful on how the procedure is accessing the data, but assuming you are just getting the data, then deleting it from the table and wish to disable the trigger for this process, you can do the following
DISABLE TRIGGER trg ON tbl;
then
ENABLE TRIGGER trg ON tbl;
for the duration of the procedure.
This only works for SQL 2005+

An alternative method is to use Context_Info to disable it for a single session, while allowing other sessions to continue to fire the trigger.
Context_Info is a variable which belongs to the session. Its value can be changed using SET Context_Info.
The trigger will mostly look like this:
USE AdventureWorks;
GO
-- creating the table in AdventureWorks database
IF OBJECT_ID('dbo.Table1') IS NOT NULL
DROP TABLE dbo.Table1
GO
CREATE TABLE dbo.Table1(ID INT)
GO
-- Creating a trigger
CREATE TRIGGER TR_Test ON dbo.Table1 FOR INSERT,UPDATE,DELETE
AS
DECLARE #Cinfo VARBINARY(128)
SELECT #Cinfo = Context_Info()
IF #Cinfo = 0x55555
RETURN
PRINT 'Trigger Executed'
-- Actual code goes here
-- For simplicity, I did not include any code
GO
If you want to prevent the trigger from being executed you can do the following:
SET Context_Info 0x55555
INSERT dbo.Table1 VALUES(100)
Before issuing the INSERT statement, the context info is set to a value. In the trigger, we are first checking if the value of context info is the same as the value declared. If yes, the trigger will simply return without executing its code, otherwise the trigger will fire.
source: http://www.mssqltips.com/tip.asp?tip=1591

if DISABLE TRIGGER/ENABLE TRIGGER is not an option for some reason, you can create a table with a single row which will serve as a flag for the trigger.

Related

SQL Server events on insert

I have two tables in SQL Server. I want to raise an event when client inserts any row in order to copy that row to another table with more columns.
I have to do that in SQL Server just after insert. Is this possible? And if it is... how?
I need something like this:
CREATE EVENT myevent
ON (INSERT ROW?)
DO
TODO...
But I don't know if there are any event on insert and I donĀ“t know where does the code go.
Thanks.
EDIT:
I have another problem added. The tables are in different databases. I'm trying to implement this trigger:
USE [DB1]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [TRIGGER_NAME]
ON [dbo].[TABLE_TRIGGERED]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO DB2.[dbo].[FINAL_TABLE]
SELECT *
FROM INSERTED
WHERE COL1= 'Stuff' AND COL2= 'Stuff' AND COL3=
(
SELECT MAX(COL3)+1
FROM DB2[dbo].[FINAL_TABLE]
)
END
And it can't access to COL1, COL2 and COL3. Is my sintax right?
Using an SQL After Insert trigger, you can handle it
If this is your first time with triggers, take care of set based coding.
If you miss it, on INSERT statements with multiple rows you might get unexpected results. So keep away using variables in the trigger code, think always set based using the Inserted and Deleted tables special to triggers
You can check the referred tutorial

Trigger doesn't fire when row is inserted

I built a trigger in SQL Server to execute a stored procedure when a new row is inserted into the table Balance Data, but the trigger doesn't get fired. I don't know what I am doing wrong or what is happening.
This is the script:
CREATE TRIGGER [dbo].[SP_Trigger]
ON [dbo].[BalanceData]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
Exec Schenck.dbo.spCopyData
END
I assume that you are using Transact-SQL.
According to the documentation, FOR INSERT triggers are synonymous with AFTER INSERT triggers by default. This should fire after you have inserted your data into [dbo].[BalanceData].
I would firstly confirm that the data has been inserted successfully (i.e. no check constraint violations, etc) and then confirm what Schenck.dbo.spCopyData is doing. You have turned ROWCOUNT off in the trigger, so perhaps this has given you the illusion that nothing happened.

How to modify the Trigger variable without altering the complete trigger in SQL server?

I have a trigger in sql server that contains more then thousand lines of code like
CREATE TRIGGER [dbo].[xyz] ON [dbo].[abc]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
--Here more then 100 field is there.
DECLARE #ErrMsg NVARCHAR(2000)
--
--
DECLARE #IsPublished BIT
DECLARE #ParentVersionedTemplateID UNIQUEIDENTIFIER
--
--
Now I need to change the datatype of one of the field of this trigger. One possible way is copy and paste the whole code and use ALTER command and change the existing datatype whatever I want.
But I want to ask is there any other way where without drop and recreate the trigger or alter the complete trigger code can I modify the parameters of that trigger?
There is no way in SQL Server to alter part of a Trigger. You need to rewriting the whole trigger (via ALTER TRIGGER). My best suggestion would to to use SSMS, right click on the Trigger in question and select Script Trigger as Alter. This would be the least amount of effort.

SQL Server Trigger - Need to Alter

I need to alter a trigger in SQL Server. After I am doing, do I just execute the trigger similar to how I would do for a Stored Procedure?
ALTER TRIGGER
Yes, that is right, just use ALTER. If you right-click on your trigger in Object Explorer in SSMS and select Script Trigger as/ALTER To, you will see the ALTER statement created for your trigger.
ALTER TRIGGER triggerName
ON tableName
FOR INSERT -- or update & delete
AS
-- sql here
http://msdn.microsoft.com/en-us/library/ms176072.aspx
You don't "execute" a trigger. Triggers are "triggered" at certain points depending upon your definition of them.
For example an AFTER UPDATE trigger would run for all rows updated after you send an UPDATE command to the table on which the trigger is created.

SQL Server - after insert trigger - update another column in the same table

I've got this database trigger:
CREATE TRIGGER setDescToUpper
ON part_numbers
AFTER INSERT,UPDATE
AS
DECLARE #PnumPkid int, #PDesc nvarchar(128)
SET #PnumPkid = (SELECT pnum_pkid FROM inserted)
SET #PDesc = (SELECT UPPER(part_description) FROM inserted)
UPDATE part_numbers set part_description_upper = #PDesc WHERE pnum_pkid=#PnumPkid
GO
Is this a bad idea? That is to update a column on the same table. I want it to fire for both insert and update.
It works, I'm just afraid of a cyclical situation. The update, inside the trigger, fires the trigger, and again and again. Will that happen?
Please, don't nitpick at the upper case thing. Crazy situation.
It depends on the recursion level for triggers currently set on the DB.
If you do this:
SP_CONFIGURE 'nested_triggers',0
GO
RECONFIGURE
GO
Or this:
ALTER DATABASE db_name
SET RECURSIVE_TRIGGERS OFF
That trigger above won't be called again, and you would be safe (unless you get into some kind of deadlock; that could be possible but maybe I'm wrong).
Still, I do not think this is a good idea. A better option would be using an INSTEAD OF trigger. That way you would avoid executing the first (manual) update over the DB. Only the one defined inside the trigger would be executed.
An INSTEAD OF INSERT trigger would be like this:
CREATE TRIGGER setDescToUpper ON part_numbers
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO part_numbers (
colA,
colB,
part_description
) SELECT
colA,
colB,
UPPER(part_description)
) FROM
INSERTED
END
GO
This would automagically "replace" the original INSERT statement by this one, with an explicit UPPER call applied to the part_description field.
An INSTEAD OF UPDATE trigger would be similar (and I don't advise you to create a single trigger, keep them separated).
Also, this addresses #Martin comment: it works for multirow inserts/updates (your example does not).
Another option would be to enclose the update statement in an IF statement and call TRIGGER_NESTLEVEL() to restrict the update being run a second time.
CREATE TRIGGER Table_A_Update ON Table_A AFTER UPDATE
AS
IF ((SELECT TRIGGER_NESTLEVEL()) < 2)
BEGIN
UPDATE a
SET Date_Column = GETDATE()
FROM Table_A a
JOIN inserted i ON a.ID = i.ID
END
When the trigger initially runs the TRIGGER_NESTLEVEL is set to 1 so the update statement will be executed. That update statement will in turn fire that same trigger except this time the TRIGGER_NESTLEVEL is set to 2 and the update statement will not be executed.
You could also check the TRIGGER_NESTLEVEL first and if its greater than 1 then call RETURN to exit out of the trigger.
IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;
Use a computed column instead. It is almost always a better idea to use a computed column than a trigger.
See Example below of a computed column using the UPPER function:
create table #temp (test varchar (10), test2 AS upper(test))
insert #temp (test)
values ('test')
select * from #temp
And not to sound like a broken record or anything, but this is critically important. Never write a trigger that will not work correctly on multiple record inserts/updates/deletes. This is an extremely poor practice as sooner or later one of these will happen and your trigger will cause data integrity problems asw it won't fail precisely it will only run the process on one of the records. This can go a long time until someone discovers the mess and by themn it is often impossible to correctly fix the data.
It might be safer to exit the trigger when there is nothing to do. Checking the nested level or altering the database by switching off RECURSIVE can be prone to issues.
Ms sql provides a simple way, in a trigger, to see if specific columns have been updated. Use the UPDATE() method to see if certain columns have been updated such as UPDATE(part_description_upper).
IF UPDATE(part_description_upper)
return
Yes, it will recursively call your trigger unless you turn the recursive triggers setting off:
ALTER DATABASE db_name SET RECURSIVE_TRIGGERS OFF
MSDN has a good explanation of the behavior at http://msdn.microsoft.com/en-us/library/aa258254(SQL.80).aspx under the Recursive Triggers heading.
Yea...having an additional step to update a table in which you can set the value in the inital insert is probably an extra, avoidable process.
Do you have access to the original insert statement where you can actually just insert the part_description into the part_description_upper column using UPPER(part_description) value?
After thinking, you probably don't have access as you would have probably done that so should also give some options as well...
1) Depends on the need for this part_description_upper column, if just for "viewing" then can just use the returned part_description value and "ToUpper()" it (depending on programming language).
2) If want to avoid "realtime" processing, can just create a sql job to go through your values once a day during low traffic periods and update that column to the UPPER part_description value for any that are currently not set.
3) go with your trigger (and watch for recursion as others have mentioned)...
HTH
Dave
create or replace
TRIGGER triggername BEFORE INSERT ON
table FOR EACH ROW
BEGIN
/*
Write any select condition if you want to get the data from other tables
*/
:NEW.COLUMNA:= UPPER(COLUMNA);
--:NEW.COUMNa:= NULL;
END;
The above trigger will update the column value before inserting.
For example if we give the value of COLUMNA as null it will update the column as null for each insert statement.

Resources