MySQL не может добавить ограничение внешнего ключа

314

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

ОШИБКА 1215 (HY000): невозможно добавить ограничение внешнего ключа

Это SQL , я использую для создания таблиц, два оскорбляющих таблиц Patientи Appointment.

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

CREATE SCHEMA IF NOT EXISTS `doctorsoffice` DEFAULT CHARACTER SET utf8 ;
USE `doctorsoffice` ;

-- -----------------------------------------------------
-- Table `doctorsoffice`.`doctor`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`doctor` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`doctor` (
  `DoctorID` INT(11) NOT NULL AUTO_INCREMENT ,
  `FName` VARCHAR(20) NULL DEFAULT NULL ,
  `LName` VARCHAR(20) NULL DEFAULT NULL ,
  `Gender` VARCHAR(1) NULL DEFAULT NULL ,
  `Specialty` VARCHAR(40) NOT NULL DEFAULT 'General Practitioner' ,
  UNIQUE INDEX `DoctorID` (`DoctorID` ASC) ,
  PRIMARY KEY (`DoctorID`) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`medicalhistory`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`medicalhistory` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`medicalhistory` (
  `MedicalHistoryID` INT(11) NOT NULL AUTO_INCREMENT ,
  `Allergies` TEXT NULL DEFAULT NULL ,
  `Medications` TEXT NULL DEFAULT NULL ,
  `ExistingConditions` TEXT NULL DEFAULT NULL ,
  `Misc` TEXT NULL DEFAULT NULL ,
  UNIQUE INDEX `MedicalHistoryID` (`MedicalHistoryID` ASC) ,
  PRIMARY KEY (`MedicalHistoryID`) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`Patient`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`Patient` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`Patient` (
  `PatientID` INT unsigned NOT NULL AUTO_INCREMENT ,
  `FName` VARCHAR(30) NULL ,
  `LName` VARCHAR(45) NULL ,
  `Gender` CHAR NULL ,
  `DOB` DATE NULL ,
  `SSN` DOUBLE NULL ,
  `MedicalHistory` smallint(5) unsigned NOT NULL,
  `PrimaryPhysician` smallint(5) unsigned NOT NULL,
  PRIMARY KEY (`PatientID`) ,
  UNIQUE INDEX `PatientID_UNIQUE` (`PatientID` ASC) ,
  CONSTRAINT `FK_MedicalHistory`
    FOREIGN KEY (`MEdicalHistory` )
    REFERENCES `doctorsoffice`.`medicalhistory` (`MedicalHistoryID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `FK_PrimaryPhysician`
    FOREIGN KEY (`PrimaryPhysician` )
    REFERENCES `doctorsoffice`.`doctor` (`DoctorID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`Appointment`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`Appointment` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`Appointment` (
  `AppointmentID` smallint(5) unsigned NOT NULL AUTO_INCREMENT ,
  `Date` DATE NULL ,
  `Time` TIME NULL ,
  `Patient` smallint(5) unsigned NOT NULL,
  `Doctor` smallint(5) unsigned NOT NULL,
  PRIMARY KEY (`AppointmentID`) ,
  UNIQUE INDEX `AppointmentID_UNIQUE` (`AppointmentID` ASC) ,
  CONSTRAINT `FK_Patient`
    FOREIGN KEY (`Patient` )
    REFERENCES `doctorsoffice`.`Patient` (`PatientID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `FK_Doctor`
    FOREIGN KEY (`Doctor` )
    REFERENCES `doctorsoffice`.`doctor` (`DoctorID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`InsuranceCompany`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`InsuranceCompany` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`InsuranceCompany` (
  `InsuranceID` smallint(5) NOT NULL AUTO_INCREMENT ,
  `Name` VARCHAR(50) NULL ,
  `Phone` DOUBLE NULL ,
  PRIMARY KEY (`InsuranceID`) ,
  UNIQUE INDEX `InsuranceID_UNIQUE` (`InsuranceID` ASC) )
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`PatientInsurance`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`PatientInsurance` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`PatientInsurance` (
  `PolicyHolder` smallint(5) NOT NULL ,
  `InsuranceCompany` smallint(5) NOT NULL ,
  `CoPay` INT NOT NULL DEFAULT 5 ,
  `PolicyNumber` smallint(5) NOT NULL AUTO_INCREMENT ,
  PRIMARY KEY (`PolicyNumber`) ,
  UNIQUE INDEX `PolicyNumber_UNIQUE` (`PolicyNumber` ASC) ,
  CONSTRAINT `FK_PolicyHolder`
    FOREIGN KEY (`PolicyHolder` )
    REFERENCES `doctorsoffice`.`Patient` (`PatientID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `FK_InsuranceCompany`
    FOREIGN KEY (`InsuranceCompany` )
    REFERENCES `doctorsoffice`.`InsuranceCompany` (`InsuranceID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;

USE `doctorsoffice` ;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
joshuaegclark
источник

Ответы:

779

Чтобы найти конкретную ошибку, запустите это:

SHOW ENGINE INNODB STATUS;

И посмотри в LATEST FOREIGN KEY ERRORразделе.

Тип данных для дочернего столбца должен точно соответствовать родительскому столбцу. Например, поскольку medicalhistory.MedicalHistoryIDявляется INT, Patient.MedicalHistoryтакже должен быть INT, а не SMALLINT.

Кроме того, вы должны выполнить запрос set foreign_key_checks=0перед запуском DDL, чтобы вы могли создавать таблицы в произвольном порядке, а не создавать все родительские таблицы перед соответствующими дочерними таблицами.

Айк Уокер
источник
3
Спасибо, и несоответствие типов данных, и foreign_key_checks устранили проблему!
joshuaegclark
30
Был вызван другим сопоставлением на столах для меня, один был UTF-8, а другой был латинский1.
ug_
6
Также должен был убедиться, что я проверил «unsigned», так как это был INT без знака, хотя мои типы и длина соответствовали.
тембр
1
Мои таблицы автоматически создавались с помощью движка MyISAM! Спасибо Айк.
Капитан Гипертекст
3
Спасибо. Я пытался set nullудалить, но столбец был not null.
Мэтт
143

Я установил одно поле как «Без знака», а другое - нет. Как только я установил для обоих столбцов значение Без знака, это сработало.

Сатсара Гунаратне
источник
лол же. MySQL мог бы использовать более точную обработку ошибок для такого рода вещей.
Дейв
82
  • Двигатель должен быть таким же, например InnoDB
  • Тип данных должен быть одинаковым и одинаковой длины. например, VARCHAR (20)
  • Кодировка Collation Columns должна быть одинаковой. например, utf8
    Watchout: даже если у ваших таблиц одинаковые параметры сортировки, столбцы могут иметь разные значения.
  • Уникальный - внешний ключ должен ссылаться на поле, которое является уникальным (обычно первичный ключ) в справочной таблице.
am0wa
источник
1
Лучший ответ когда-либо, попробовав почти все, оказалось, что я должен явно добавить uniqueв столбец справочной таблицы, хотя это Primary Key!!
Яхья
Да, лучший ответ когда-либо ... в особенности первый пункт! В моем случае я сделал миграцию (от 2.5.14 до 2.7.2), где скрипт миграции не изменил ядро ​​базы данных, поэтому при создании новых таблиц я получил эту ошибку.
Бернхард
Лучший ответ мне тоже.
EngineerCoder
Было бы еще лучше с советами о том, как проверить / изменить. Для меня это была
sjgp
18

Попробуйте использовать тот же тип ваших первичных ключей - int (11) - для внешних ключей - smallint (5) - также.

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

Фелипп Оливейра
источник
mysql> создать уникальный индекс index_bar_id для foos (bar_id); ... mysql> изменить таблицу foos добавить ограничение index_bar_id внешний ключ (bar_id) ссылки бары (id); sixarm.com/about/…
CookieCoder
11

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

В моем собственном случае одна из таблиц использовала, utf8а другая использовала latin1.

У меня был другой случай, когда кодировка была такой же, но сопоставление отличалось. Один utf8_general_ciдругойutf8_unicode_ci

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

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Я надеюсь, что это поможет кому-то.

Гоке Обаса
источник
Хороший @Adegoke, отличный ответ
Edwin Ikechukwu Okonkwo
7

Чтобы установить ИНОСТРАННЫЙ КЛЮЧ в таблице B, вы должны установить КЛЮЧ в таблице A.

В таблице A: ИНДЕКС id( id)

А затем в таблице B,

CONSTRAINT `FK_id` FOREIGN KEY (`id`) REFERENCES `table-A` (`id`)
user3707075
источник
Я не совсем уверен, что вы говорите, но я обнаружил, что мой синтаксис был неверным. Я делал: изменить таблицу самолетов добавить ограничение fk_somehting_unique организация ссылок внешнего ключа (operator_id), но следовало сделать: изменить таблицу самолетов добавить ограничение fk_somehting_unique организация ссылок внешнего идентификатора (operator_id) (id) ;
Майкл Коксон
7

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

ссылка: Если вы указываете действие SET NULL, убедитесь, что вы не объявили столбцы в дочерней таблице как NOT NULL. ( ссылка )

Singh
источник
4

Проверьте следующие правила:

  • Сначала проверяется, правильно ли указаны имена для имен таблиц.

  • Второй правильный тип данных дать внешнему ключу?

Бхаскар Бхатт
источник
4

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

Кроме того, другое дело, что оба поля должны быть одного типа. Если один - INT, то другой также должен быть INT. Если один из них VARCHAR, другой также должен быть VARCHAR и т. Д.

Виджай Шринивас
источник
3

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

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

ученик
источник
2

Проверьте подпись в обеих колонках таблицы. Если столбец ссылающейся таблицы имеет значение SIGNED, столбец ссылочной таблицы также должен быть SIGNED.

katwekibs
источник
1

ПРИМЕЧАНИЕ. Следующие таблицы были взяты с какого-то сайта, когда я занимался исследованиями в базе данных. Таким образом, соглашение об именах не является правильным.

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

Родительский стол (ПРОДУКТЫ)

products | CREATE TABLE `products` (
  `productCode` varchar(15) NOT NULL,
  `productName` varchar(70) NOT NULL,
  `productLine` varchar(50) NOT NULL,
  `productScale` varchar(10) NOT NULL,
  `productVendor` varchar(50) NOT NULL,
  `productDescription` text NOT NULL,
  `quantityInStock` smallint(6) NOT NULL,
  `buyPrice` decimal(10,2) NOT NULL,
  `msrp` decimal(10,2) NOT NULL,
  PRIMARY KEY (`productCode`),
  KEY `productLine` (`productLine`),
  CONSTRAINT `products_ibfk_1` FOREIGN KEY (`productLine`) REFERENCES `productlines` (`productLine`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Детская таблица, в которой возникла проблема (PRICE_LOGS)

price_logs | CREATE TABLE `price_logs` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `productCode` varchar(15) DEFAULT NULL,
  `old_price` decimal(20,2) NOT NULL,
  `new_price` decimal(20,2) NOT NULL,
  `added_on` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `productCode` (`productCode`),
  CONSTRAINT `price_logs_ibfk_1` FOREIGN KEY (`productCode`) REFERENCES `products` (`productCode`) ON DELETE CASCADE ON UPDATE CASCADE
);

ИЗМЕНЕНО ДЛЯ

price_logs | CREATE TABLE `price_logs` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `productCode` varchar(15) DEFAULT NULL,
  `old_price` decimal(20,2) NOT NULL,
  `new_price` decimal(20,2) NOT NULL,
  `added_on` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `productCode` (`productCode`),
  CONSTRAINT `price_logs_ibfk_1` FOREIGN KEY (`productCode`) REFERENCES `products` (`productCode`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
Ханнавир Хакари
источник
1

Моя проблема заключалась в том, что я пытался создать таблицу отношений перед другими таблицами!

Ахмад Мобараки
источник
SET foreign_key_checks = 0;
LeeGee
0

У меня была похожая ошибка при создании внешнего ключа в таблице «многие ко многим», где первичный ключ состоял из 2 внешних ключей и другого обычного столбца. Я исправил проблему, исправив имя таблицы, на которую указывает ссылка, т.е. компанию, как показано в исправленном коде ниже:

create table company_life_cycle__history -- (M-M)
(
company_life_cycle_id tinyint unsigned not null,
Foreign Key (company_life_cycle_id) references company_life_cycle(id) ON DELETE    CASCADE ON UPDATE CASCADE,
company_id MEDIUMINT unsigned not null,
Foreign Key (company_id) references company(id) ON DELETE CASCADE ON UPDATE CASCADE,
activity_on date NOT NULL,
PRIMARY KEY pk_company_life_cycle_history (company_life_cycle_id, company_id,activity_on),
created_on datetime DEFAULT NULL,
updated_on datetime DEFAULT NULL,
created_by varchar(50) DEFAULT NULL,
updated_by varchar(50) DEFAULT NULL
);
Илтаф Халид
источник
0

У меня была похожая ошибка с двумя внешними ключами для разных таблиц, но с одинаковыми именами ключей! Я переименовал ключи и ошибка ушла)

Олег Всильдеревьев
источник
0

Была похожая ошибка, но в моем случае я пропустил объявление pk как auto_increment.

На всякий случай это может быть полезно любому

Луис Ролим
источник
0

Я получил ту же ошибку. Причина в моем случае была:

  1. Я создал резервную копию базы данных через phpmyadmin, скопировав всю базу данных.
  2. Я создал новый БД с тем же именем, что и старый БД, и выбрал его.
  3. Я запустил скрипт SQL для создания обновленных таблиц и данных.
  4. Я получил ошибку. Также, когда я отключил foreign_key_checks. Хотя база данных была полностью пустой.

Причина была следующей: поскольку я использовал phpmyadmin для создания некоторых внешних ключей в переименованной базе данных - внешние ключи создавались с префиксом имени базы данных, но префикс имени базы данных не обновлялся. Таким образом, в резервной базе данных все еще были ссылки, указывающие на вновь созданную базу данных.

lsblsb
источник
0

Мое решение, может быть, немного смущает и рассказывает историю о том, почему вы иногда должны смотреть на то, что у вас есть, вместо этих сообщений :)

Раньше я работал с форвард-инженером, который потерпел неудачу, так что это означало, что в моей базе данных уже было несколько таблиц, затем я сидел, пытаясь исправить ошибки, связанные с несовпадением внешних ключей, пытаясь убедиться, что все было идеально, но это столкнулось с Таблицы созданы ранее, поэтому не было преобладать.

DenLilleMand
источник
0

Еще одна причина этой ошибки - когда ваши таблицы или столбцы содержат зарезервированные ключевые слова :

Иногда это забывают.

EssGee
источник
0

В моем случае была синтаксическая ошибка, которая не была явно уведомлена консолью MySQL при выполнении запроса. Однако, SHOW ENGINE INNODB STATUSкомандования LATEST FOREIGN KEY ERRORсообщил раздел,

  Syntax error close to:

  REFERENCES`role`(`id`) ON DELETE CASCADE) ENGINE = InnoDB DEFAULT CHARSET = utf8

Мне пришлось оставить пробел между ними REFERENCESи roleзаставить его работать.

vicke4
источник
0

Для меня это было - вы не можете опустить префикс текущей таблицы БД, если вы создаете FK для не текущей БД, ссылающейся на текущую БД:

USE currrent_db;
ALTER TABLE other_db.tasks ADD CONSTRAINT tasks_fk FOREIGN KEY (user_id) REFERENCES currrent_db.users (id);

Если я опущу "currrent_db." для таблицы пользователей я получаю ошибку FK. Интересно, что ПОКАЗАТЬ ДВИГАТЕЛЬ INNODB STATUS; ничего не показывает в этом случае.

bearoff
источник
-1

У меня была такая же проблема, затем я исправил имя Engine как Innodb в родительской и дочерней таблицах и исправил имя ссылочного поля FOREIGN KEY ( c_id) REFERENCES x9o_parent_table( c_id),
затем оно работает нормально, и таблицы установлены правильно. Это будет полное использование для кого-то.

Субраманян
источник