PostgreSQL 9.0 und höher
PostgreSQL 9.0 hinzugefügt aufschiebbare eindeutige Beschränkungen was genau die Funktion ist, die Sie zu brauchen scheinen. Auf diese Weise wird die Einzigartigkeit zum Zeitpunkt der Übergabe und nicht zum Zeitpunkt der Aktualisierung geprüft.
Erstellen Sie die UNIQUE-Beschränkung mit dem Schlüsselwort DEFERRABLE:
ALTER TABLE foo ADD CONSTRAINT foo_uniq (foo_id) DEFERRABLE;
Später, bevor Sie die UPDATE-Anweisung ausführen, führen Sie dieselbe Transaktion durch:
SET CONSTRAINTS foo_uniq DEFERRED;
Alternativ können Sie die Einschränkung auch mit dem Befehl INITIALLY DEFERRED
Schlüsselwort für die eindeutige Einschränkung selbst - Sie müssen also nicht SET CONSTRAINTS
-- aber das könnte die Leistung Ihrer anderen Abfragen beeinträchtigen, die die Einschränkung nicht aufschieben müssen.
PostgreSQL 8.4 und älter
Wenn Sie die eindeutige Einschränkung nur zum Garantieren der Eindeutigkeit verwenden möchten - nicht als Ziel für einen Fremdschlüssel - dann könnte dieser Workaround helfen:
Fügen Sie zunächst eine boolesche Spalte wie is_temporary
in der Tabelle, die vorübergehend zwischen aktualisierten und nicht aktualisierten Zeilen unterscheidet:
CREATE TABLE foo (value int not null, is_temporary bool not null default false);
Als nächstes erstellen Sie eine Teilweise eindeutiger Index die nur Zeilen betrifft, bei denen is_temporary=false ist:
CREATE UNIQUE INDEX ON foo (value) WHERE is_temporary=false;
Wenn Sie nun die von Ihnen beschriebenen Aktualisierungen vornehmen, führen Sie sie in zwei Schritten durch:
UPDATE foo SET is_temporary=true, value=value+1 WHERE value>3;
UPDATE foo SET is_temporary=false WHERE is_temporary=true;
Solange diese Anweisungen in einer einzigen Transaktion erfolgen, ist dies völlig sicher - andere Sitzungen werden die temporären Zeilen nie sehen. Der Nachteil ist, dass Sie die Zeilen zweimal schreiben müssen.
Beachten Sie, dass es sich hierbei lediglich um einen eindeutigen Index handelt, nicht um einen Einschränkung aber in der Praxis sollte das keine Rolle spielen.