Neben was @Craig bereitgestellt hat (und einige davon korrigiert):
Effective Postgres 9.4 , UNIQUE, PRIMARY KEYund EXCLUDEwerden Randbedingungen überprüft unmittelbar nach jeder Zeile , wenn definiert NOT DEFERRABLE. Dies unterscheidet sich von anderen Arten von NOT DEFERRABLEEinschrä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 KEYoder EXCLUDE) Einschränkung darin besteht DEFERRABLE, dass der präsentierte Code mit mehreren Anweisungen funktioniert.
Und Sie können nicht verwenden ALTER TABLE ... ALTER CONSTRAINTfü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 DEFERREDentweder 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 KEYEinschrä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.