MySQL Создание таблиц с использованием внешних ключей с ошибкой: 150 - PullRequest
95 голосов
/ 22 сентября 2009

Я пытаюсь создать таблицу в MySQL с двумя внешними ключами, которые ссылаются на первичные ключи в 2 других таблицах, но я получаю ошибку 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;

Любая помощь будет принята с благодарностью.

Ответы [ 19 ]

232 голосов
/ 12 января 2011

У меня была такая же проблема с 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. Столбцы столбца PK в родительской таблице должны иметь тот же тип данных, что и столбцы столбца FK в дочерней таблице. Например, если столбец PK в родительской таблице равен 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.

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

61 голосов
/ 12 августа 2013

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

25 голосов
/ 27 октября 2009

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

Часто свойство «unsigned» в столбце идентификаторов вас поймает.

ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
10 голосов
/ 22 сентября 2009

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

Если вы ошибаетесь, когда «исходный код» вашего SQL-файла, вы сможете запустить команду «ПОКАЗАТЬ СТАТУС ДВИГАТЕЛЯ INNODB» сразу после команды «источник», чтобы увидеть более подробную информацию об ошибке. .

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

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

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

5 голосов
/ 13 июня 2012

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

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

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

4 голосов
/ 23 февраля 2012

Для других, которые находят эту запись SO через Google: убедитесь, что вы не пытаетесь выполнить действие SET NULL для столбца внешнего ключа (который будет), определенного как «NOT NULL». Это вызывало сильное разочарование, пока я не вспомнил, что сделал CHECK ENGINE INNODB STATUS.

3 голосов
/ 26 ноября 2014

Определенно, это не тот случай, но я нашел эту ошибку довольно распространенной и неочевидной. Целью 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 голосов
/ 04 июня 2015

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

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

2 голосов
/ 27 ноября 2013

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

Так что в этом случае время заново создать мою таблицу!

2 голосов
/ 29 мая 2016

Пожалуйста, сначала убедитесь, что

  1. вы используете таблицы InnoDB.
  2. для FOREIGN KEY имеет тот же тип и длину (!), Что и поле источника.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...