wake-up-neo.com

Können Tabellenspalten mit einem Fremdschlüssel NULL sein?

Ich habe eine Tabelle, die mehrere ID-Spalten zu anderen Tabellen hat.

Ich möchte, dass ein Fremdschlüssel die Integrität erzwingt nur, wenn ich dort Daten einspeichere. Wenn ich zu einem späteren Zeitpunkt ein Update durchführe, um diese Spalte zu füllen, sollte auch die Einschränkung überprüft werden.

(Dies ist wahrscheinlich datenbankserverabhängig. Ich verwende den Tabellentyp MySQL & InnoDB.)

Ich halte das für eine vernünftige Erwartung, aber korrigiere mich, wenn ich falsch liege.

194
bender

Ja, Sie können die Einschränkung nur erzwingen, wenn der Wert nicht NULL ist. Dies kann anhand des folgenden Beispiels einfach getestet werden:

CREATE DATABASE t;
USE t;

CREATE TABLE parent (id INT NOT NULL,
                     PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (id INT NULL, 
                    parent_id INT NULL,
                    FOREIGN KEY (parent_id) REFERENCES parent(id)
) ENGINE=INNODB;


INSERT INTO child (id, parent_id) VALUES (1, NULL);
-- Query OK, 1 row affected (0.01 sec)


INSERT INTO child (id, parent_id) VALUES (2, 1);

-- ERROR 1452 (23000): Cannot add or update a child row: a foreign key 
-- constraint fails (`t/child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY
-- (`parent_id`) REFERENCES `parent` (`id`))

Die erste Einfügung wird bestanden, da wir eine NULL in parent_id Einfügen. Die zweite Einfügung schlägt aufgrund der Fremdschlüsseleinschränkung fehl, da versucht wurde, einen Wert einzufügen, der in der Tabelle parent nicht vorhanden ist.

199
Daniel Vassallo

Ich stellte fest, dass beim Einfügen die Werte der Nullspalte speziell als NULL deklariert werden mussten, da sonst ein Fehler aufgrund einer Einschränkungsverletzung (im Gegensatz zu einer leeren Zeichenfolge) auftreten würde.

25
Backslider

Ja, das wird so funktionieren, wie Sie es erwarten. Leider scheint es mir schwer zu fallen, eine explizite Aussage dazu im MySQL-Handbuch zu finden.

Fremdschlüssel bedeuten, dass der Wert in der anderen Tabelle vorhanden sein muss. NULL bezieht sich auf das Fehlen eines Werts. Wenn Sie also eine Spalte auf NULL setzen, wäre es nicht sinnvoll, diesbezügliche Einschränkungen zu erzwingen.

3
davidtbernal

Das obige funktioniert aber nicht. Beachten Sie die ON DELETE CASCADE

CREATE DATABASE t;
USE t;

CREATE TABLE parent (id INT NOT NULL,
                 PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (id INT NULL, 
                parent_id INT NULL,
                FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE

) ENGINE=INNODB;


INSERT INTO child (id, parent_id) VALUES (1, NULL);
-- Query OK, 1 row affected (0.01 sec)
2
MrFabulous

Eine andere Möglichkeit besteht darin, ein DEFAULT-Element in die andere Tabelle einzufügen. Beispielsweise würde ein Verweis auf uuid = 00000000-0000-0000-0000-000000000000 in der anderen Tabelle keine Aktion anzeigen. Sie müssen auch alle Werte für diese ID auf "neutral" setzen, z. 0, leere Zeichenfolge, null, um Ihre Codelogik nicht zu beeinträchtigen.

1
Wildhammer

Ich bin auch bei diesem Thema geblieben. Aber ich habe es einfach gelöst, indem ich den Fremdschlüssel als unsigned integer Definiert habe. Finden Sie das folgende Beispiel-

CREATE TABLE parent (
   id int(10) UNSIGNED NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (
    id int(10) UNSIGNED NOT NULL,
    parent_id int(10) UNSIGNED DEFAULT NULL,
    FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE
) ENGINE=INNODB;
0
Shams Reza