Update trigger behavior in SQL 2005 - sql

I used an Update statement inside a procedure to update a table which has an update trigger. Does the update statement complete after the trigger completes or what?

the trigger runs as part of the UPDATE statement (after the data in the table has been updated); the proc resumes after this. There are also "instead of" triggers that replace the UPDATE statement.
See here for more.

There are two types of triggers in SQL Servers. INSTEAD OF triggers, and AFTER triggers. By default, a trigger is an AFTER trigger, meaning this is what happens. Consider TableA, with an UPDATE AFTER TRIGGER which updates TableB.
Issue statement: UPDATE TableA set XXX = 5;
TableA gets updated
The trigger fires, and TableB gets updated.

triggers are attached to the statement(s) that trigger them and are implicitly the part of transaction that fired them.
For ex :
if triggers are fired because of update , then it helps to understand that database would implicitly insert a begin tran and end tran surrounding that update.

Related

Simple IF EXISTS in TRIGGER fails

I've created a simple TRIGGER:
ALTER TRIGGER [dbo].[SprawdzZajetosc] ON [dbo].[Wypozyczenia]
FOR insert, update
AS
BEGIN
IF EXISTS (SELECT * FROM Wypozyczenia)
BEGIN
RAISERROR('Wybrany pojazd został już wypożyczony w wybranym przedziale czasu.', 16, 1)
ROLLBACK TRANSACTION
END
END
I can't understand why 'if' is returning me TRUE even if table 'Wypozyczenia' is empty? It doesn't matter what 'Wypozyczenia' contains - it always returns me TRUE.
I tried with count(*) it always returns me a value > 0.
Why is that?
I am not 100% sure of this, but it sounds logical to me - The trigger is an insert/update trigger. As soon as something is being inserted, the trigger is triggered and the condition is TRUE. Since there is a ROLLBACK TRANSACTION fired, the inserted row is then rolled back and hence you get an empty table. What are you actually trying to achieve here ?
Apart from the reasons why you're doing this, the cause for IF EXISTS() to be always TRUE in your case is very simple it's because you're using an AFTER or FOR trigger.
CREATE TRIGGER
AFTER specifies that the DML trigger is fired only when all operations
specified in the triggering SQL statement have executed successfully.
All referential cascade actions and constraint checks also must
succeed before this trigger fires.
Meaning the row(s) you're trying to insert are already in the table. It's just a transaction has not been committed yet.
Here is SQLFiddle demo
Your IF EXISTS() check might've worked only in INSTEAD OF INSERT trigger but then you should've take into consideration that triggers in SQL Server are statement based. Meaning it fires once per statement and you can insert more than one row in one statement.
Here is SQLFiddle demo
As far as FOR UPDATE clause goes in your trigger definition it doesn't make any sense at all. If you're updating something it should be in the table. Thus table is not empty.

Pre-insert/update trigger in SQL Server

All we need is to create several pre-insert/update triggers in SQL Server 2008 R2 which do some select * or select count(*) and explicitly fail if it is empty or non-empty.
Please, how to achieve that?
Create an INSTEAD OF INSERT, UPDATE trigger. Now to prevent DML you have 2 options. In the body of trigger execute RAISERROR so your application can catch the error. Another way is not to perform actual insert/update in the trigger, so no records will be inserted/updated, but the user will not know if DML succeeds.

Regarding trigger sequence

Have two triggers on a table. One trigger is executed when there is a insert or update for each row in the table. Second trigger is executed when there is a update for each row in the table. Which trigger gets executed first in ORACLE 10G when there is a update statement on a row in the table. Is there any order of execution for triggers in oracle? If so how can i set it?
The order in which the triggers will fire is arbitrary and not something that you can control in 10g. I believe, technically, it goes in the order that the triggers happened to be created but that's certainly not something that you'd want to count on.
In 11g, you can control the firing order of triggers. However you are almost always better off replacing the two triggers with one trigger that calls two stored procedures. So rather than
CREATE TRIGGER trg_1
BEFORE UPDATE ON t
FOR EACH ROW
BEGIN
<<do thing 1>>
END;
CREATE TRIGGER trg_2
BEFORE UPDATE ON t
FOR EACH ROW
BEGIN
<<do thing 2>>
END;
you would be much better served with something like
CREATE PROCEDURE p1( <<arguments>> )
AS
BEGIN
<<do thing 1>>
END;
CREATE PROCEDURE p2( <<arguments>> )
AS
BEGIN
<<do thing 2>>
END;
CREATE TRIGGER trg
BEFORE UPDATE ON t
FOR EACH ROW
BEGIN
p1( <<list of arguments>> );
p2( <<list of arguments>> );
END;
For versions before 11g, no, the order is unspecified. From 10g Release 2 docs:
For enabled triggers, Oracle automatically performs the following actions:
Oracle runs triggers of each type in a planned firing sequence when more than one trigger is fired by a single SQL statement. First, statement level triggers are fired, and then row level triggers are fired.
Oracle performs integrity constraint checking at a set point in time with respect to the different types of triggers and guarantees that triggers cannot compromise integrity constraints.
Oracle provides read-consistent views for queries and constraints.
Oracle manages the dependencies among triggers and schema objects referenced in the code of the trigger action
Oracle uses two-phase commit if a trigger updates remote tables in a distributed database.
Oracle fires multiple triggers in an unspecified, random order, if more than one trigger of the same type exists for a given statement; that is, triggers of the same type for the same statement are not guaranteed to fire in any specific order.
No order to trigger firing can be relied upon in 10g beyond the normal before statement, before row, after row, after statement order. In 11g a new FOLLOWS clause was added to the CREATE TRIGGER statement.
In Oracle 10g we do not control the triggers that are created on same timing. It is executed randomly. So we cannot say which trigger is fired first. To overcome this problem, Oracle 11g introduced FOLLOWS CLAUSE. Using this we can control the execution order.

prevent updates, deletes and truncates on database table

I am in the process of creating a sql server 2008 database table for auditing users actions.
Is it possible to create a database table which can only inserted in to - no truncates, deletes or updates allowed on the data in the table. One option I know of is to use a different user with limited rights, but this isnt option for me. So looking at other options?
You need to create a TRIGGER that fires on UPDATE and DELETE and throws an error:
CREATE TRIGGER user_action_update on UserActions FOR UPDATE, DELETE AS
BEGIN
RAISERROR ('Cannot modify or delete user actions', 16, 1)
ROLLBACK TRAN
RETURN
END
GO
Source: http://msdn.microsoft.com/en-us/magazine/cc164047.aspx
Another way to do that is to Write a trigger creation script for the table and set the action to " INSTEAD OF " which will override the triggering action (unwanted action in your case ) for some other code, or null code.
INSTEAD OF Property
Specifies that the DML trigger is executed instead of the triggering SQL statement, therefore, overriding the actions of the triggering statements.
Here is a link in how to Write the SQL statement for the trigger creation:
http://technet.microsoft.com/en-us/library/ms189799.aspx
Good luck
Adrian

Are Sql Triggers synchronous or asynchronous?

I have a table that has an insert trigger on it. If I insert in 6000 records into this table in one insert statement from a stored procedure, will the stored procedure return before the insert trigger completes?
Just to make sure that I'm thinking correctly, the trigger should only be called (i know 'called' isn't the right word) once because there was only 1 insert statement, right?
My main question is: will the sproc finish even if the trigger hasn't completed?
Your insert trigger will run once for the entire insert statement. This is why it is important to use the inserted temporary table to see what has actually been inserted, and not just select the most recent single record, or something like that.
I just tested an insert and update trigger and indeed, they are considered part of the insert by sql server. the process will not finish until the trigger finishes.
Triggers are part of the transaction that called them.
One important thing about triggers that you must be aware of is that the trigger fires once for each transaction (at least in SQL server, you should check other dbs, but even if it will process row by row, that is usually a poor idea), so if you insert 6000 records the trigger fires once not 6000 times. Many people are not aware of this and write triggers as if they will process multiple record inserts one record at a time. This is not true and your trigger must account for handing the multiple record insert.
The trigger call is not asynchronous. Each call to your insert procedure will result in the trigger being fired, and the procedure will not return until the trigger finishes.
Take a look at the query plan to see how it works. You'll see that the statements in the trigger will be called for each call to the procedure.
The thing is, every time the TRIGGER criteria is met, the TRIGGER fires. It fires once in batch processing or Transaction. See my lesson 101 on TRIGGER
You should use cursor in insert statement to process trigger row.
Because Triggers in SQL Server fire once per statement, not once per row.