MySQL Erstellen von Tabellen mit Fremdschlüsseln mit der Angabe errno: 150

98

Ich versuche, eine Tabelle in MySQL mit zwei Fremdschlüsseln zu erstellen, die auf die Primärschlüssel in zwei anderen Tabellen verweisen, erhalte jedoch den Fehler errno: 150, und die Tabelle wird nicht erstellt.

Hier ist die SQL für alle 3 Tabellen:

CREATE TABLE role_groups (
  `role_group_id` int(11) NOT NULL `AUTO_INCREMENT`,
  `name` varchar(20),
  `description` varchar(200),
  PRIMARY KEY (`role_group_id`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `roles` (
  `role_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50),
  `description` varchar(200),
  PRIMARY KEY (`role_id`)
) ENGINE=InnoDB;

create table role_map (
  `role_map_id` int not null `auto_increment`,
  `role_id` int not null,
  `role_group_id` int not null,
  primary key(`role_map_id`),
  foreign key(`role_id`) references roles(`role_id`),
  foreign key(`role_group_id`) references role_groups(`role_group_id`)
) engine=InnoDB;

Jede Hilfe wäre sehr dankbar.

Bill Karwin
quelle
1
Könnten Sie die Fehlerausgabe posten und uns mitteilen, welcher Befehl (von den drei) den Fehler verursacht?
Dave
4
Was ist mit den Back-Ticks auto_increment? Das ist nicht gültig. Auto_increment ist ein Schlüsselwort, kein Bezeichner.
Bill Karwin

Antworten:

237

Ich hatte das gleiche Problem mit ALTER TABLE ADD FOREIGN KEY.

Nach einer Stunde stellte ich fest, dass diese Bedingungen erfüllt sein müssen, um den Fehler 150 nicht zu erhalten:

  1. Die übergeordnete Tabelle muss vorhanden sein, bevor Sie einen Fremdschlüssel definieren, um darauf zu verweisen. Sie müssen die Tabellen in der richtigen Reihenfolge definieren: Zuerst die übergeordnete Tabelle, dann die untergeordnete Tabelle. Wenn beide Tabellen aufeinander verweisen, müssen Sie eine Tabelle ohne FK-Einschränkungen erstellen, dann die zweite Tabelle erstellen und dann die FK-Einschränkung zur ersten Tabelle mit hinzufügen ALTER TABLE.

  2. Die beiden Tabellen müssen beide Fremdschlüsseleinschränkungen unterstützen, d ENGINE=InnoDB. H. Andere Speicher-Engines ignorieren Fremdschlüsseldefinitionen stillschweigend, sodass sie keinen Fehler oder keine Warnung zurückgeben, aber die FK-Einschränkung wird nicht gespeichert.

  3. Die Spalten, auf die in der übergeordneten Tabelle verwiesen wird, müssen die Spalten ganz links eines Schlüssels sein. Am besten, wenn der Schlüssel im Elternteil PRIMARY KEYoder ist UNIQUE KEY.

  4. Die FK-Definition muss auf die PK-Spalte (n) in derselben Reihenfolge wie die PK-Definition verweisen. Wenn beispielsweise die FK, REFERENCES Parent(a,b,c)darf die PK des Elternteils nicht in der angegebenen Reihenfolge für Spalten definiert werden (a,c,b).

  5. Die PK-Spalte (n) in der übergeordneten Tabelle müssen denselben Datentyp haben wie die FK-Spalte (n) in der untergeordneten Tabelle. Wenn sich beispielsweise eine PK-Spalte in der übergeordneten Tabelle befindet UNSIGNED, müssen Sie UNSIGNEDdie entsprechende Spalte im Feld Untergeordnete Tabelle definieren.

    Ausnahme: Die Länge der Zeichenfolgen kann unterschiedlich sein. VARCHAR(10)Kann zum Beispiel referenzieren VARCHAR(20)oder umgekehrt.

  6. Alle FK-Spalten vom Typ "Zeichenfolge" müssen denselben Zeichensatz und dieselbe Sortierung wie die entsprechenden PK-Spalten haben.

  7. Wenn die untergeordnete Tabelle bereits Daten enthält, muss jeder Wert in den FK-Spalten mit einem Wert in den PK-Spalten der übergeordneten Tabelle übereinstimmen. Überprüfen Sie dies mit einer Abfrage wie:

    SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK 
    WHERE Parent.PK IS NULL;

    Dies muss null (0) nicht übereinstimmende Werte zurückgeben. Offensichtlich ist diese Abfrage ein allgemeines Beispiel. Sie müssen Ihre Tabellennamen und Spaltennamen ersetzen.

  8. Weder die übergeordnete Tabelle noch die untergeordnete Tabelle können eine TEMPORARYTabelle sein.

  9. Weder die übergeordnete Tabelle noch die untergeordnete Tabelle können eine PARTITIONEDTabelle sein.

  10. Wenn Sie eine FK mit der ON DELETE SET NULLOption deklarieren , müssen die FK-Spalten nullwertfähig sein.

  11. Wenn Sie einen Einschränkungsnamen für einen Fremdschlüssel deklarieren, muss der Einschränkungsname im gesamten Schema eindeutig sein, nicht nur in der Tabelle, in der die Einschränkung definiert ist. Zwei Tabellen haben möglicherweise keine eigene Einschränkung mit demselben Namen.

  12. Wenn andere FKs in anderen Tabellen auf dasselbe Feld verweisen, für das Sie die neue FK erstellen möchten, und diese fehlerhaft sind (dh eine andere Sortierung aufweisen), müssen sie zuerst konsistent gemacht werden. Dies kann auf frühere Änderungen zurückzuführen sein, bei denen SET FOREIGN_KEY_CHECKS = 0;eine versehentlich definierte inkonsistente Beziehung verwendet wurde. In der Antwort von @ andrewdotn unten finden Sie Anweisungen zum Identifizieren dieser Problem-FKs.

Hoffe das hilft.

Wunder
quelle
4
Eine weitere Sache, die hinzugefügt werden sollte: Wenn die PK der übergeordneten Tabelle mehr als ein Feld enthält, muss die Reihenfolge der Felder in der FK mit der Reihenfolge in der PK
Kip
26
Dazu gehören Dinge wie int(11) unsigned NOT NULLvs int(11) NOT NULL.
Glen Solsberry
4
ALTER TABLE Tabellenname ENGINE = InnoDB;
TolMera
12
Wenn die Tabelle ENGINE = MyISAM definiert ist, wird errno 150 nicht generiert, da Fremdschlüsseldeklarationen ignoriert werden . Es ist, als würde man sagen, dass der beste Weg, um Probleme mit Ihrem Automotor zu vermeiden, darin besteht, ein Boot zu fahren. :-)
Bill Karwin
2
Wenn die ON DELETERegel Ihres CONSTRAINT lautet, SET NULLstellen Sie sicher, dass der Fremdschlüssel tatsächlich NULL sein kann! Ich verbrachte 30 Minuten damit, diese Antwort immer wieder zu lesen, um sicherzustellen, dass meine Tabellen die Bedingungen erfüllten, aber immer noch Fehler 150 erhielten. Dann bemerkte ich, dass mein FK ein NICHT NULL-Feld war, was bedeutete, dass die Regel nicht angewendet werden konnte.
Martin Joiner
62

Die generische Meldung "errno 150" von MySQL bedeutet, dass eine Fremdschlüsseleinschränkung nicht korrekt gebildet wurde . Wie Sie wahrscheinlich bereits wissen, wenn Sie diese Seite lesen, ist die generische Fehlermeldung "errno: 150" nicht hilfreich. Jedoch:

Sie können die eigentliche Fehlermeldung erhalten, indem Sie ausführen SHOW ENGINE INNODB STATUS;und dann LATEST FOREIGN KEY ERRORin der Ausgabe suchen .

Beispiel für diesen Versuch, eine Fremdschlüsseleinschränkung zu erstellen:

CREATE TABLE t1
(id INTEGER);

CREATE TABLE t2
(t1_id INTEGER,
 CONSTRAINT FOREIGN KEY (t1_id) REFERENCES t1 (id));

schlägt mit dem Fehler fehl Can't create table 'test.t2' (errno: 150). Das sagt niemandem etwas Nützliches, außer dass es ein Fremdschlüsselproblem ist. Aber renn SHOW ENGINE INNODB STATUS;und es wird sagen:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
130811 23:36:38 Error in foreign key constraint of table test/t2:
FOREIGN KEY (t1_id) REFERENCES t1 (id)):
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.

Das Problem besteht darin, dass kein Index gefunden werden kann. SHOW INDEX FROM t1zeigt, dass es für die Tabelle überhaupt keine Indizes gibt t1. Korrigieren Sie dies, indem Sie beispielsweise einen Primärschlüssel definieren t1, und die Fremdschlüsseleinschränkung wird erfolgreich erstellt.

andrewdotn
quelle
4
SHOW ENGINE INNODB STATUShalf mir sofort, ein Problem zu identifizieren, das ich seit fast einer Stunde zu diagnostizieren versuchte. Vielen Dank.
Jatrim
In meinem Fall deutete dies darauf hin, dass eine völlig andere Tabelle, auf die FK dasselbe Feld hatte, auf das ich zeigen wollte, inkonsistent war und daher die neue nicht speichern würde ... vorausgesetzt, dies wurde SET FOREIGN_KEY_CHECKS = 0;während eines Imports / einer Änderung verwendet, die fehlerhaft war irgendeinmal. Große Hilfe, danke.
Oucil
25

Stellen Sie sicher, dass die Eigenschaften der beiden Felder, die Sie mit einer Einschränkung verknüpfen möchten, genau gleich sind.

Häufig werden Sie von der Eigenschaft "ohne Vorzeichen" in einer ID-Spalte aufgefangen.

ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
Jon Winstanley
quelle
Nach meiner Erfahrung lohnt es sich, die SHOW CREATE TABLE von MySQL in Ihrer Haupttabelle zu verwenden, um genau zu überprüfen, welche Flags für Ihre Hauptindexspalte gesetzt sind, und sie dann in Ihre Fremdschlüsselspalte zu kopieren. Möglicherweise gibt es dort Dinge wie "nicht signiert", die nicht offensichtlich sind.
Ambulare
10

Wie ist der aktuelle Status Ihrer Datenbank, wenn Sie dieses Skript ausführen? Ist es komplett leer? Ihr SQL läuft für mich einwandfrei, wenn Sie eine Datenbank von Grund auf neu erstellen, aber errno 150 hat normalerweise mit dem Löschen und Neuerstellen von Tabellen zu tun, die Teil eines Fremdschlüssels sind. Ich habe das Gefühl, dass Sie nicht mit einer 100% frischen und neuen Datenbank arbeiten.

Wenn Sie beim "Quellieren" Ihrer SQL-Datei einen Fehler machen, sollten Sie in der Lage sein, den Befehl "SHOW ENGINE INNODB STATUS" unmittelbar nach dem Befehl "source" an der MySQL-Eingabeaufforderung auszuführen, um detailliertere Fehlerinformationen anzuzeigen.

Vielleicht möchten Sie auch den manuellen Eintrag lesen:

Wenn Sie eine Tabelle neu erstellen, die gelöscht wurde, muss sie eine Definition haben, die den Fremdschlüsseleinschränkungen entspricht, auf die sie verweist. Es muss die richtigen Spaltennamen und -typen und Indizes für die referenzierten Schlüssel enthalten, wie bereits erwähnt. Wenn diese nicht erfüllt sind, gibt MySQL die Fehlernummer 1005 zurück und verweist in der Fehlermeldung auf Fehler 150. Wenn MySQL eine Fehlernummer 1005 aus einer CREATE TABLE-Anweisung meldet und die Fehlermeldung auf Fehler 150 verweist, ist die Tabellenerstellung fehlgeschlagen, da eine Fremdschlüsseleinschränkung nicht korrekt gebildet wurde.

- MySQL 5.1 Referenzhandbuch .

Brent schreibt Code
quelle
5

Für Personen, die diesen Thread mit demselben Problem anzeigen:

Es gibt viele Gründe für solche Fehler. Eine ziemlich vollständige Liste der Ursachen und Lösungen von Fremdschlüsselfehlern in MySQL (einschließlich der hier beschriebenen) finden Sie unter folgendem Link:

MySQL-Fremdschlüsselfehler und Errno 150

Juacala
quelle
4

Für andere, die diesen SO-Eintrag über Google finden: Stellen Sie sicher, dass Sie nicht versuchen, eine SET NULL-Aktion für eine Fremdschlüsselspalte auszuführen, die als "NOT NULL" definiert ist. Das verursachte große Frustration, bis ich mich daran erinnerte, einen CHECK ENGINE INNODB STATUS durchzuführen.

Eric L.
quelle
3

Auf jeden Fall ist das nicht der Fall, aber ich fand diesen Fehler ziemlich häufig und nicht offensichtlich. Das Ziel eines FOREIGN KEYkönnte nicht sein PRIMARY KEY. Die Antwort, die für mich nützlich wird, lautet:

Ein FOREIGN KEY muss immer auf ein PRIMARY KEY true-Feld einer anderen Tabelle zeigen.

CREATE TABLE users(
   id INT AUTO_INCREMENT PRIMARY KEY,
   username VARCHAR(40));

CREATE TABLE userroles(
   id INT AUTO_INCREMENT PRIMARY KEY,
   user_id INT NOT NULL,
   FOREIGN KEY(user_id) REFERENCES users(id));
I159
quelle
3

Wie von @andrewdotn gezeigt, ist es am besten, den detaillierten Fehler ( SHOW ENGINE INNODB STATUS;) anstelle nur eines Fehlercodes anzuzeigen .

Einer der Gründe könnte sein, dass ein Index mit demselben Namen bereits vorhanden ist und sich möglicherweise in einer anderen Tabelle befindet. In der Praxis empfehle ich, den Tabellennamen vor dem Indexnamen zu setzen, um solche Kollisionen zu vermeiden. zB statt zu idx_userIdbenutzen idx_userActionMapping_userId.

Viel mehr
quelle
3

Bitte stellen Sie zunächst sicher, dass

  1. Sie verwenden InnoDB-Tabellen.
  2. Das Feld für FOREIGN KEY hat den gleichen Typ und die gleiche Länge (!) wie das Quellfeld.

Ich hatte das gleiche Problem und habe es behoben. Ich hatte INT für ein Feld ohne Vorzeichen und für ein anderes Feld nur eine Ganzzahl.

Juljan
quelle
2

Hilfreicher Tipp, verwenden Sie ihn SHOW WARNINGS;nach dem Versuch Ihrer CREATEAbfrage und Sie erhalten den Fehler sowie die detailliertere Warnung:

    ---------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                 |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+
| Warning |  150 | Create table 'fakeDatabase/exampleTable' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
|
| Error   | 1005 | Can't create table 'exampleTable' (errno:150)                                                                                                                                                                           |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+

In diesem Fall ist es also Zeit, meine Tabelle neu zu erstellen!

Sturrockad
quelle
1

Dies geschieht normalerweise, wenn Sie versuchen, eine Quelldatei in eine vorhandene Datenbank zu übertragen. Löschen Sie zuerst alle Tabellen (oder die Datenbank selbst). Und dann Quelldatei mit SET foreign_key_checks = 0;am Anfang und SET foreign_key_checks = 1;am Ende.

Ganzheitlichkeit
quelle
1

Ich habe einen anderen Grund gefunden, warum dies fehlschlägt ... Groß- und Kleinschreibung von Tabellennamen.

Für diese Tabellendefinition

CREATE TABLE user (
  userId int PRIMARY KEY AUTO_INCREMENT,
  username varchar(30) NOT NULL
) ENGINE=InnoDB;

Diese Tabellendefinition funktioniert

CREATE TABLE product (
  id int PRIMARY KEY AUTO_INCREMENT,
  userId int,
  FOREIGN KEY fkProductUser1(userId) REFERENCES **u**ser(userId)
) ENGINE=InnoDB;

während dieser scheitert

CREATE TABLE product (
  id int PRIMARY KEY AUTO_INCREMENT,
  userId int,
  FOREIGN KEY fkProductUser1(userId) REFERENCES User(userId)
) ENGINE=InnoDB;

Die Tatsache, dass es unter Windows funktionierte und unter Unix fehlschlug, dauerte ein paar Stunden, um es herauszufinden. Hoffe das hilft jemand anderem.

Tim
quelle
1

MySQL Workbench 6.3 für Mac OS.

Problem: Fehler Nr. 150 in Tabelle X beim Versuch, Forward Engineering in einem DB-Diagramm durchzuführen. 20 von 21 waren erfolgreich, 1 ist fehlgeschlagen. Wenn FKs in Tabelle X gelöscht wurden, wurde der Fehler in eine andere Tabelle verschoben, die zuvor nicht fehlgeschlagen war.

Alle Tabellen-Engine wurde auf myISAM geändert und es hat einwandfrei funktioniert.

Geben Sie hier die Bildbeschreibung ein

Eduardo Chongkan
quelle
0

Es lohnt sich auch zu überprüfen, ob Sie nicht versehentlich mit der falschen Datenbank arbeiten. Dieser Fehler tritt auf, wenn die Fremdtabelle nicht vorhanden ist. Warum muss MySQL so kryptisch sein?

SystemParadox
quelle
0

Stellen Sie sicher, dass die Fremdschlüssel im übergeordneten Element nicht als eindeutig aufgeführt sind. Ich hatte das gleiche Problem und löste es, indem ich es als nicht eindeutig abgrenzte.

Raza
quelle
0

In meinem Fall lag es an der Tatsache, dass das Feld, das ein Fremdschlüsselfeld war, einen zu langen Namen hatte, d. H. foreign key (some_other_table_with_long_name_id). Versuchen Sie etwas kürzer. Die Fehlermeldung ist in diesem Fall etwas irreführend.

Wie bereits bei @Jon erwähnt, müssen die Felddefinitionen identisch sein (achten Sie auf den unsignedSubtyp).

Kangur
quelle
0

(Randnotizen zu groß für einen Kommentar)

AUTO_INCREMENTIn einer Zuordnungstabelle ist keine ID erforderlich . werde es los.

Ändern Sie das PRIMARY KEYin (role_id, role_group_id)(in beliebiger Reihenfolge). Dies beschleunigt den Zugriff.

Da Sie wahrscheinlich beide Richtungen zuordnen möchten, fügen Sie auch eine INDEXmit diesen beiden Spalten in umgekehrter Reihenfolge hinzu. (Es ist nicht nötig, es zu machen UNIQUE.)

Weitere Tipps: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta

Rick James
quelle
0

Wenn die Fremdschlüsseleinschränkung auf dem varcharTyp basiert , muss zusätzlich zu der vonmarv-el der Zielspalte bereitgestellten Liste eine eindeutige Einschränkung vorhanden sein.

Ralph
quelle
0

Führen Sie die folgende Zeile aus, bevor Sie eine Tabelle erstellen: SET FOREIGN_KEY_CHECKS = 0;

Die Option FOREIGN_KEY_CHECKS gibt an, ob Fremdschlüsseleinschränkungen für InnoDB-Tabellen überprüft werden sollen.

- Geben Sie an, dass Fremdschlüsseleinschränkungen überprüft werden sollen (dies ist die Standardeinstellung).

SET FOREIGN_KEY_CHECKS = 1;

 

- Überprüfen Sie keine Fremdschlüsseleinschränkungen

SET FOREIGN_KEY_CHECKS = 0;

Verwendungszweck: Das vorübergehende Deaktivieren von referenziellen Einschränkungen (FOREIGN_KEY_CHECKS auf 0 setzen) ist nützlich, wenn Sie die Tabellen neu erstellen und Daten in einer beliebigen Eltern-Kind-Reihenfolge laden müssen

user11949964
quelle
-1

Ich habe das gleiche Problem festgestellt, aber ich überprüfe, ob ich die übergeordnete Tabelle nicht hatte. Also bearbeite ich einfach die übergeordnete Migration vor der untergeordneten Migration. Mach es einfach.

韩向飞
quelle
1
Dies sollte ein Kommentar statt einer Antwort gewesen sein
Hannad Rehman