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.
Related
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.
I'm having a little trouble with understanding functions and triggers in sql. I didn't post the code of procedure chkInsertAritcle but let's say it returns NEW if it managed to make change and NULL if it didn't.
So my question is about the trigger. If I put AFTER INSERT does that means that it will complete INSERT without depending on the return value? And what
happens with the rest of the rows?
Next question is if I put BEFORE INSERT, in what order does code runs?
Thanks!
CREATE TRIGGER ArticleIns
AFTER INSERT ON ListOfArticles
FOR EACH ROW
EXECUTE PROCEDURE chkInsertArticle();
First all BEFORE triggers run in alphabetical order, then the operation is performed, then all AFTER triggers run in alphabetical order.
Each operation sees the result of the previous one as input, and if any trigger returns NULL, processing for that row stops. So if a BEFORE trigger returns NULL, the DML operation won't take place.
This happens independently for each row affected by the triggering DML statement.
So if the trigger runs before insert, then the code runs before the data is inserted into the row and constraints are checked. So for example you might want to add a timestamp before the data is committed to the database,
If it runs after then the data is already present in the table and all constraints have been checked. This is usually where you want to trigger another process based on the row data, maybe update another table, send an e-mail etc.
In your example, the data will be in the database before your procedure runs. So if your procedure modifies the row data, it needs to be in the database.
I want my database to show the table every time while I insert a new row. My code is able to compile but It don't show the table after I insert a new row.
Below is my code :
create trigger show_all
after insert ON Toy
for each row mode db2sql
select * from Toy
This isn't possible.
Triggers don't return a value to the statement (insert) that caused the trigger to fire. Further, that behaviour wouldn't even be possible because multiple triggers could fire in response to an insert, which would get to return something?
You could create a stored procedure that performs an insert and then returns the result of a select, and then call that function instead of inserting directly.
If I have a statement
that updates multiple rows, only the trigger will fire only on the first or last row that is being updated (not sure which one). I need to make a trigger that fires for ALL the records that are being updated into a particular table
Assuming SQL Server, A trigger only fires once per update, regardless of the number of rows that are updated. If you need to carry out some additional logic based on updates to multiple rows you can access the changed records by looking at the INSERTED and DELETED logical tables that are accessible in the context of a trigger.
You have not specified the database .....
In Oracle a trigger can be defined to fire for individual rows and based on the type of transaction:
CREATE OR REPLACE TRIGGER BIUDR_MY_TABLE
BEFORE INSERT OR UPDATE OR DELETE
ON MY_TABLE
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
pk PLS_INTEGER;
BEGIN
etc ....
You just need to indicate if your trigger needs to be executed "FOR EACH ROW" or "FOR EACH STATEMENT". Adding one of these two clauses in the trigger definition will tell the DBMS when to execute the trigger (most, but not all, DBMSs support it). If you don't indicate this clause then the DBMS uses the default option which in your case seems to be the FOR EACH STATEMENT option, and that's why your trigger only fires one for each update sentence, regardless of how many rows you are updating
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.