I have a column sort_order
with a unique constraint on it.
The following SQL fails on Postgres 9.5:
UPDATE test
SET sort_order = sort_order + 1;
-- [23505] ERROR: duplicate key value violates unique constraint "test_sort_order_key"
-- Detail: Key (sort_order)=(2) already exists.
Clearly, if the sort_order
values were unique before the update, they will still be unique after the update. Why is this?
The same statement works fine on Oracle and MS SQL, but also fails on MySQL and SQLite.
Here's the complete setup code for a SQL fiddle:
DROP TABLE IF EXISTS test;
CREATE TABLE test (
val TEXT,
sort_order INTEGER NOT NULL UNIQUE
);
INSERT INTO test
VALUES ('A', 1), ('B', 2);
To find the name of a constraint in PostgreSQL, use the view pg_constraint in the pg_catalog schema. Join the view pg_catalog. pg_constraint with the view pg_class ( JOIN pg_class t ON t. oid = c.
The PostgreSQL PRIMARY KEY is a column in a table which must contain a unique value which can be used to identify each and every row of a table uniquely.
While the SQL standard allows multiple nulls in a unique column, and that is how Postgres behaves, some database systems (e.g. MS SQL) allow only a single null in such cases.
The syntax for creating a unique constraint using an ALTER TABLE statement in PostgreSQL is: ALTER TABLE table_name ADD CONSTRAINT constraint_name UNIQUE (column1, column2, ... column_n); table_name.
Postgres decides to check constraints of type IMMEDIATELY
at a different time than proposed in the SQL standard.
Specifically, the documentation for SET CONSTRAINTS
states (emphasis mine):
NOT NULL and CHECK constraints are always checked immediately when a row is inserted or modified (not at the end of the statement). Uniqueness and exclusion constraints that have not been declared DEFERRABLE are also checked immediately.
Postgres chooses to execute this query using a plan that results in a temporary collision for sort_order
and IMMEDIATELY fails. Note that means that for the same schema and the same data, the same query may work or fail depending on the execution plan.
You'll have to make the constraint DEFERRABLE
or DEFERRABLE INITIALLY DEFERRED
, which delays verification of the constraint until the end of the transaction or up to the point where a statement SET CONSTRAINTS ... IMMEDIATE
is executed.
Addendum from @HansGinzel's comment:
for
COPY
, it seems, that (even IMMEDIATE) constraints are tested after all data are COPYied.
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