Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting constraint deferrable doesn't work on PostgreSQL transaction

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.

like image 225
frabala Avatar asked Feb 22 '11 19:02

frabala


People also ask

What is deferrable constraints in PostgreSQL?

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.

Why do you need deferrable option in case of SQL transactions?

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.

What is deferred constraint?

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 .

What is deferrable SQL?

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.


1 Answers

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.

like image 71
frabala Avatar answered Oct 13 '22 18:10

frabala