I wanted to know how it is possible that I can execute DELETE query inside a trigger "Instead of DELETE" without calling the same trigger? Is it a SQL feature? Can somebody explain why it works this way?
From the docs
If an INSTEAD OF trigger defined on a table runs a statement against the table that would ordinarily fire the INSTEAD OF trigger again, the trigger isn't called recursively. Instead, the statement processes as if the table had no INSTEAD OF trigger and starts the chain of constraint operations and AFTER trigger executions. For example, if a trigger is defined as an INSTEAD OF INSERT trigger for a table. And, the trigger runs an INSERT statement on the same table, the INSERT statement launched by the INSTEAD OF trigger doesn't call the trigger again. The INSERT launched by the trigger starts the process of running constraint actions and firing any AFTER INSERT triggers defined for the table.
It works that way because that is how Microsoft have decided. Although I can't imagine recursing would ever be useful for INSTEAD OF.
Related
In some cases when a record is inserted into a table, it should be split into few records, which would be inserted instead.
The logic is written inside an INSERT trigger, which fires before the INSERT operation. Inside of this trigger I am trying to execute an INSERT statement, which subsequently causes a recursive call of the trigger. However I do not want this to happen. I tried to disable a trigger from its body using smth like
execute immediate 'ALTER TRIGGER sale_trigger DISABLE';
But, obviously it is a commit operation and thus it doesnt work from inside of the trigger.
How can I get around this recursive call of the trigger?
Edit I declared my trigger as this declare PRAGMA AUTONOMOUS_TRANSACTION; and now i can run alter statement. However when I disable a trigger from the same trigger - the PLSQL developer stops working. What do I do? :)
Instead of loading the first insert directly into your target table, insert records into a staging table. The trigger with the troublesome logic should be on the staging table. If the logic does not apply, the trigger inserts the row into the target table. If the logic applies, the trigger inserts the row (if necessary?) and fires off whatever additional inserts to the target table are required. Truncate the staging table on regular intervals to keep it small and efficient (but probably not after each trigger operation since this would be less efficient).
In other words: decouple the trigger from the table it is inserting into.
I have an update trigger for a table. When I am updating the table rows I need to check certain condition in trigger then based on that I want to update another column.
Is it possible?
You might want to read the documentation for CREATE TRIGGER, especially the remarks section, which includes:
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. Instead, the statement is processed as if the table had no INSTEAD OF trigger and starts the chain of constraint operations and AFTER trigger executions.
If this, or other parts of the remarks section, don't answer your questions, you probably need to add more to your question about what problems you're having, or what issues you're concerned about.
What's the difference between FOR and AFTER triggers?
There is no difference, they do the same thing.
CREATE TRIGGER trgTable on dbo.Table FOR INSERT,UPDATE,DELETE
Is the same as
CREATE TRIGGER trgTable on dbo.Table AFTER INSERT,UPDATE,DELETE
An INSTEAD OF trigger is different, and fires before and instead of the insert and can be used on views, in order to insert the appropriate values into the underlying tables.
#Ben is absolutely right.
Here is MSDN article Exploring SQL Server Triggers
A paragraph from the article:
That syntax is also acceptable in older versions of SQL Server. However, now that there are two types of triggers in SQL Server 2000, I prefer to refer to FOR triggers as AFTER triggers. Thus, for the remainder of this article I will refer to either AFTER or INSTEAD OF triggers.
Like the AFTER trigger you saw earlier, this trigger prevents changes from being made to the lastname field. However, it implements this business rule differently than the previous example. Because the INSTEAD OF trigger fires in place of the UPDATE statement, the INSTEAD OF trigger then evaluates if the business rule test passes or not. If the business rule test passes, in order for the update to occur the INSTEAD OF trigger must explicitly invoke the UPDATE statement again.
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.
AFTER is the default when FOR is the only keyword specified.
AFTER triggers cannot be defined on views.
INSTEAD OF
Specifies that the DML trigger is executed instead of the triggering SQL statement, therefore, overriding the actions of the triggering statements. INSTEAD OF cannot be specified for DDL or logon triggers.
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql
I am newbie in SQL. I am reading about Triggers in SQL.I have got almost about Triggers. But in DML Triggers, we use FOR/AFTER keyword. I didn't get difference between FOR/AFTER and why we use FOR/AFTER keyword. I have already read on MSDN but didn't get the simple answer.
Can anyone explain me what is it?
Thanks in advance.
There is no difference between using FOR and AFTER.
I believe the original (pre 2000) syntax only used the FOR keyword. However, when INSTEAD OF triggers were introduced, the "FOR" keyword could seem quite confusing. "AFTER" more accurately conveys the type of trigger, and is more easily distinguished from "INSTEAD OF".
An INSTEAD OF trigger would be used if we wanted to transform what was inserted into the table, or prevent an insertion from taking place.
An AFTER trigger would more normally be used if we wanted to perform additional tasks, based on what has just occurred. For instance, you could have an "AFTER DELETE" trigger, that copied deleted rows into some kind of archive table. Basically, in an AFTER trigger, you more normally do still want the activity to occur.
From MSDN:
AFTER triggers are never executed if a constraint violation occurs; therefore, these triggers cannot be used for any processing that might prevent constraint violations.
And then:
You can request AFTER triggers by specifying either the AFTER or FOR keywords. Because the FOR keyword has the same effect as AFTER, DML triggers with the FOR keyword are also classified as AFTER triggers
It would seem there is no difference.
If I interpret your comments to the other answers correctly, you want to know why or when one uses the "FOR|AFTER" keywords.
It's simple: there are two kinds of triggers, the AFTER-trigger and the INSTEAD-OF-trigger.
The INSTEAD-OF-trigger for e.g. an insert action can be written as
create trigger myTrigger on myTable
INSTEAD OF insert
begin
(... code goes here ...)
end
and the AFTER-trigger can be written as either
create trigger myTrigger on myTable
AFTER insert
begin
(... code goes here ...)
end
or
create trigger myTrigger on myTable
FOR insert
begin
(... code goes here ...)
end
As Damien_The_Unbeliever mentions, the AFTER keyword is more readable than the FOR version, that is all.
They are the same. See this excerpt from BOL
"
FOR | AFTER
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.
AFTER is the default when FOR is the only keyword specified.
AFTER triggers cannot be defined on views.
"
According to what I observe, FOR is used in DDL trigger while AFTER is used in DML triggers. They have same way of working.
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.