Kann ein Fremdschlüssel NULL sein?
Die bisherigen Antworten konzentrierten sich auf ein einspaltiges Szenario. Wenn wir einen mehrspaltigen Fremdschlüssel betrachten, haben wir mehr Möglichkeiten, indem wir MATCH [SIMPLE | PARTIAL | FULL]
Klausel, die im SQL-Standard definiert ist:
PostgreSQL-CREATE TABLE
Ein in die referenzierende(n) Spalte(n) eingefügter Wert wird mit den Werten der referenzierten Tabelle und der referenzierten Spalten unter Verwendung des angegebenen Übereinstimmungstyps abgeglichen. Es gibt drei Abgleichsarten: MATCH FULL, MATCH PARTIAL und MATCH SIMPLE (dies ist die Standardeinstellung). MATCH FULL lässt nicht zu, dass eine Spalte eines mehrspaltigen Fremdschlüssels Null ist, es sei denn, alle Fremdschlüsselspalten sind Null; wenn sie alle Null sind, muss die Zeile keine Übereinstimmung in der referenzierten Tabelle haben. MATCH SIMPLE lässt zu, dass eine der Fremdschlüsselspalten Null ist; wenn eine von ihnen Null ist, muss die Zeile keine Übereinstimmung in der referenzierten Tabelle haben. TEILWEISE ÜBEREINSTIMMEN ist noch nicht implementiert.
(Natürlich können NOT NULL-Beschränkungen auf die referenzierende(n) Spalte(n) angewendet werden, um diese Fälle zu vermeiden).
Beispiel:
CREATE TABLE A(a VARCHAR(10), b VARCHAR(10), d DATE , UNIQUE(a,b));
INSERT INTO A(a, b, d)
VALUES (NULL, NULL, NOW()),('a', NULL, NOW()),(NULL, 'b', NOW()),('c', 'b', NOW());
CREATE TABLE B(id INT PRIMARY KEY, ref_a VARCHAR(10), ref_b VARCHAR(10));
-- MATCH SIMPLE - default behaviour nulls are allowed
ALTER TABLE B ADD CONSTRAINT B_Fk FOREIGN KEY (ref_a, ref_b)
REFERENCES A(a,b) MATCH SIMPLE;
INSERT INTO B(id, ref_a, ref_b) VALUES (1, NULL, 'b');
-- (NULL/'x') 'x' value does not exists in A table, but insert is valid
INSERT INTO B(id, ref_a, ref_b) VALUES (2, NULL, 'x');
ALTER TABLE B DROP CONSTRAINT IF EXISTS B_Fk; -- cleanup
-- MATCH PARTIAL - not implemented
ALTER TABLE B ADD CONSTRAINT B_Fk FOREIGN KEY (ref_a, ref_b)
REFERENCES A(a,b) MATCH PARTIAL;
-- ERROR: MATCH PARTIAL not yet implemented
DELETE FROM B; ALTER TABLE B DROP CONSTRAINT IF EXISTS B_Fk; -- cleanup
-- MATCH FULL nulls are not allowed
ALTER TABLE B ADD CONSTRAINT B_Fk FOREIGN KEY (ref_a, ref_b)
REFERENCES A(a,b) MATCH FULL;
-- FK is defined, inserting NULL as part of FK
INSERT INTO B(id, ref_a, ref_b) VALUES (1, NULL, 'b');
-- ERROR: MATCH FULL does not allow mixing of null and nonnull key values.
-- FK is defined, inserting all NULLs - valid
INSERT INTO B(id, ref_a, ref_b) VALUES (1, NULL, NULL);
db<>fiddle demo