If the table has more than one FOR INSERT trigger and one of them writes to an audit table and the other does a rollback is the audit rolled back - sql-server-2017

Let's say a table has a validation trigger that enforces some business logic:
TRG_MYTABLE_INSERT_UPDATE_VALIDATION
FOR INSERT, UPDATE on MYTABLE
and an audit trigger that writes all inserts and updates to another table.
TRG_MYTABLE_INSERT_UPDATE_AUDIT
FOR INSERT, UPDATE on MYTABLE
and there's no guarantee that they will be executed in a particular order, will a rollback in the VALIDATION trigger rollback the write to the audit table?
Are all of the triggers enlisted in the same transaction "behind the scenes"?

To answer the question about triggers and transactions: yes triggers are enlisted in the same explicit, or implicit, transaction as the code that executes the statement which makes the trigger fire is enlisted in.
Furthermore, in SQL Server triggers runs be default under XACT_ABORT ON which means that if an error happens in the trigger, the WHOLE transaction is rolled back immediately.
So the answer to your question is that if an error happens in either of the triggers, the whole transaction is rolled back.
You can however do a SET XACT_ABORT OFF in your transaction code, in which case, a rollback would only impact whatever you do in the trigger. That is UNLESS your calling code starts a transaction, and you explicitly do a ROLLBACK in your trigger.
The above is why you should be very careful with using triggers in the first place.

Related

Where is the flaw in my trigger to override DELETE with a soft-delete?

I have a trigger created with
CREATE TRIGGER [CantDeleteStuff] ON [dbo].[Stuff]
INSTEAD OF DELETE
AS
BEGIN
ROLLBACK
UPDATE [dbo].[Stuff] SET [Deleted]=1 FROM DELETED WHERE [dbo].[Stuff].[Id] = DELETED.[Id]
END
GO
and I think it's intent is clear. But when I try to delete a row I get the error
The transaction ended in the trigger. The batch has been aborted.
How to fix?
Instead of Delete will replace the Delete with your triggering code.
According to Technet, the Rollback in your trigger is the issue. You can read more here.
A trigger operates as if there were an outstanding transaction in effect when the trigger is executed. This is true whether the statement firing the trigger is in an implicit or explicit transaction.
When a statement begins executing in autocommit mode, there is an implied BEGIN TRANSACTION to allow the recovery of all modifications generated by the statement if it encounters an error. This implied transaction has no effect on the other statements in the batch because it is either committed or rolled back when the statement completes. This implied transaction is still in effect, however, when a trigger is called.
When a trigger executes, an implicit transaction is started. If the trigger completes execution and ##TRANCOUNT = 0, error 3609 occurs and the batch is terminated. If a BEGIN TRANSACTION statement is issued in a trigger, it creates a nested transaction. In this situation, when a COMMIT TRANSACTION statement is executed, the statement will apply only to the nested transaction.
When using ROLLBACK TRANSACTION in a trigger, be aware of the following behavior:
All data modifications made to that point in the current transaction are rolled back, including any that were made by the trigger.
The trigger continues executing any remaining statements after the ROLLBACK statement. If any of these statements modify data, the modifications are not rolled back.
A ROLLBACK in a trigger closes and deallocates all cursors that were declared and opened in the batch containing the statement that fired the trigger. This includes cursors declared and opened in stored procedures called by the batch that fired the trigger. Cursors declared in a batch prior to the batch that fired the trigger are only closed. However, STATIC or INSENSITIVE cursors are left open if:
CURSOR_CLOSE_ON_COMMIT is set OFF.
The static cursor is either synchronous or a fully populated asynchronous cursor.
Instead of using ROLLBACK TRANSACTION, the SAVE TRANSACTION statement can be used to execute a partial rollback in a trigger.
https://technet.microsoft.com/en-us/library/ms187844(v=sql.105).aspx
So just remove the Rollback.

What does COMMIT do?

please I want to understand the difference between the folowing two statements:
insert into table_name values (,,,,,);
and
insert into table_name values (,,,,,);
commit;
If you insert data without commit you can select data from database and see it. But other users can't.
It's better to look to sql documentation:
Until you commit a transaction:
You can see any changes you have made during the transaction by
querying the modified tables, but other users cannot see the changes.
After you commit the transaction, the changes are visible to other
users' statements that execute after the commit.
You can roll back (undo) any changes made during the transaction with
the ROLLBACK statement (see ROLLBACK.
for example here Oracle Documentation
and some info about transactions
All the DML (insert, update , delete) to be inserted in the database you have to commit them, like approve that you want to add them in the database. If you dont commit DML statment , it will not be enter in the database.
what is commit ?
Docs.oracle cant describe it better
Use the COMMIT statement to end your current transaction and make
permanent all changes performed in the transaction. A transaction is a
sequence of SQL statements that Oracle Database treats as a single
unit. his statement also erases all savepoints in the transaction and
releases transaction locks.

When do I have to commit?

I heard in SQL I do not have to commit every statement. Perhaps create I don't have to.
So can you answer me which Statements I have to commit?
I read, that I have to commit all transactions, but I don't know what this is and can't find it anywhere.
Thanks for your help.
Per the SQL standard, most statements that require a transaction will automatically open one.
Some database engines, such as SQL Server, will (by default) automatically commit the transaction if the statement completes successfully. See Autocommit Transactions.
Autocommit mode is the default transaction management mode of the SQL Server Database Engine. Every Transact-SQL statement is committed or rolled back when it completes
SQL Server also has an Implicit Conversions mode which will leave the transaction open until it's explicitly commited.
When operating in this second such mode (which is the default, I believe, for Oracle), or if you've explicitly created a transaction, it's up to you as a developer when to commit the transaction. It should be when you've accomplished a "complete" set of operations against the database.
If you BEGIN a transaction then you have to either ROLLBACK or COMMIT
Example:
BEGIN TRAN
--Your code
INSERT INTO
NewTable
SELECT *
FROM TABLE
COMMIT TRAN
If you do not use that, it is committed upon execution. So the follow will either fail or be committed:
INSERT INTO
NewTable
SELECT *
FROM Table
If there is an error (like there is no NewTable in the DB) the execution will raise an error and the transaction will roll back. If there is no error the transaction will be committed.

When exactly is an AFTER DELETE trigger fired

I hope that you can help me on some SQL theory, as I am not 100% sure how this works.
If I have a trigger and I define it as
AFTER DELETE ON xxxx
I was wondering when exactly this would fire, in terms of transaction management?
So if I delete a record from my table I assume that the trigger will not fire until I type commit and finish the transaction. Is this correct?
If so, then I assume that if the commit on my delete statement works but the trigger fails for some reason then only the trigger would be rolled back, and the original executed delete statement that I performed would still be committed (because I have it defined as AFTER DELETE).
Can somebody please confirm this?
Thanks.
1. You delete a row on TABLE1 no COMMIT;
2. TRIGGER performs an action (This takes place before COMMIT or ROLLBACK for step1, but trigger will not have any commit or rollback in it)
3a. You apply commit - Both step1 and step2 gets completed .
3b. You apply rollback- Both step1 and step2 rolled back.
Either you give 3a or 3b
The purpose of SQL triggers is to ensure referential consistency. But when they would be exectued in a separate transaction commit, there would be the possibility that they leave data in an inconsistent state.
So the delete trigger is executed the moment you do the delete command. When this happens as a transaction and you roll it back, the triggered delete is also rolled back.
An AFTER DELETE trigger is fired after the delete statement is executed, and before the control is returned to the user - i.e., he perceives the delete statement and the code executed after it in a trigger as a single action (assuming the trigger just does DMLs and nothing funky like calling UTL_TCP :-)).
This has nothing to do with transaction management - once the DELETE and the AFTER DELETE trigger execute, you can choose to commit, to rollback, or to continue performing DML statements in the same transaction.

Truncate Table Within Transaction

Can the SQL "truncate table" command be used within a transaction? I am creating an app and my table has a ton of records. I want to delete all the records, but if the app fails I was to rollback my transaction. Deleting each record takes a very long time. I'm wondering if I use truncate table, can I still rollback the transaction and get my data back in the event of a failure. I realize that truncate table doesn't write each delete to the transaction log, but I'm wondering if it writes the page deallocation to the log so that rollback works.
In SQL Server, you can rollback a TRUNCATE from a transaction. It does write page deallocation to the log, as you mentioned.
In Oracle, TRUNCATE TABLE is a DDL statement that cannot be used in a transaction (or, more accurately, cannot be rolled back). AFAIK, if there is a transaction in progress when the statement is executed, the transaction is committed and then the TRUNCATE is executed and cannot be undone.
In Informix, the behaviour of TRUNCATE is slightly different; you can use TRUNCATE in a transaction, but the only statements permissible after that are COMMIT and ROLLBACK.
Other DBMS probably have their own idiosyncratic interpretations of the behaviour of TRUNCATE TABLE.
If you read the official documentation of PostgreSQL, It said that The TRUNCATE TABLE statement is transaction-safe.