This is the situation: I have two tables where the one references the other (say, table2 references table1). When creating these tables, I did set the foreign key constraint as DEFERRABLE and the ON UPDATE and ON DELETE clauses as NO ACTION (which is the default).
But still, when running the transaction below, I get the following error.
Transaction:
START TRANSACTION;
SET CONSTRAINTS ALL DEFERRED;
UPDATE table1 SET blah blah;
UPDATE table2 SET blah blah;
COMMIT;
Error:
ERROR: update or delete on table "table1" violates foreign key constraint "table1_column_fkey" on table "table2"
DETAIL: Key (column1)=(blahblah) is still referenced from table "table2".
And table construction:
CREATE TABLE table1(
column1 CHAR(10),
[...]
PRIMARY KEY (column1)
);
CREATE TABLE table2(
primkey CHAR(9),
[...]
column2 CHAR(10) NOT NULL,
PRIMARY KEY(primkey),
FOREIGN KEY(column2) REFERENCES table1(column1) DEFERRABLE
);
What I want to do is to defer the foreign key checking while the transaction is in progress, until it commits. I just can't see why is this error returning and how can I make the transaction work.
If a constraint is deferrable, this clause specifies the default time to check the constraint. If the constraint is INITIALLY IMMEDIATE, it is checked after each statement, which is the default. If the constraint is INITIALLY DEFERRED, it is checked only at the end of the transaction.
In this case a statement is allowed to make its full set of changes before the database checks for violations. By transaction. Any statement inside a transaction is free to violate constraints. However at commit time the constraints will be checked, and the transaction will fail if any constraints do not hold.
DEFERRED constraints are not checked until transaction commit. Each constraint has its own IMMEDIATE or DEFERRED mode. Upon creation, a constraint is given one of three characteristics: DEFERRABLE INITIALLY DEFERRED , DEFERRABLE INITIALLY IMMEDIATE , or NOT DEFERRABLE .
In SQL Server Enterprise, a corrupted transaction can become deferred if data required by rollback (undo) is offline during database startup. A deferred transaction is a transaction that is uncommitted when the roll forward phase finishes and that has encountered an error that prevents it from being rolled back.
The problem was indeed a foreign key constraint violation. I mean, the constraints were indeed deferred within the transaction, but the problem was that at the end of the transaction, after table1 and table2 were updated, the new data were violating a foreign key constraint. I was updating the primary key of a table1 row, which was still being referenced by some table2 rows. These rows I had to update them too, so that the referencing column of table2 rows matched the updated primary key of table1's row. I changed the 'UPDATE' queries within the transaction and the problem got solved.
Sorry to put you into this. The solution was so simple, but that day I coudn't see it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With