Neben was @Craig bereitgestellt hat (und einige davon korrigiert):
Effective Postgres 9.4 , UNIQUE
, PRIMARY KEY
und EXCLUDE
werden Randbedingungen überprüft unmittelbar nach jeder Zeile , wenn definiert NOT DEFERRABLE
. Dies unterscheidet sich von anderen Arten von NOT DEFERRABLE
Einschränkungen (derzeit nur REFERENCES
(Fremdschlüssel)), die nach jeder Anweisung überprüft werden . All dies haben wir unter dieser verwandten Frage zu SO ausgearbeitet:
Es reicht nicht aus, dass eine UNIQUE
(oder PRIMARY KEY
oder EXCLUDE
) Einschränkung darin besteht DEFERRABLE
, dass der präsentierte Code mit mehreren Anweisungen funktioniert.
Und Sie können nicht verwenden ALTER TABLE ... ALTER CONSTRAINT
für diesen Zweck. Per Dokumentation:
ALTER CONSTRAINT
Dieses Formular ändert die Attribute einer zuvor erstellten Einschränkung. Derzeit können nur Fremdschlüsseleinschränkungen geändert werden .
Meine kühne Betonung. Verwenden Sie stattdessen:
ALTER TABLE t
DROP CONSTRAINT category_name_key
, ADD CONSTRAINT category_name_key UNIQUE(name) DEFERRABLE;
Löschen Sie die Einschränkung und fügen Sie sie in einer einzigen Anweisung wieder hinzu, damit niemand Zeit hat, sich in beleidigende Zeilen zu schleichen. Für große Tabellen wäre es verlockend, den zugrunde liegenden eindeutigen Index irgendwie beizubehalten, da es kostspielig ist, ihn zu löschen und neu zu erstellen. Leider scheint das mit Standardwerkzeugen nicht möglich zu sein (wenn Sie eine Lösung dafür haben, lassen Sie es uns bitte wissen!):
Für eine einzelne Anweisung reicht es aus , die Einschränkung aufschiebbar zu machen:
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;
Eine Abfrage mit CTEs ist auch eine einzelne Anweisung:
WITH x AS (
UPDATE category SET name = 'phones' WHERE id = 1
)
UPDATE category SET name = 'tablets' WHERE id = 2;
Allerdings , für Ihren Code mit mehreren Anweisungen Sie (zusätzlich) Notwendigkeit, tatsächlich defer die Einschränkung - oder definiert es als INITIALLY DEFERRED
entweder die Regel teurer als die oben ist. Es ist jedoch möglicherweise nicht einfach, alles in eine Aussage zu packen.
BEGIN;
SET CONSTRAINTS category_name_key DEFERRED;
UPDATE category SET name = 'phones' WHERE id = 1;
UPDATE category SET name = 'tablets' WHERE id = 2;
COMMIT;
Beachten Sie jedoch eine Einschränkung im Zusammenhang mit FOREIGN KEY
Einschränkungen. Per Dokumentation:
Die referenzierten Spalten müssen die Spalten einer nicht deferrierbaren Eindeutigkeits- oder Primärschlüsseleinschränkung in der referenzierten Tabelle sein.
Sie können also nicht beide gleichzeitig haben.