web-dev-qa-db-fra.com

MySQL Créer des tables avec des clés étrangères, ce qui donne errno: 150

J'essaie de créer une table dans MySQL avec deux clés étrangères, qui référencent les clés primaires dans deux autres tables, mais j'obtiens une erreur errno: 150 qui ne créera pas la table.

Voici le code SQL pour les 3 tables:

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;

Toute aide serait grandement appréciée.

93
user176842

J'ai eu le même problème avec ALTER TABLE ADD FOREIGN KEY.

Au bout d’une heure, j’ai trouvé que ces conditions devaient être remplies pour ne pas obtenir l’erreur 150:

  1. La table parent doit exister avant que vous définissiez une clé étrangère pour la référencer. Vous devez définir les tables dans le bon ordre: la table parent en premier, puis la table enfant. Si les deux tables se référencent, vous devez créer une table sans contrainte FK, puis créer la deuxième table, puis ajouter la contrainte FK à la première table avec ALTER TABLE

  2. Les deux tables doivent toutes deux prendre en charge les contraintes de clé étrangère, à savoir ENGINE=InnoDB. D'autres moteurs de stockage ignorent en silence les définitions de clé étrangère. Par conséquent, ils ne renvoient ni erreur ni avertissement, mais la contrainte FK n'est pas enregistrée.

  3. Les colonnes référencées dans la table parent doivent être les colonnes les plus à gauche d'une clé. Meilleur si la clé dans le parent est PRIMARY KEY ou UNIQUE KEY.

  4. La définition FK doit référencer la ou les colonnes PK dans le même ordre que la définition PK. Par exemple, si FK REFERENCES Parent(a,b,c), la PK du parent ne doit pas être définie sur les colonnes dans l'ordre (a,c,b).

  5. La ou les colonnes PK de la table parent doivent être du même type de données que les colonnes FK de la table enfant. Par exemple, si une colonne PK de la table Parent est UNSIGNED, veillez à définir UNSIGNED pour la colonne correspondante dans le champ de la table Child. 

    Exception: la longueur des chaînes peut être différente. Par exemple, VARCHAR(10) peut faire référence à VARCHAR(20) ou inversement.

  6. Toute colonne FK de type chaîne doit avoir le même jeu de caractères et le même classement que la ou les colonnes PK correspondantes.

  7. S'il existe déjà des données dans la table Child, chaque valeur de la ou des colonnes FK doit correspondre à une valeur de la ou des colonnes PK de la table parent. Vérifiez ceci avec une requête comme:

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

    Cela doit renvoyer zéro (0) valeur sans correspondance. De toute évidence, cette requête est un exemple générique; vous devez substituer vos noms de table et vos noms de colonne.

  8. Ni la table parent ni la table enfant ne peuvent être une table TEMPORARY.

  9. Ni la table parent ni la table enfant ne peuvent être une table PARTITIONED.

  10. Si vous déclarez un FK avec l'option ON DELETE SET NULL, la ou les colonnes FK doivent avoir la valeur NULL.

  11. Si vous déclarez un nom de contrainte pour une clé étrangère, le nom de contrainte doit être unique dans l'ensemble du schéma, et pas seulement dans la table dans laquelle la contrainte est définie. Deux tables peuvent ne pas avoir leur propre contrainte avec le même nom.

J'espère que cela t'aides.

230
marv-el

Le message «errno 150» générique de MySQL « signifie qu'une contrainte de clé étrangère n'a pas été correctement formée .» Comme vous le savez probablement déjà si vous lisez cette page, le message d'erreur générique «errno: 150» est vraiment inutile. Toutefois:

Vous pouvez obtenir le message d'erreur réel en exécutant SHOW ENGINE INNODB STATUS;, puis en recherchant LATEST FOREIGN KEY ERROR dans le résultat.

Par exemple, cette tentative pour créer une contrainte de clé étrangère:

CREATE TABLE t1
(id INTEGER);

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

échoue avec l'erreur Can't create table 'test.t2' (errno: 150). Cela ne dit à personne rien d’utile d’autre que d’être un problème de clé étrangère. Mais lancez SHOW ENGINE INNODB STATUS; et vous verrez:

------------------------
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.

Le problème est qu’il ne trouve pas d’index. SHOW INDEX FROM t1 montre qu’il n’ya pas d’index pour la table t1. Supprimez cela en définissant une clé primaire sur t1, par exemple, et la contrainte de clé étrangère sera créée avec succès.

60
andrewdotn

Assurez-vous que les propriétés des deux champs que vous essayez de lier avec une contrainte sont exactement les mêmes.

Souvent, la propriété 'unsigned' sur une colonne d'ID va vous attirer.

ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
25
Jon Winstanley

Quel est l'état actuel de votre base de données lorsque vous exécutez ce script? Est-ce complètement vide? Votre code SQL fonctionne bien pour moi lorsque je crée une base de données à partir de rien, mais errno 150 concerne généralement la suppression et la recréation de tables faisant partie d'une clé étrangère. J'ai l'impression que vous ne travaillez pas avec une base de données 100% fraîche et nouvelle.

Si vous vous trompez lors de la "source" de votre fichier SQL, vous devriez pouvoir exécuter la commande "SHOW ENGINE INNODB STATUS" à partir de l'invite MySQL immédiatement après la commande "source" pour afficher des informations d'erreur plus détaillées.

Vous voudrez peut-être aussi vérifier la saisie manuelle:

Si vous recréez une table qui a été supprimée, sa définition doit être conforme aux contraintes de la clé étrangère la référant. Il doit avoir les bons noms et types de colonnes et des index sur les clés référencées, comme indiqué précédemment. Si ceux-ci ne sont pas satisfaits, MySQL renvoie le numéro d'erreur 1005 et renvoie à l'erreur 150 dans le message d'erreur. Si MySQL signale un numéro d'erreur 1005 à partir d'une instruction CREATE TABLE et que le message d'erreur fait référence à l'erreur 150, la création de la table a échoué car une contrainte de clé étrangère n'était pas correctement formée.

- Manuel de référence MySQL 5.1 .

10
Brent Writes Code

Pour les personnes qui consultent ce fil avec le même problème:

Il y a beaucoup de raisons pour obtenir des erreurs comme celle-ci. Pour une liste assez complète des causes et des solutions des erreurs de clé étrangère dans MySQL (y compris celles décrites ici), consultez ce lien:

Erreurs de clé étrangère MySQL et Errno 150

5
juacala

Pour les autres utilisateurs qui trouvent cette entrée SO via Google: Assurez-vous de ne pas tenter d'effectuer d'action SET NULL sur une colonne de clé étrangère (future) définie comme "NOT NULL". Cela a provoqué une grande frustration jusqu'à ce que je me souvienne de faire un état de vérification de moteur INNODB.

4
Eric Lawler

Comme l'a souligné @andrewdotn, le meilleur moyen consiste à afficher l'erreur détaillée (SHOW ENGINE INNODB STATUS;) au lieu d'un code d'erreur.

Une des raisons pourrait être qu'un index existe déjà avec le même nom, peut être dans une autre table. En règle générale, je recommande de préfixer le nom de la table avant le nom de l'index afin d'éviter de telles collisions. par exemple. au lieu de idx_userId, utilisez idx_userActionMapping_userId.

3
MuchMore

Ce n’est certainement pas le cas, mais j’ai trouvé cette erreur assez commune et non évidente. La cible d'un FOREIGN KEY pourrait ne pas être PRIMARY KEY. La réponse qui m'est utile est:

Une clé étrangère doit toujours être dirigée vers un champ vrai de clé primaire d'une autre table.

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));
3
I159

Conseil utile, utilisez SHOW WARNINGS; après avoir essayé votre requête CREATE et vous recevrez le message d'erreur ainsi que l'avertissement plus détaillé:

    ---------------------------------------------------------------------------------------------------------+
| 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)                                                                                                                                                                           |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+

Donc dans ce cas, il est temps de recréer ma table!

2
sturrockad

S'il vous plaît assurez-vous d'abord que

  1. vous utilisez des tables InnoDB.
  2. le champ for FOREIGN KEY a le même type et la même longueur (!) que le champ source.

J'ai eu le même problème et je l'ai corrigé. J'avais non signé INT pour un champ et juste entier pour un autre champ.

2
Juljan

Cela se produit généralement lorsque vous essayez de créer un fichier dans une base de données existante . Commencez par supprimer toutes les tables (ou le DB lui-même). Et le fichier source avec SET foreign_key_checks = 0; au début et SET foreign_key_checks = 1; à la fin.

1
wholenewstrain

J'ai trouvé une autre raison pour laquelle cela échoue ... noms de table sensibles à la casse.

Pour cette définition de table

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

Cette définition de table fonctionne

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

alors que celui-ci échoue

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

Le fait que cela fonctionne sous Windows et échoue sous Unix m'a pris quelques heures à comprendre. J'espère que ça aide quelqu'un d'autre.

1
Tim

MySQL Workbench 6.3 pour Mac OS. 

Problème: erreur 150 dans le tableau X lors d’une tentative d’ingénierie avancée sur un diagramme de base de données, 20 sur 21 ont réussi, 1 a échoué. Si les FK de la table X étaient supprimés, l'erreur était déplacée vers une autre table qui n'échouait pas auparavant. 

Changé le moteur de toutes les tables en myISAM et cela fonctionnait très bien. 

 enter image description here

1
Eduardo Chongkan

Assurez-vous que les clés étrangères ne sont pas répertoriées comme uniques dans le parent. J'ai eu ce même problème et je l'ai résolu en le démarquant comme n'étant pas unique.

0
Raza

Cela vaut également la peine de vérifier que vous n’utilisez pas accidentellement la mauvaise base de données. Cette erreur se produira si la table étrangère n'existe pas. Pourquoi MySQL doit-il être si crypté?

0
SystemParadox

Lorsque la contrainte de clé étrangère est basée sur le type varchar, en plus de la liste fournie par marv-el la colonne target doit avoir une contrainte unique.

0
Ralph

(Notes latérales trop grandes pour un commentaire)

Un identifiant AUTO_INCREMENT n'est pas nécessaire dans une table de mappage; s'en débarrasser.

Changez le PRIMARY KEY en (role_id, role_group_id) (dans l'un ou l'autre ordre). Cela rendra les accès plus rapides.

Comme vous souhaitez probablement mapper les deux directions, ajoutez également une INDEX avec ces deux colonnes dans l'ordre inverse. (Il n'est pas nécessaire de le rendre UNIQUE.)

Autres conseils: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta

0
Rick James

Dans mon cas, cela était dû au fait que le champ qui était une clé étrangère avait un nom trop long, c'est-à-dire. foreign key (some_other_table_with_long_name_id). Essayez ça plus court. Le message d'erreur est un peu trompeur dans ce cas. 

En outre, comme @Jon l’a mentionné précédemment, les définitions de champ doivent être identiques (surveillez le sous-type unsigned).

0
Kangur