Should I use the template from MS SQL Management Studio to create new triggers? - sql

If you create a new trigger in MS SQL Management Studio by using the GUI, it gives you this template:
--====================================
-- Create database trigger template
--====================================
USE <database_name, sysname, AdventureWorks>
GO
IF EXISTS(
SELECT *
FROM sys.triggers
WHERE name = N'<trigger_name, sysname, table_alter_drop_safety>'
AND parent_class_desc = N'DATABASE'
)
DROP TRIGGER <trigger_name, sysname, table_alter_drop_safety> ON DATABASE
GO
CREATE TRIGGER <trigger_name, sysname, table_alter_drop_safety> ON DATABASE
FOR <data_definition_statements, , DROP_TABLE, ALTER_TABLE>
AS
IF IS_MEMBER ('db_owner') = 0
BEGIN
PRINT 'You must ask your DBA to drop or alter tables!'
ROLLBACK TRANSACTION
END
GO
Should I use this template?
I dont know anything about triggers, but I think I need to use them. The purpose in this case is that on an insert to the table, I need to update one of the fields.
Please help me get started!

OK to begin with that is the wrong template if you want an ordinary trigger that one is a trigger on making structural changes to the table itself.
If you decide to do a trigger that affects data (as opposed to structure), there are several things you need to know. First and by far the most critical, triggers operate on sets of data not one row at time. You must write any trigger to handle multiple row inserts.updates or deletes. If you end up with any code setting the value in inserted or deleted to a variable, there is a 99% chance it will not work properly if multiple records are involved.
What is inserted or deleted you ask? That is the next thing you need to know about triggers, there are two pseudotables (inserted and deleted) that are only available in a trigger (or an output clause) which contain the new information being inserted or the updated values (in the inserted table) and the old information being deleted or being changed by an update (in the deleted table). So an insert has values in inserted, a delete has values in deleted and an update has values in both. Use these in your trigger to pull the values you need to change.

Since you don't know anything about triggers, I would say no, don't use the template.
Read the books online page for Create Trigger and write the trigger by hand.
There is probably more in that template code than you actually need. Read the manual and keep it simple.

If you don't know anything about triggers then I would strongly suggest that you read up on them before implementing them. Get Triggers right and they can make your life a lot easier; get it wrong and Triggers will cause you a lot of trouble.
I would suggest starting off with this tutorial
http://www.sqlteam.com/article/an-introduction-to-triggers-part-i
You can use the above SQL as a template or you can simply write your own. I would suggest you write your own as you'll understand what you are doing. Obviously only do this after you have done some serious reading on triggers. Check out MSDN too

Related

Is it possible to create a trigger that creates another trigger

Is it possible to have a trigger that creates another trigger?
For example, I have table_1 with a column table_name. On inserting into table_1 the first trigger would create a trigger for the table inserted as table_name? I have not found much info on this.
Trigger enables you to run dynamic SQL, in which you can create what objects you like, including other triggers (assuming you have the right permissions).
You can do that by using sp_executesql, it executes a Transact-SQL statement or batch that can be reused many times, or one that has been built dynamically. The Transact-SQL statement or batch can contain embedded parameters
This seems tough as a (very) bad design. So go ahead and try that (or not*).
*You can state your problem to begin with, may be in programmers (if it's more a design oriented question) or in Database Administrators, and you may get better help.

Can you disable a trigger within a trigger? SQL Server 2008

Can you disable and re-enable triggers within a trigger?
For example, I have a piece of information in a front-end application that can be put in one of two places. If someone puts it in place A, I want to copy it to place B and vice versa.
So, my idea is to put two triggers on the different tables 1) When it's put in A it puts it in B. 2) When it's put in B it puts it in A
This would create a neverending loop (I assume?) so can you disable Trigger 1 while Trigger 2 runs and enable it at the end?
Although I agree with Damien's comment that duplicating data in two tables in the same database is generally undesirable, if you really have a good reason for doing this then you could use INSTEAD OF triggers instead of AFTER triggers (which I assume you're looking at now). That way you can 'replace' a single INSERT with two separate INSERTs that you code and control yourself.
Yes you can:
ALTER TABLE tablename DISABLE TRIGGER triggername
ALTER TABLE tablename ENABLE TRIGGER triggername
Although, for your solution, I'd create a trigger that runs the same on each side, and is clever enough not to mess itself up.
i.e. Make the trigger intelligently distinguish between a user/client INSERT and a trigger 'MOVE'.
Or you could check whether the information had changed in the trigger before doing the update, which would end the loop?

SQL Server 2005 Insert Trigger with Update Statement

I am currently not in a location to test any of this out but would like to know if this is an option so I can start designing the solution in my head.
I would like to create an insert trigger on a table. In this insert trigger, I would like to get values from the inserted virtual table and use them to UPDATE the same table. Would this work or would we enter some kind of infinite loop (even though the trigger is not for update commands).
As an example if a row was inserted (which represents a new rate/cost for a vendor) I would like to update the same table to expire the old rate/cost for that vendor. The expiration is necessary vs updating the record that already exists so a history of rates/costs can be kept for reporting purposes (not to mention that the current reporting infrastructure expects this type of thing to happen and we are migrating current reports/data to SQL Server).
Thanks!
If you have only an INSERT trigger and no UPDATE trigger then there isn't any problem, but I assume you want to catch also UPDATEs and perhaps even DELETEs.
The INSTEAD OF triggers are guaranteed not to behave recursively:
If an INSTEAD OF trigger defined on a
table executes a statement against the
table that would ordinarily fire the
INSTEAD OF trigger again, the trigger
is not called recursively
With and INSTEAD OF trigger you must do both the original INSERT and the UPDATE you desire.
This doesn't sound like it would cause any problems to me, providing you're not doing an INSERT in another UPDATE trigger.

Watch a Database column to determine what is modifying

How do I find out what application or SP is modifing the values in a config table? I thought I had isolated the app that was responsible but these particular values keep chnging back to true when I keep modifying them to be false.
First, create a logging table:
CREATE TABLE modlog(
datestamp smalldatetime,
username varchar(255) NOT NULL DEFAULT SYSTEM_USER
);
Then create an UPDATE trigger on your table:
CREATE TRIGGER mytable_mods ON mytable FOR UPDATE AS
INSERT INTO modlog(smalldatetime) VALUES (GETDATE());
Just peek into the modlog table to figure out which user is updating the table, and when. You could get fancy and also log particular fields being updated.
Another approach would be to set up a trace in SQL Server Profiler, filter the heck out of it so it only returns updates on that table, and keep it open until something happens.
If your applications include the ApplicationName parameter in their connection strings, you can use App_Name() instead of SYSTEM_USER, which will log the application name, removing the extra detective work. Knowing the user might still be useful so you can figure out what they are doing to trigger the update.
Create a trigger to roll back the update. Wait for the app to error out. It can be a very simple trigger:
CREATE TRIGGER BugOffRogueProgram
ON MyConfigTable
FOR UPDATE
AS
BEGIN
ROLLBACK TRAN
END
The answers provided so far are absolutely on the spot - that's the way to do it in SQL Server 2005.
Just as a brief teaser: in SQL Server 2008, there's a new feature called Change Data Capture to support this exact scenario "out of the box" without the need to write triggers and update tables yourself. Quite handy!
Marc

MSSQL: Disable triggers for one INSERT

This question is very similar to SQL Server 2005: T-SQL to temporarily disable a trigger
However I do not want to disable all triggers and not even for a batch of commands, but just for one single INSERT.
I have to deal with a shop system where the original author put some application logic into a trigger (bad idea!). That application logic works fine as long as you don't try to insert data in another way than the original "administration frontend". My job is to write an "import from staging system" tool, so I have all data ready. When I try to insert it, the trigger overwrites the existing Product Code (not the IDENTITY numeric ID!) with a generated one. To generate the Code it uses the autogenerated ID of an insert to another table, so that I can't even work with the ##IDENTITY to find my just inserted column and UPDATE the inserted row with the actual Product Code.
Any way that I can go to avoid extremly awkward code (INSERT some random characters into the product name and then try to find the row with the random characters to update it).
So: Is there a way to disable triggers (even just one) for just one INSERT?
You may find this helpful:
Disabling a Trigger for a Specific SQL Statement or Session
But there is another problem that you may face as well.
If I understand the situation you are in correctly, your system by default inserts product code automatically(by generating the value).
Now you need to insert a product that was created by some staging system, and for that product its product code was created by the staging system and you want to insert it to the live system manually.
If you really have to do it you need to make sure that the codes generated by you live application in the future are not going to conflict with the code that you inserted manually - I assume they musty be unique.
Other approach is to allow the system to generate the new code and overwrite any corresponding data if needed.
You can disable triggers on a table using:
ALTER TABLE MyTable DISABLE TRIGGER ALL
But that would do it for all sessions, not just your current connection.. which is obviously a very bad thing to do :-)
The best way would be to alter the trigger itself so it makes the decision if it needs to run, whether that be with an "insert type" flag on the table or some other means if you are already storing a type of some sort.
Rather than disabling triggers can you not change the behaviour of the trigger. Add a new nullable column to the table in question called "insertedFromImport".
In the trigger change the code so that the offending bit of the trigger only runs on rows where "insertedFromImport" is null. When you insert your records set "insertedFromImport" to something non-null.
Disable the trigger, insert, commit.
SET IDENTITY_INSERT Test ON
GO
BEGIN TRAN
DISABLE TRIGGER trg_Test ON Test
INSERT INTO Test (MyId, MyField)
VALUES (999, 'foo')
ENABLE TRIGGER trg_Test ON Test
COMMIT TRAN
SET IDENTITY_INSERT Test OFF
GO
Can you check for SUSER_SNAME() and only run when in context of the administration frontend?
I see many things that could create a problem. First change the trigger to consider multiple record imports. That may probably fix your problem. DO not turn off the trigger as it is turned off for everyone not just you. If you must then put the database into single user user mode before you do it and do your task during off hours.
Next, do not under any circumstances ever use ##identity to get the value just inserted! USe scope_identity instead. ##identity will return the wrong value if there are triggers onthe table that also do inserts to other tables with identity fields. If you are using ##identity right now through your system (since we know your system has triggers), your abosolute first priority must be to immediately find and change all instances of ##identity in your code. You can have serious data integrity issues if you do not. This is a "stop all work until this is fixed" kind of problem.
As far as getting the information you just inserted back, consider creating a batchid as part of you insert and then adding a column called batchid (which is nullable so it won't affect other inserts)to the table. Then you can call back what you inserted by batchid.
If you insert using BULK INSERT, you can disable triggers just for the insert.
I'm pretty sure bulk insert will require a data file on the file system to import so you can't just use T-SQL.
To use BULK INSERT you need INSERT and ADMINISTRATOR BULK OPERATION permissions.
If you disable triggers or constraints, you'll also need ALTER TABLE permission.
If you are using windows authentication, your windows user will need read access from the file. if using Mixed Mode authentication, the SQl Server Service account needs read access from the file.
When importing using BULK IMPORT, triggers are disabled by default.
More information: http://msdn.microsoft.com/en-us/library/ms188365.aspx