Row is not being deleted because of cascade trigger updates this row - sql

I have problem with deleteing rows in table which has trigger which invokes trigger of second table, which updates row in first table. Here is the description:
Table A (id,b_table_count)
Table B (id,a_table_id_fk)
Table A has trigger BEFORE DELETE which has instructions:
BEGIN
DELETE FROM b where a_table_fk = OLD.id;
RETURN OLD;
END;
Table B has trigger AFTER DELETE with instruction:
UPDATE a SET b_table_count = b_table_count-1 WHERE OLD.a_table_id_fk = a.id;
When I delete row from table A, which has no connected rows in B, everything is correct.
But, when I delete row from table A, which has connected row(s) in table B, then DELETE statement returns "Query returned successfully: 0 rows affected" . I must execute DELETE statment second time, then row is finnaly deleted. After first DELTE only connected ROWS are deleted in TABLE B, but row being deleted in table A remains.
Do you have answer for that? I suspect that pgsql doesn't allow to update row being deleted in trigger, but I haven't found anything about it in pgsql documentation.
What is the solution?

I'm having a similar problem, but with one table only. Deleting rows from the given table fires a trigger (before delete), that searches for related rows int the same table (by a given condition), and if finds them, these rows get updated. Now, if an updated row is to be deleted by the same delete command, then it doesn't gets deleted.
So basically, if you create a trigger, that always updates the same row that is being deleted, you can't delete anything from now on.
I don't know if this is on purpose, or not. From one way, it seems logical, that's for sure. If you update a record, it's not the same record that was intended for deletion.
(sorry for bad english)

So basicly you have a A -> trigger -> B -> trigger -> A situation, which is actually incorrect thing to do by design and I think postgres locks the row that is executing trigger or A row is locked but i'm not sure about all inner behavior of postgres.
so you can try DELETE FROM B WHERE a_id = %Row_to_delete_id% first and then
DELETE FROM A WHERE a_id = %Row_to_delete_id%, in a transaction,
but i highly recommend you revise your trigger dependencies

Related

How to fire trigger after all records inserted?

In SQL server, when does a trigger get fired?
The problem is, I have a table where 45,000 records are going to be inserted.
And I want to copy all 45k records to other tables.
But I don't want the trigger to run on every insert, i.e 45000 times trigger.
My trigger is basically copying record from TableA to TableB.
Trigger:
Create trigger tri_1
on TableA
after insert
as
Begin
Insert into TableB (ID,Name,Others)
select ID,Name,Others from TableA
inner join inserted
on inserted.ID = TableA.ID
End
The above is just the template of my trigger.
Also, I have a question, the trigger mentioned above, how is it working? like firing for each row or after all insert is done?
In SQL Server, the trigger is fired when the insert statement is completed.
In some databases, the trigger is executed for each row inserted (in those databases for each row is often part of the syntax). By contrast, SQL Server keeps track of the changed rows, which is why they are stored in table-like structures, inserted and deleted -- and it is a mistake to assume that these contain only one row.

Delete trigger not inserting record

Need a trigger which runs on deletion.
The code I wrote is not working: It is firing the trigger but is not inserting any records.
I want it to insert the to be deleted row in a audit table.
My code:
CREATE TRIGGER [EXERCISE].[delete_trigger] ON [EXERCISE].[Fact_Sales]
AFTER DELETE
AS
INSERT INTO [EXERCISE].[Fact_Sales_Audit](City_ID,Product_ID,Time_ID,Created_Date,Updated_Date)
SELECT F.City_ID,F.Product_ID,F.Time_ID,F.Created_Date,F.Updated_Date
FROM [EXERCISE].[Fact_Sales] F
JOIN deleted D
ON F.Fact_Sales_ID = D.Fact_Sales_ID
PRINT 'Deleted row entered.'
It is not working. Reason I suspect is- the row is being deleted from the table before the trigger is fired and thats why it is not able to join and hence not inserting any records. But when I debug and print messages I can see that trigger happens before deletion.
Can someone please explain me how exactly does this trigger work?
You are deleting rows from the [EXERCISE].[Fact_Sales] table, yet in your trigger you are joining to this table, expecting the records to still be there - they are not.
At that point, the Deleted pseudo-table has the same schema as the [EXERCISE].[Fact_Sales] table, but with the rows you have just deleted in it. Instead of trying to join back to a table for rows you know aren't there any more, just use the Deleted table directly for your insert:
CREATE TRIGGER [EXERCISE].[delete_trigger]
ON [EXERCISE].[Fact_Sales]
AFTER DELETE
AS
INSERT INTO [EXERCISE].[Fact_Sales_Audit](City_ID,Product_ID,Time_ID,Created_Date,Updated_Date)
SELECT D.City_ID,
D.Product_ID,
D.Time_ID,
D.Created_Date,
D.Updated_Date
FROM deleted D
The trigger does fire after the delete on the main table, as the AFTER DELETE syntax implies. It fires somewhere between when the delete statement is executed, and before the control is returned to the user. It takes place in the same transaction - e.g. if the delete was rolled back for whatever reason, the inserts performed by the trigger would also be rolled back.
You should simplify your trigger definition to fetch just deleted row(s) from virtual table DELETED. What will happen is your deleted rows will be temporarily stored in that table and then will be inserted into audit table.
NB! Be sure you have set primary key on your Fact_Sales table.
CREATE TRIGGER [delete_trigger] ON [Fact_Sales]
FOR DELETE
AS
INSERT INTO [Fact_Sales_Audit](Fact_Sales_Id,City_ID,Product_ID,Time_ID,Created_Date,Updated_Date)
SELECT Fact_Sales_Id,City_ID,Product_ID,Time_ID,Created_Date,Updated_Date
FROM DELETED

sql server: ROLLBACK inserted row only

I have a trigger that runs after the update record in the table A, add records to a table B
Now the table B has a trigger that works to ensure that the values ​​entered are correct, when there is a problem with it, the role of a trigger table B is to prevent the entry record (I can not use a unique index because the conditions are in other tables), but I want to avoid only the current record entry, as well as not to prevent the update is done in Table A and not the all good records in this transaction.
the ROLLBACK function is canceling all open transactions.

SQL Server INSERT trigger does not work

I have a trigger to copy over the data from Table A to table B when table A is changed
The trigger is like this :
ALTER TRIGGER ATrigger
ON A AFTER INSERT, DELETE, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM B WHERE id IN (SELECT id FROM deleted)
INSERT INTO B(Id, col1,col2) (SELECT i.Id, i.col1, i.col2 FROM inserted i)
END
But i see not all the data inserted in A are copied to B, the data copied seems very random
I was searching around, found it might caused by multi-insert, someone is suggesting using cusor, but i think for mine, it should be ok to insert or delete from the inserted, deleted table using this two sql.
Please advise, thanks!
I'm not certain this is your problem but your trigger has 2 "gotchas". First on an insert the deleted table will have no rows in it so no deletes will be done. Second is the reverse and potentially your problem. On a delete the inserted table has no rows. So all of the IDs are going to be deleted from table B but not re-inserted. On top of this if ID is not a unique key for table A then when you insert a second copy of it you will be deleting all of your history in table B and only adding the "new" history.
If you can provide more information on the structure of the 2 tables and the purpose of the trigger, not to mention any patterns on the rows being inserted or not being inserted as the case may be we can be of more help.

SQL update using values from the same record

In the following statement, will f1 always get the value that f2 used to have? Or will f2 sometimes get updated first and f1 winds up with NULL? I am under the impression that the new values are not available within the statement, that f2 has the old value while processing the record, but I can't find an authoritative place that says this.
UPDATE x
SET
x.f1 = x.f2,
x.f2 = NULL
Conceptually the operation happens "all at once" so it will use the "before" values
Indeed
UPDATE x
SET
x.f1 = x.f2,
x.f2 = x.f1
would also work fine to swap the two column values.
f1 will always get f2's previous value before the UPDATE.
Technically speaking the record is deleted, and reinserted. So SQL will work out what the new record should be, then delete the current record, and insert the new record afterwards.
This article regarding SQL Triggers may help explain:
The deleted table stores copies of the affected rows during DELETE and UPDATE statements. During the execution of a DELETE or UPDATE statement, rows are deleted from the trigger table and transferred to the deleted table. The deleted table and the trigger table ordinarily have no rows in common.
The inserted table stores copies of the affected rows during INSERT
and UPDATE statements. During an insert or update transaction, new
rows are added to both the inserted table and the trigger table. The
rows in the inserted table are copies of the new rows in the trigger
table.
http://msdn.microsoft.com/en-us/library/ms191300.aspx