it-roy-ru.com

MySQL Создание таблиц с использованием внешних ключей с ошибкой: 150

Я пытаюсь создать таблицу в 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;

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

93
user176842

У меня была такая же проблема с 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 для соответствующего столбца в поле дочерней таблицы. 

    Исключение: длина строк может быть разной. Например, 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. Если вы объявляете имя ограничения для внешнего ключа, имя ограничения должно быть уникальным во всей схеме, а не только в таблице, в которой определено ограничение. Две таблицы могут не иметь собственных ограничений с одинаковыми именами.

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

230
marv-el

Общее сообщение 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, и ограничение внешнего ключа будет успешно создано.

60
andrewdotn

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

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

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

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

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

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

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

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

10
Brent Writes Code

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

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

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

5
juacala

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

4
Eric Lawler

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

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

3
MuchMore

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

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

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

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

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

2
Juljan

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

1
wholenewstrain

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

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

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
Tim

MySQL Workbench 6.3 для Mac OS. 

Проблема: ошибка 150 в таблице X при попытке выполнить форвард-инжиниринг на диаграмме БД, 20 из 21 успешно выполнены, 1 не удалось. Если FK таблицы X были удалены, ошибка переносилась в другую таблицу, которая ранее не вызывала ошибок. 

Поменял все таблицы движка на myISAM и он работал просто отлично. 

 enter image description here

1
Eduardo Chongkan

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

0
Raza

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

0
SystemParadox

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

0
Ralph

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

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

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

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

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

0
Rick James

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

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

0
Kangur