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

169

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

ОШИБКА 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;
Теги:
foreign-keys

17 ответов

466
Лучший ответ

Чтобы найти конкретную ошибку, выполните следующее:

SHOW ENGINE INNODB STATUS;

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

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

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

  • 1
    Спасибо, и несоответствие типов данных, и foreign_key_checks устранили проблему!
  • 16
    Был вызван другим сопоставлением на столах для меня, один был UTF-8, а другой был латинский1.
Показать ещё 13 комментариев
87

Я установил одно поле как "Без знака", а другое - нет. Как только я установил оба столбца в Unsigned, он сработал.

  • 2
    Установка на unsigned работала и для меня.
  • 0
    Установка неподписанного в поле внешнего ключа работала у меня
Показать ещё 2 комментария
30
  • Двигатель должен быть таким же, например. InnoDB
  • Тип данных должен совпадать с той же длиной. например VARCHAR (20)
  • Collation Колонка символов должна быть одинаковой. например utf8
    Watchout: Даже если ваши таблицы имеют одинаковое значение Collation, столбцы могут быть разными.
  • Уникальный. Внешний ключ должен ссылаться на поле, которое является уникальным (обычно первичный ключ) в справочной таблице.
  • 1
    Лучший ответ когда-либо, попробовав почти все, оказалось, что я должен явно добавить unique столбец справочной таблицы, даже если это Primary Key !!
  • 0
    Да, лучший ответ когда-либо ... в особенности первый пункт! В моем случае я сделал миграцию (от 2.5.14 до 2.7.2), где сценарий миграции не изменил ядро базы данных, поэтому при создании новых таблиц я получил эту ошибку.
Показать ещё 1 комментарий
13

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

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

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

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

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

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

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

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

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

  • 0
    Хороший @Adegoke, отличный ответ
4

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

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

4

Чтобы установить FOREIGN KEY в таблице B, вы должны установить KEY в таблице A.

В таблице A:   INDEX id (id)

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

CONSTRAINT `FK_id` FOREIGN KEY (`id`) REFERENCES `table-A` (`id`)
  • 0
    Я не совсем уверен, что вы говорите, но я обнаружил, что мой синтаксис был неверным. Я делал: изменить таблицу самолетов добавить ограничение fk_somehting_unique организация ссылок внешнего ключа (operator_id), но следовало сделать: изменить таблицу самолетов добавить ограничение fk_somehting_unique ссылка организации внешнего ключа (operator_id) (id) ;
  • 1
    Спасибо!!!!! После нескольких часов попыток исправить мою проблему, это было исправлением!
Показать ещё 1 комментарий
3

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

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

3

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

  • Сначала проверяется правильность присвоения имен именам таблиц

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

0

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

0

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

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

0

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

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

0

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

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

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

0

Имел подобную ошибку, но в моем случае я отсутствовал, чтобы объявить pk как auto_increment.

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

0

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

0

У меня была аналогичная ошибка при создании внешнего ключа в таблице Many to Many, где первичный ключ состоял из 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
);
-2

У меня была такая же проблема, после чего я исправил имя Engine как Innodb в родительских и дочерних таблицах и исправил имя ссылочного поля ИНОСТРАННЫЙ КЛЮЧ (c_id) ССЫЛКИ x9o_parent_table (c_id)
то он отлично работает, и таблицы установлены правильно. Это будет полезно для кого-то.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню