Verwenden von Fremdschlüsseln und Referenzen für ON DELETE CASCADE in MySQL

7

Ich dachte, dass diese beiden Möglichkeiten zum Erstellen von Fremdschlüsseln gleich sind

CREATE TABLE child1 (
id int(11) not null auto_increment,
parent_id int(11) REFERENCES parent_table(parent_id) ON DELETE CASCADE,
PRIMARY KEY(id)
);

und

CREATE TABLE child2 (
id int(11) not null auto_increment,
parent_id int(11),
PRIMARY KEY(id),
FOREIGN KEY(parent_id) REFERENCES parent_table(parent_id) ON DELETE CASCADE
);

Beim Löschen eines Datensatzes aus der übergeordneten Tabelle wird jedoch der entsprechende Datensatz in der Tabelle child2gelöscht, NICHT jedoch der der Tabelle child1.

Wo irre ich mich REFERENCESist nicht genug und wir müssen schreiben FOREIGN KEY, um zu verwenden ON DELETE CASCADE?

Googlebot
quelle

Antworten:

7

Es ist ein MySQL "Gotcha" . Der erste Weg funktioniert NICHT.

FOREIGN KEYEinschränkungen aus MySQL-Dokumenten :

Wichtig:

... 4 Absätze unten ...

Darüber hinaus erkennt oder unterstützt InnoDB keine „Inline-REFERENZEN-Spezifikationen“ (wie im SQL-Standard definiert), bei denen die Referenzen als Teil der Spaltenspezifikation definiert sind. InnoDB akzeptiert REFERENCES-Klauseln nur, wenn sie als Teil einer separaten FOREIGN KEY-Spezifikation angegeben werden. Bei anderen Speicher-Engines analysiert und ignoriert MySQL Server Fremdschlüsselspezifikationen.

Erstellen der 2 Tabellen (Weg 1):

CREATE TABLE parent_table (
parent_id int(11) not null auto_increment,
PRIMARY KEY(parent_id)
);

CREATE TABLE child1 (
id int(11) not null auto_increment,
parent_id int(11) REFERENCES parent_table(parent_id) ON DELETE CASCADE,
PRIMARY KEY(id)
);

Mal sehen, was ist child1:

> SHOW CREATE TABLE child1 ;

delimiter $$

CREATE TABLE `child1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

Wo ist das FOREIGN KEY? ... Vom Winde verweht (und ohne Vorwarnung)


Das Erstellen der Tabelle child2(Weg 2) funktioniert einwandfrei:

CREATE TABLE child2 (
id int(11) not null auto_increment,
parent_id int(11),
PRIMARY KEY(id),
FOREIGN KEY(parent_id) REFERENCES parent_table(parent_id) ON DELETE CASCADE
);

> SHOW CREATE TABLE child2 ;

delimiter $$

CREATE TABLE `child2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `parent_id` (`parent_id`),
  CONSTRAINT `child2_ibfk_1` 
    FOREIGN KEY (`parent_id`) REFERENCES `parent_table` (`parent_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$
ypercubeᵀᴹ
quelle
3

Interessant. Ich dachte nicht, dass die Syntax für child1überhaupt passen würde, als ich mir das zum ersten Mal ansah.

Ein möglicher Grund child1schlägt fehl, dass Sie keinen Typ explizit angeben. Fremdschlüssel müssen dem Typ entsprechen.

Entsprechende Spalten im Fremdschlüssel und im referenzierten Schlüssel müssen ähnliche interne Datentypen in InnoDB aufweisen, damit sie ohne Typkonvertierung verglichen werden können. Die Größe und das Vorzeichen von Ganzzahltypen müssen identisch sein. Die Länge der Zeichenfolgentypen muss nicht gleich sein. Bei nicht-binären (Zeichen-) Zeichenfolgenspalten müssen Zeichensatz und Sortierung identisch sein. [src]

Ich bezweifle, dass dies der Grund ist, da Ihre DDL minimalistisch ist und die parent_idin der übergeordneten Tabelle wahrscheinlich ähnlich definiert ist.

Wenn Sie jedoch alles andere zu dieser Frage außer Acht lassen, sollten Sie die Syntax child2einfach verwenden, weil sie klarer und wartbarer ist.

Derek Downey
quelle
1
Der fehlende Typ war hier ein Tippfehler. Die Typen sind in parent, child1 und child2 alle gleich. Ja, ich denke auch, dass ich die sichere Syntax von child2 verwenden muss; aber immer noch neugierig zu wissen, was der erste nicht funktioniert;)
Googlebot