MySQL Створення таблиць із зовнішніми ключами, що дають помилку: 150


98

Я намагаюся створити таблицю в MySQL з двома зовнішніми ключами, які посилаються на первинні ключі у двох інших таблицях, але я отримую помилку errno: 150, і вона не створить таблицю.

Ось SQL для всіх 3 таблиць:

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;

Будь-яка допомога буде дуже вдячна.


1
Чи можете ви опублікувати помилку та сказати нам, яка команда (з трьох) викликає помилку?
Дейв

4
Що з тиками навколо auto_increment? Це не вірно. Auto_increment - це ключове слово, а не ідентифікатор.
Білл Карвін

Відповіді:


238

У мене була та сама проблема ALTER TABLE ADD FOREIGN KEY.

Через годину я виявив, що ці умови повинні бути виконані, щоб не отримати помилку 150:

  1. Таблиця батьків має існувати перед тим, як визначити зовнішній ключ для посилання на нього. Ви повинні визначити таблиці в правильному порядку: Спочатку батьківська таблиця, потім дочірня таблиця. Якщо обидві таблиці посилаються один на одного, потрібно створити одну таблицю без обмежень FK, а потім створити другу таблицю, а потім додати обмеження FK до першої таблиці ALTER TABLE.

  2. Обидві таблиці повинні підтримувати зовнішні ключові обмеження, тобто ENGINE=InnoDB. Інші двигуни зберігання мовчки ігнорують визначення іноземних ключів, тому вони не повертають жодних помилок чи попереджень, але обмеження FK не зберігається.

  3. Колонки, що посилаються у батьківській таблиці, повинні бути самими лівими стовпцями ключа. Найкраще, якщо ключем у батьків є PRIMARY KEYабо UNIQUE KEY.

  4. Визначення FK має посилатися на стовпці (ПК) PK у тому ж порядку, що і на визначення PK. Наприклад, якщо FK, REFERENCES Parent(a,b,c)тоді PK батьків не слід визначати в стовпцях по порядку (a,c,b).

  5. Стовпець (и) ПК у батьківській таблиці повинен бути тим самим типом даних, що і стовпці (і) ФК у дочірній таблиці. Наприклад, якщо стовпець ПК у батьківській таблиці UNSIGNED, обов'язково визначте UNSIGNEDвідповідний стовпець у полі Дочірня таблиця.

    Виняток: довжина струн може бути різною. Наприклад, VARCHAR(10)може посилатися VARCHAR(20)або навпаки.

  6. Будь-який стовпець FK типу рядка повинен мати той самий набір символів та порівняння, що і відповідний стовпець PK.

  7. Якщо дані є вже в дочірній таблиці, кожне значення у стовпці (-ках) ФК повинно відповідати значенню в стовпці (ПК) батьківської таблиці. Перевірте це за допомогою запиту на зразок:

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

    Це має повернути нульові (0) невідповідних значень. Очевидно, цей запит є загальним прикладом; ви повинні замінити імена таблиць та назви стовпців.

  8. Ні Таблиця батьків та Дочірня таблиця не можуть бути TEMPORARYтаблицею.

  9. Ні Таблиця батьків та Дочірня таблиця не можуть бути PARTITIONEDтаблицею.

  10. Якщо ви оголосили FK з ON DELETE SET NULLможливістю вибору, то стовпці (і) FK повинні бути нульовими.

  11. Якщо ви оголошуєте ім'я обмеження для іноземного ключа, ім'я обмеження повинно бути унікальним у всій схемі, а не тільки в таблиці, в якій визначено обмеження. Дві таблиці можуть не мати власного обмеження з тим самим іменем.

  12. Якщо в інших таблицях є інші FK, які вказують на те саме поле, для якого ви намагаєтеся створити новий FK, і вони неправильно формуються (тобто, різні зіставлення), спочатку їх потрібно узгодити. Це може бути результатом минулих змін, коли вони SET FOREIGN_KEY_CHECKS = 0;використовувались із суперечливими відносинами, визначеними помилково. Дивіться відповідь @ andrewdotn нижче для інструкцій, як визначити ці проблеми ФК.

Сподіваюся, це допомагає.


4
ще одне, що варто додати: якщо PK батьківської таблиці більше одного поля, порядок полів у FK має бути таким же, як і в PK
Kip

26
Це включає в себе такі речі , як int(11) unsigned NOT NULLпроти int(11) NOT NULL.
Глен Солсберрі

4
ALTER TABLE table_name ENGINE = InnoDB;
TolMera

12
Якщо таблиця визначена ENGINE = MyISAM, вона не генерує errno 150, оскільки вона ігнорує декларації іноземних ключів. Це як сказати, що найкращим способом уникнути неприємностей з автомобільним двигуном є керування човном. :-)
Білл Карвін

2
Крім того, якщо ваше ON DELETEправило CONSTRAINT SET NULLпереконайтеся, що зовнішній ключ може бути дійсно NULL! Я витратив 30 хвилин на читання цієї відповіді знову і знову, переконавшись, що мої таблиці відповідають умовам, але все-таки отримую помилку 150. Потім я помітив, що мій FK - це поле NOT NULL, що означає, що правило неможливо застосувати.
Мартін Столяр

62

Загальне повідомлення "errno 150" MySQL " означає, що обмеження зовнішнього ключа було неправильно сформовано ". Як ви, напевно, вже знаєте, чи читаєте ви цю сторінку, загальне повідомлення про помилку "errno: 150" справді не допомагає. Однак:

Ви можете отримати фактичне повідомлення про помилку, запустивши SHOW ENGINE INNODB STATUS;та шукаючи LATEST FOREIGN KEY ERRORу висновку.

Наприклад, ця спроба створити обмеження зовнішнього ключа:

CREATE TABLE t1
(id INTEGER);

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

не вдається з помилкою Can't create table 'test.t2' (errno: 150). Це не говорить нікому нічого корисного, крім того, що це проблема іноземного ключа. Але біжи, SHOW ENGINE INNODB STATUS;і воно скаже:

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

Це говорить про те, що проблема полягає в тому, що він не може знайти індекс. SHOW INDEX FROM t1показує, що індекси для таблиці взагалі відсутні t1. Виправте це, скажімо, шляхом визначення первинного ключа t1, а обмеження зовнішнього ключа буде створено успішно.


4
SHOW ENGINE INNODB STATUSдопомогло мені негайно визначити проблему, яку я намагався діагностувати майже годину. Дякую.
jatrim

У моєму випадку це вказувало на те, що абсолютно інша таблиця, на якій FK мав те саме поле, на яку я намагався вказати, була непослідовною, і тому не врятувало нове ... припускаючи, що це було використано SET FOREIGN_KEY_CHECKS = 0;під час імпорту / зміни, який був неправильно сформований в той чи інший час. Велика допомога, дякую.
oucil

25

Переконайтеся, що властивості двох полів, які ви намагаєтеся зв’язати з обмеженням, точно однакові.

Часто властивість "без підпису" в стовпці ідентифікатора застане вас.

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

На мій досвід, варто скористатися SHOW CREATE TABLE MySQL у вашій головній таблиці, щоб перевірити, які саме прапорці встановлені у вашому головному стовпці індексу, а потім скопіюйте їх у свій стовпець із зовнішнім ключем. Там можуть бути речі, такі як "неподписані", які не є очевидними.
амбулаторія

10

Який поточний стан вашої бази даних під час запуску цього сценарію? Це зовсім порожньо? Ваш SQL працює добре для мене при створенні бази даних з нуля, але errno 150 зазвичай пов'язаний зі скиданням та відтворенням таблиць, які є частиною іноземного ключа. У мене виникає відчуття, що ти не працюєш зі 100% свіжою та новою базою даних.

Якщо ви помиляєтесь, коли "джерело" вводить ваш файл SQL, вам слід мати змогу запустити команду "ПОКАЗАТИ ДВИГАТЕЛЯ ІННОДБА СТАТУС" у вікні MySQL відразу після команди "Джерело", щоб побачити більш детальну інформацію про помилку.

Ви також можете перевірити ручний запис:

Якщо ви заново створите таблицю, яку випали, вона повинна мати визначення, яке відповідає обмеженням закордонних ключів, що посилаються на неї. Він повинен мати правильні імена та типи стовпців, а також на індексах на посилаються ключі, як зазначено раніше. Якщо їх не влаштовує, MySQL повертає номер помилки 1005 і посилається на помилку 150 у повідомленні про помилку. Якщо MySQL повідомляє про помилку № 1005 з оператора CREATE TABLE, а повідомлення про помилку посилається на помилку 150, створення таблиці не вдалося, оскільки обмеження зовнішнього ключа було неправильно сформовано.

- Посібник з посилання на MySQL 5.1 .


5

Для людей, які переглядають цю тему з тією ж проблемою:

Причин для отримання подібних помилок є маса. Для отримання повного переліку причин та рішень помилок із зовнішніми ключами в MySQL (включаючи ті, що обговорювалися тут), перегляньте це посилання:

Помилки зовнішніх ключів MySQL та Errno 150


4

Для інших, хто знайде цей запис SO через Google: Будьте впевнені, що ви не намагаєтесь виконати дії SET NULL у стовпчику іноземного ключа (бути), визначеному як "NOT NULL". Це викликало великі розчарування, поки я не згадав зробити ЗАВДАННЯ СТАТУТУ ДВИГАТЕЛЯ.


3

Безумовно, це не так, але я вважав цю помилку досить поширеною та непомітною. Цільовою FOREIGN KEYланкою не може бути PRIMARY KEY. Відповідь, яка стане для мене корисною:

ІНОЗЕМНИЙ КЛЮЧ завжди повинен бути вказаний на ПОЧАТКОВИЙ КЛЮЧ справжнє поле іншої таблиці.

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

Як вказує @andrewdotn, найкращий спосіб бачити детальну помилку (SHOW ENGINE INNODB STATUS; ), а не просто код помилки.

Однією з причин може бути те, що індекс вже існує з такою ж назвою, може бути в іншій таблиці. Як правило, я рекомендую префіксувати назву таблиці перед ім'ям індексу, щоб уникнути подібних зіткнень. наприклад, замість idx_userIdвикористання idx_userActionMapping_userId.


3

Будь ласка, переконайтеся, що це спочатку

  1. ви використовуєте таблиці InnoDB.
  2. поле для FOREIGN KEY має той самий тип і довжину (!), що і вихідне поле.

У мене були такі ж неприємності, і я це виправив. Я не підписав INT для одного поля і просто ціле число для іншого поля.


2

Корисна порада, скористайтеся SHOW WARNINGS;після спроби CREATEзапиту, і ви отримаєте помилку, а також більш детальне попередження:

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

Тож у цьому випадку час наново створити свою таблицю!


1

Зазвичай це відбувається при спробі джерела файлу в існуючу базу даних. Спочатку видаліть усі таблиці (або саму БД). А потім вихідний файл з SET foreign_key_checks = 0;на початку та SET foreign_key_checks = 1;в кінці.


1

Я знайшов ще одну причину цього не вдається ... імена таблиць з урахуванням регістру.

Для цього визначення таблиці

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

Це визначення таблиці працює

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

тоді як цей не вдається

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

На те, що він працював у Windows та не працював на Unix, знадобилося мені пару годин. Сподіваюся, що допоможе хтось інший.


1

MySQL Workbench 6.3 для Mac OS.

Проблема: errno 150 в таблиці X при спробі зробити Forward Engineering на схемі БД, 20 з 21 вдалося, 1 - не вдалося. Якщо FK-файли таблиці X були видалені, помилка перейшла до іншої таблиці, яка раніше не працювала.

Змінив усі двигуни таблиць на myISAM, і він працював чудово.

введіть тут опис зображення


0

Також варто перевірити, чи не випадково ви працюєте на неправильній базі даних. Ця помилка виникне, якщо іноземної таблиці не існує. Чому MySQL повинен бути настільки виразним?


0

Переконайтесь, що зовнішні ключі не вказані як унікальні в батьківській. У мене була ця сама проблема, і я вирішив її, визначивши її як не унікальну.


0

У моєму випадку це було пов’язано з тим, що поле, яке було іноземним ключовим полем, мало занадто довгу назву, тобто. foreign key (some_other_table_with_long_name_id). Спробуйте, що коротше. Повідомлення про помилку в цьому випадку трохи оману.

Також, як згадувалося раніше @Jon - визначення полів повинні бути однаковими (стежте за unsignedпідтипом).


0

(Бічні нотатки занадто великі для коментаря)

Немає необхідності AUTO_INCREMENTідентифікатора в таблиці зіставлення; позбутися від нього.

Змініть PRIMARY KEYна (role_id, role_group_id)(у будь-якому порядку). Це зробить доступ швидше.

Оскільки ви, мабуть, хочете зіставити обидва напрямки, також додайте INDEXці два стовпці у зворотному порядку. (Не потрібно цього робити UNIQUE.)

Більше порад: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta



0

виконати нижче рядка перед створенням таблиці: SET FOREIGN_KEY_CHECKS = 0;

Параметр FOREIGN_KEY_CHECKS визначає, чи слід перевіряти обмеження зовнішнього ключа для таблиць InnoDB чи ні.

- Вкажіть, щоб перевірити обмеження зовнішніх ключів (це за замовчуванням)

SET FOREIGN_KEY_CHECKS = 1;

 

- Не перевіряйте обмеження сторонніх ключів

SET FOREIGN_KEY_CHECKS = 0;

Коли використовувати: Тимчасове вимкнення референтних обмежень (встановіть FOREIGN_KEY_CHECKS на 0) корисно, коли вам потрібно заново створити таблиці та завантажити дані в будь-якому порядку батько-дитина


-1

Я зіткнувся з тією ж проблемою, але перевіряю, чи не було у мене батьківської таблиці. Тому я просто редагую міграцію батьків перед дочірньою міграцією. Просто зроби це.


1
це повинен був бути коментарем замість відповіді
hannad rehman
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.