Postgresql: Bedingt eindeutige Einschränkung

116

Ich möchte eine Einschränkung hinzufügen, die die Eindeutigkeit einer Spalte nur in einem Teil einer Tabelle erzwingt.

ALTER TABLE stop ADD CONSTRAINT myc UNIQUE (col_a) WHERE (col_b is null);

Der WHEREobige Teil ist Wunschdenken.

Wie geht das? Oder sollte ich zum relationalen Zeichenbrett zurückkehren?

EoghanM
quelle
2
Häufig gemacht. Siehe "teilweise eindeutiger Index"
Craig Ringer
11
@yvesonline nein, das ist eine reguläre eindeutige Einschränkung. Das Poster möchte eine teilweise eindeutige Einschränkung.
Craig Ringer

Antworten:

186

PostgreSQL definiert keine partielle (dh bedingte) UNIQUEEinschränkung. Sie können jedoch einen partiellen eindeutigen Index erstellen . PostgreSQL verwendet eindeutige Indizes, um eindeutige Einschränkungen zu implementieren. Der Effekt ist also der gleiche. Sie sehen die darin aufgeführte Einschränkung einfach nicht information_schema.

CREATE UNIQUE INDEX stop_myc ON stop (col_a) WHERE (col_b is NOT null);

Siehe Teilindizes .

Craig Ringer
quelle
24
Super! Unintuitiv, dass die "Einschränkung" nicht als Einschränkung ERROR: duplicate key value violates unique constraint "stop_myc"
angezeigt wird
7
Es ist anzumerken, dass dies nicht das Erstellen von FKs ermöglicht, die auf dieses teilweise eindeutige Feld verweisen.
Ffflabs
11
Es ist auch erwähnenswert, dass diese Indexeffekte nicht zurückgestellt werden können. Wenn Sie Massenaktualisierungen durchführen müssen, kann dies ein Problem darstellen, da die Eindeutigkeit nach jeder Zeile überprüft wird, nicht nach der Anweisung, wie sie für eine Einschränkung wäre, oder nach der Transaktion, wie es für eine aufschiebbare Einschränkung wäre.
sage88
37

Es wurde bereits gesagt, dass PG keine partielle (dh bedingte) EINZIGARTIGE Einschränkung definiert. Die Dokumentation besagt auch, dass die bevorzugte Methode zum Hinzufügen einer eindeutigen Einschränkung zu einer Tabelle ADD CONSTRAINT eindeutige Indizes ist

Die bevorzugte Methode zum Hinzufügen einer eindeutigen Einschränkung zu einer Tabelle ist ALTER TABLE ... ADD CONSTRAINT. Die Verwendung von Indizes zum Erzwingen eindeutiger Einschränkungen kann als Implementierungsdetail betrachtet werden, auf das nicht direkt zugegriffen werden sollte. Man sollte sich jedoch bewusst sein, dass es nicht notwendig ist, Indizes für eindeutige Spalten manuell zu erstellen. Dies würde nur den automatisch erstellten Index duplizieren.

Es gibt eine Möglichkeit, es mithilfe von Ausschlussbeschränkungen zu implementieren (danke @dukelion für diese Lösung).

In deinem Fall wird es so aussehen

ALTER TABLE stop ADD CONSTRAINT myc EXCLUDE (col_a WITH =) WHERE (col_b IS null);
Peter Yeremenko
quelle
Bei diesem Ansatz verwenden Sie nicht "using", um die Indexmethode zu definieren, sodass dies extrem langsam sein kann oder postgres einen Standardindex dafür erstellt. Diese Methode ist die kanonische Wahl, aber niemals die bessere Wahl! Ich denke, Sie brauchen eine "using" -Klausel mit Index, damit diese Wahl die bessere ist.
Natan Medeiros
10
Die Ausschlusslösung ist zwar langsamer, hat jedoch den Vorteil, dass sie aufschiebbar ist (und standardmäßig bis zum Ende der Anweisung verschoben wird). Im Gegensatz dazu kann die akzeptierte eindeutige Indexlösung nicht zurückgestellt werden (und wird nach jedem Zeilenwechsel überprüft). Ein Massenupdate ist daher häufig nicht möglich, da Schritte während des Updates die eindeutige Einschränkung verletzen würden, selbst wenn sie am Ende der atomaren Update-Anweisung nicht verletzt würden.
sage88
1
Diese Notiz wurde im August 2015
Raniz