Oltre a quanto fornito da @Craig (e correggendone alcuni):
Efficace Postgres 9.4 , UNIQUE
, PRIMARY KEY
e EXCLUDE
vincoli vengono controllati immediatamente dopo ogni riga quando definito NOT DEFERRABLE
. Questo è diverso da altri tipi di NOT DEFERRABLE
vincoli (attualmente solo REFERENCES
(chiave esterna)) che vengono controllati dopo ogni istruzione . Abbiamo risolto tutto questo con questa domanda correlata su SO:
E ' non è sufficiente per una UNIQUE
(o PRIMARY KEY
o EXCLUDE
) vincolo di essere DEFERRABLE
per rendere il codice presentato con più istruzioni di lavoro.
Ed è possibile non utilizzare ALTER TABLE ... ALTER CONSTRAINT
per questo scopo. Per documentazione:
ALTER CONSTRAINT
Questo modulo modifica gli attributi di un vincolo precedentemente creato. Attualmente è possibile modificare solo i vincoli di chiave esterna .
Enorme enfasi sulla mia. Usa invece:
ALTER TABLE t
DROP CONSTRAINT category_name_key
, ADD CONSTRAINT category_name_key UNIQUE(name) DEFERRABLE;
Rilascia e aggiungi nuovamente il vincolo in una singola istruzione in modo che non ci sia tempo per nessuno che si intrufoli nelle file offensive. Per le tabelle di grandi dimensioni sarebbe in qualche modo allettante conservare l'indice univoco sottostante, in quanto è costoso eliminarlo e ricrearlo. Purtroppo, ciò non sembra possibile con gli strumenti standard (se hai una soluzione per questo, faccelo sapere!):
Per una singola affermazione è sufficiente rendere differibile il vincolo:
UPDATE category c
SET name = c_old.name
FROM category c_old
WHERE c.id IN (1,2)
AND c_old.id IN (1,2)
AND c.id <> c_old.id;
Una query con CTE è anche una singola istruzione:
WITH x AS (
UPDATE category SET name = 'phones' WHERE id = 1
)
UPDATE category SET name = 'tablets' WHERE id = 2;
Tuttavia , per il tuo codice con più istruzioni devi (in aggiunta) effettivamente rinviare il vincolo o definirlo come INITIALLY DEFERRED
O è in genere più costoso di quanto sopra. Ma potrebbe non essere facilmente fattibile racchiudere tutto in un'unica istruzione.
BEGIN;
SET CONSTRAINTS category_name_key DEFERRED;
UPDATE category SET name = 'phones' WHERE id = 1;
UPDATE category SET name = 'tablets' WHERE id = 2;
COMMIT;
Essere consapevoli di una limitazione in relazione ai FOREIGN KEY
vincoli, però. Per documentazione:
Le colonne di riferimento devono essere le colonne di un vincolo di chiave unica o primaria non differibile nella tabella di riferimento.
Quindi non puoi avere entrambi allo stesso tempo.