Ich habe eine Tabelle wie die folgende:
create table my_table (
id int8 not null,
id_A int8 not null,
id_B int8 not null,
id_C int8 null,
constraint pk_my_table primary key (id),
constraint u_constrainte unique (id_A, id_B, id_C)
);
Und ich möchte (id_A, id_B, id_C)
in jeder Situation anders sein. Die folgenden zwei Einfügungen müssen also zu einem Fehler führen:
INSERT INTO my_table VALUES (1, 1, 2, NULL);
INSERT INTO my_table VALUES (2, 1, 2, NULL);
Es verhält sich jedoch nicht wie erwartet, da laut Dokumentation zwei NULL
Werte nicht miteinander verglichen werden, sodass beide Einfügungen fehlerfrei verlaufen.
Wie kann ich meine eindeutige Einschränkung garantieren, auch wenn id_C
dies NULL
in diesem Fall der Fall sein kann? Eigentlich lautet die eigentliche Frage: Kann ich diese Art von Einzigartigkeit in "pure sql" garantieren oder muss ich sie auf einer höheren Ebene implementieren (in meinem Fall Java)?
postgresql
constraint
null
unique-constraint
Manuel Leduc
quelle
quelle
(1,2,1)
und(1,2,2)
in den(A,B,C)
Spalten. Soll ein(1,2,NULL)
hinzugefügt werden dürfen oder nicht?Antworten:
Sie können das in reinem SQL tun . Erstellen Sie einen partiellen eindeutigen Index zusätzlich zu dem, den Sie haben:
So können Sie
(a, b, c)
in Ihre Tabelle eingeben :Aber keines davon ein zweites Mal.
Oder verwenden Sie zwei Teilindizes
UNIQUE
und keinen vollständigen Index (oder Einschränkung). Die beste Lösung hängt von den Details Ihrer Anforderungen ab. Vergleichen Sie:Dies ist zwar elegant und effizient für eine einzelne nullfähige Spalte im
UNIQUE
Index, gerät jedoch schnell außer Kontrolle . Diskutieren Sie dies - und wie Sie UPSERT mit Teilindizes verwenden:Nebenbei
Keine Verwendung für Bezeichner mit gemischten Groß- und Kleinschreibung ohne Anführungszeichen in PostgreSQL.
Sie können eine
serial
Spalte als Primärschlüssel oder eineIDENTITY
Spalte in Postgres 10 oder höher betrachten. Verbunden:Damit:
Wenn Sie nicht mehr als 2 Milliarden Zeilen (> 2147483647) über die Lebensdauer Ihrer Tabelle (einschließlich Abfall und gelöschter Zeilen) erwarten, sollten Sie
integer
(4 Bytes) anstelle vonbigint
(8 Bytes) in Betracht ziehen .quelle
Ich hatte das gleiche Problem und fand einen anderen Weg, eindeutige NULL in die Tabelle aufzunehmen.
In meinem Fall ist das Feld
foreign_key_field
eine positive ganze Zahl und wird niemals -1 sein.Also, um Manual Leduc zu beantworten, könnte eine andere Lösung sein
Ich gehe davon aus, dass die IDs nicht -1 sein werden.
Was ist der Vorteil beim Erstellen eines Teilindex?
Für den Fall, Sie haben nicht die NOT NULL - Klausel
id_a
,id_b
undid_c
können zusammen nur einmal NULL sein.Bei einem Teilindex können die 3 Felder mehr als einmal NULL sein.
quelle
COALESCE
kann die Duplikate effektiv einschränken, aber der Index wäre beim Abfragen nicht sehr nützlich, da er ein Ausdrucksindex ist, der wahrscheinlich nicht mit Abfrageausdrücken übereinstimmt. Das heißt, es sei denn,SELECT COALESCE(col, -1) ...
Sie würden den Index nicht erreichen.Eine Null kann bedeuten, dass der Wert für diese Zeile im Moment nicht bekannt ist, aber, falls bekannt, in Zukunft hinzugefügt wird (Beispiel
FinishDate
für einen LaufProject
) oder dass für diese Zeile kein Wert angewendet werden kann (BeispielEscapeVelocity
für ein Schwarzes LochStar
).Meiner Meinung nach ist es normalerweise besser, die Tabellen zu normalisieren, indem alle Nullen entfernt werden.
In Ihrem Fall möchten Sie
NULLs
in Ihrer Spalte zulassen , möchten jedoch nur eineNULL
zulassen. Warum? Welche Art von Beziehung besteht zwischen den beiden Tabellen?Vielleicht können Sie einfach die Spalte ändern
NOT NULL
und stattdessenNULL
einen speziellen Wert (wie-1
) speichern, von dem bekannt ist , dass er niemals erscheint. Dies löst das Problem der Eindeutigkeitseinschränkung (kann jedoch andere möglicherweise unerwünschte Nebenwirkungen haben. Wenn Sie beispielsweise-1
"nicht bekannt / trifft nicht zu" verwenden, werden Summen- oder Durchschnittsberechnungen für die Spalte verzerrt. Andernfalls müssen alle derartigen Berechnungen ausgeführt werden berücksichtigen Sie den speziellen Wert und ignorieren Sie ihn.)quelle