MySQL Создание таблиц с внешними ключами, дающих errno: 150

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

Вот SQL для всех трех таблиц:

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

У меня была такая же проблема с ALTER TABLE ADD FOREIGN KEY.

Через час я обнаружил, что эти условия должны быть выполнены, чтобы не получить ошибку 150:

  1. Родительская таблица должна существовать до того, как вы определите внешний ключ для ссылки на него. Вы должны определить таблицы в правильном порядке: сначала родительская таблица, затем дочерняя таблица. Если обе таблицы ссылаются друг на друга, необходимо создать одну таблицу без ограничений FK, затем создать вторую таблицу, а затем добавить ограничение FK в первую таблицу с помощью ALTER TABLE.

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

  3. Столбцы, на которые есть ссылки в родительской таблице, должны быть крайними левыми столбцами ключа. Лучше всего, если ключ в Parent - PRIMARY KEY или UNIQUE KEY.

  4. Определение FK должно ссылаться на столбцы PK в том же порядке, что и определение PK. Например, если FK REFERENCES Parent(a,b,c) то родительский PK не должен быть определен в столбцах в порядке (a,c,b).

  5. Столбцы PK в родительской таблице должны иметь тот же тип данных, что и столбцы FK в дочерней таблице. Например, если для столбца PK в родительской таблице UNSIGNED, обязательно укажите UNSIGNED для соответствующего столбца в поле UNSIGNED таблицы.

    Исключение: длина строк может быть разной. Например, VARCHAR(10) может ссылаться на VARCHAR(20) или наоборот.

  6. Любые столбцы столбца типа FK должны иметь тот же набор символов и сопоставление, что и соответствующие столбцы PK.

  7. Если в дочерней таблице уже есть данные, каждое значение в столбцах столбцов FK должно соответствовать значению в столбцах столбцов PK родительской таблицы. Проверьте это с помощью запроса:

    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 должны иметь значение NULL.

  11. Если вы объявляете имя ограничения для внешнего ключа, имя ограничения должно быть уникальным во всей схеме, а не только в таблице, в которой определено ограничение. Две таблицы могут не иметь собственных ограничений с одинаковыми именами.

  12. Если в других таблицах есть другие FK, указывающие на то же поле, для которого вы пытаетесь создать новый FK, и они имеют неправильный формат (т.е. Различное сопоставление), сначала их необходимо согласовать. Это может быть результатом прошлых изменений, где SET FOREIGN_KEY_CHECKS = 0; был использован с противоречивыми отношениями, определенными по ошибке. См. @Andrewdotn ответ ниже для получения инструкций о том, как определить эти проблемы FK.

Надеюсь это поможет.

Ответ 2

MySQL generic "errno 150" message " означает, что ограничение внешнего ключа было неправильно сформировано." Как вы, наверное, уже знаете, читаете ли вы эту страницу, общее сообщение об ошибке "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, и ограничение внешнего ключа будет создано успешно.

Ответ 3

Убедитесь, что свойства двух полей, которые вы пытаетесь связать с ограничением, точно совпадают.

Часто свойство "unsigned" в столбце идентификатора выведет вас.

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

Ответ 4

Какое текущее состояние вашей базы данных при запуске этого script? Он полностью пуст? Ваш SQL работает отлично для меня при создании базы данных с нуля, но errno 150 обычно имеет дело с удалением и воссозданием таблиц, которые являются частью внешнего ключа. Я чувствую, что вы не работаете со 100% новой и новой базой данных.

Если вы ошибаетесь, когда "источник" - ваш файл SQL, вы можете запустить команду "SHOW ENGINE INNODB STATUS" из приглашения MySQL сразу после команды "source", чтобы увидеть более подробную информацию об ошибке.

Вы также можете проверить ввод вручную:

Если вы воссоздали таблицу, которая была удалена, она должна иметь определение, соответствующее ограничениям внешнего ключа, ссылающимся на него. Он должен иметь правильные имена и типы столбцов, и он должен иметь индексы на ссылочных ключах, как указано ранее. Если они не выполняются, MySQL возвращает номер ошибки 1005 и ссылается на ошибку 150 в сообщении об ошибке. Если MySQL сообщает номер ошибки 1005 из инструкции CREATE TABLE, а сообщение об ошибке относится к ошибке 150, создание таблицы завершилось неудачно, потому что ограничение внешнего ключа было неправильно сформировано.

- Справочное руководство MySQL 5.1.

Ответ 5

Для тех, кто просматривает эту тему с той же проблемой:

Есть много причин для получения таких ошибок. Для получения достаточно полного списка причин и решений ошибок внешнего ключа в MySQL (включая те, которые обсуждаются здесь), посмотрите эту ссылку:

Ошибки внешнего ключа MySQL и Errno 150

Ответ 6

Для других, которые находят эту запись SO через Google: убедитесь, что вы не пытаетесь выполнить действие SET NULL на столбце внешнего ключа, который будет указан как "NOT NULL". Это вызвало сильное разочарование, пока я не вспомнил о том, чтобы сделать СТАНДАРТНЫЙ ИНСТРУМЕНТ ДВИГАТЕЛЯ.

Ответ 7

Конечно, это не тот случай, но я нашел эту ошибку довольно распространенной и неочевидной. Целью FOREIGN KEY может быть не PRIMARY 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));

Ответ 8

Как указано @andrewdotn, лучший способ - увидеть подробную ошибку (SHOW ENGINE INNODB STATUS;) вместо кода ошибки.

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

Ответ 9

Сначала убедитесь, что

  • вы используете таблицы InnoDB. Поле
  • для FOREIGN KEY имеет тип и длину (!) в качестве исходного поля.

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

Ответ 10

Полезный совет, используйте 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)                                                                                                                                                                           |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+

Итак, в этом случае, время для воссоздания моей таблицы!

Ответ 11

Обычно это происходит, когда вы пытаетесь загрузить исходный файл в существующую базу данных. Сначала отбросьте все таблицы (или сам БД). И затем исходный файл с SET foreign_key_checks = 0; в начале и SET foreign_key_checks = 1; в конце.

Ответ 12

Я нашел другую причину, по которой это не удается... имена таблиц, чувствительных к регистру.

Для определения этой таблицы

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, занял у меня пару часов, чтобы понять. Надеюсь, что это поможет кому-то другому.

Ответ 13

MySQL Workbench 6.3 для Mac OS.

Проблема: errno 150 в таблице X при попытке сделать Forward Engineering на диаграмме DB, 20 из 21 удалось, 1 не удалось. Если FKs на таблице X были удалены, ошибка переместилась в другую таблицу, которая не была провалена раньше.

Изменен механизм всех таблиц для myISAM, и он работал отлично.

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

Ответ 14

Также стоит проверить, что вы случайно не работаете с неправильной базой данных. Эта ошибка возникает, если внешняя таблица не существует. Почему MySQL должен быть настолько загадочным?

Ответ 15

Убедитесь, что внешние ключи не указаны как уникальные в родительском. У меня была такая же проблема, и я решил ее, разделив ее как уникальную.

Ответ 16

В моем случае это было связано с тем, что поле, являющееся полем внешнего ключа, имеет слишком длинное имя, т.е. foreign key (some_other_table_with_long_name_id). Попробуйте коротко. В этом случае сообщение об ошибке немного вводит в заблуждение.

Кроме того, как упоминалось ранее @Jon - определения полей должны быть одинаковыми (обратите внимание на подтип unsigned).

Ответ 17

Если ограничение внешнего ключа основано на типе varchar, то в дополнение к списку, предоставленному marv-el целевой столбец должен иметь уникальное ограничение.

Ответ 18

(Слишком большие примечания для комментариев)

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

Измените PRIMARY KEY на (role_id, role_group_id) (в любом порядке). Это сделает доступ быстрее.

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

Дополнительные советы: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta

Ответ 19

выполнить ниже строки перед созданием таблицы: SET FOREIGN_KEY_CHECKS = 0;

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

- Укажите, чтобы проверить ограничения внешнего ключа (это по умолчанию)

SET FOREIGN_KEY_CHECKS = 1;

 

- Не проверяйте ограничения внешнего ключа

SET FOREIGN_KEY_CHECKS = 0;

Когда использовать: Временное отключение ссылочных ограничений (установите для FOREIGN_KEY_CHECKS значение 0) полезно, когда вам нужно заново создать таблицы и загрузить данные в любом порядке родитель-потомок

Ответ 20

Я столкнулся с той же проблемой, но я проверяю, что у меня нет родительской таблицы. Поэтому я просто редактирую родительскую миграцию перед дочерней миграцией. Просто сделай это.