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;

Відповіді:


778

Щоб знайти конкретну помилку, виконайте наступне:

SHOW ENGINE INNODB STATUS;

І подивіться у LATEST FOREIGN KEY ERRORрозділі.

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

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


3
Дякуємо, як непослідовність типу даних, так і Foreign_key_checks виправили проблему!
joshuaegclark

30
Було викликано різним зіставленням на столах для мене, один - UTF-8, а другий - латинський1.
ug_

6
Також потрібно було переконатися, що я перевірив "неподписаний", оскільки це був безпідписаний INT, хоча мої типи та довжина збігалися.
timbrown

1
Мої таблиці автоматично створювалися за допомогою двигуна MyISAM! Дякую Айку.
Капітан Гіпертекст

3
Дякую. Я намагався set nullвидалити, але стовпець був not null.
Метт,

142

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


LOL ж. MySQL може використовувати більш точну обробку помилок у подібних матеріалах.
Дейв

81
  • Двигун повинен бути таким же, як InnoDB
  • Тип даних повинен бути однаковим і з однаковою довжиною. наприклад VARCHAR (20)
  • Колекція Графік стовпців повинен бути однаковим. наприклад, utf8
    Watchout: Навіть якщо ваші таблиці мають однакове зібрання, стовпці все одно можуть мати інший.
  • Унікальний - зовнішній ключ повинен посилатися на поле, яке є унікальним (як правило, первинним ключем) у довідковій таблиці.

1
Найкращий відповідь коли-небудь, Після спроби майже всього, виявилося, що я мушу явно додати uniqueдо стовпчика довідкової таблиці, хоча це Primary Key!!
Ях’я

Так, найкращий відповідь коли-небудь ... зокрема, перша точка! У моєму випадку я здійснив міграцію (зарезервував 2.5.14 до книги 2.7.2), де сценарій міграції не змінив двигун бази даних, тому при створенні нових таблиць я отримав цю помилку.
Бернхард

Найкраще відповісти і на мене.
EngineerCoder

Було б ще приголомшливішими порадами щодо перевірки / зміни. Для мене це була різниця Collation на рівні стовпців , і це дало мені виправити (спасибі за ідею!): Stackoverflow.com/questions/1294117 / ...
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, чудова відповідь
Едвін Ікечукву Оконькво

7

Для встановлення ІМЕЧНОГО КЛЮЧА в Таблиці B ви повинні встановити КЛЮЧ у таблиці А.

У таблиці A: INDEX id( id)

А потім у таблиці B,

CONSTRAINT `FK_id` FOREIGN KEY (`id`) REFERENCES `table-A` (`id`)

Я не впевнений, що саме ви говорите, але я виявив, що мій синтаксис був неправильним. Я робив: змінювати літальний апарат настільних обмежень fk_somehting_unique закордонний ключ (operator_id) посилання організації, але повинен був би зробити: змінити літальний стіл додати обмеження fk_somehting_unique іноземний ключ (operator_id) посилання організації (id) ;
Майкл Коксон

7

У мене була така ж проблема, і рішення було дуже простим. Рішення: зовнішні ключі, задекларовані в таблиці, не повинні встановлювати значення "null".

довідка: Якщо ви вказали дію SET NULL, переконайтеся, що ви не оголосили стовпці в дочірній таблиці як NOT NULL. ( ref )


4

Перевірте такі правила:

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

  • Другий правий тип даних надавати іноземному ключу?


4

Переконайтеся, що обидві таблиці у форматі InnoDB. Навіть якщо він є у форматі MyISAM, значить, обмеження зовнішніх ключів не спрацює.

Також інша справа, що обидва поля повинні бути одного типу. Якщо один є INT, то інший також повинен бути INT. Якщо один - VARCHAR, інший також повинен бути VARCHAR тощо.


3

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

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


2

Перевірте підпис у обох стовпцях таблиці. Якщо стовпець стовпчикової таблиці є ПІДТВОРЕНО, стовпчик згаданої таблиці також повинен бути ЗНАЧЕНО.


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. Я створив новий db з такою ж назвою, коли старий db вибрав його.
  3. Я створив сценарій SQL для створення оновлених таблиць і даних.
  4. Я отримав помилку. Також, коли я відключив Foreign_key_checks. Хоча база даних була абсолютно порожньою.

Причина полягала в тому, що я використовував phpmyadmin для створення деяких іноземних ключів у перейменованій базі даних - іноземних ключів, де створено з префіксом імені бази даних, але префікс імені бази даних не оновлювався. Тож у резервній копії даних все ще були посилання на новостворений db.


0

Моє рішення, можливо, трохи бентежить і розповідає історію, чому іноді слід дивитись на те, що у вас перед собою, замість цих постів :)

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


0

Ще однією причиною цієї помилки є те, коли ваші таблиці або стовпці містять зарезервовані ключові слова :

Іноді хтось це забуває.


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змусити його працювати.


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. Цікаво, що ПОКАЗУЙТЕ ДВИГАТЕЛЬНИЙ СТАТУС ІННОДБУ; в цьому випадку нічого не показує.


-1

У мене була ця сама проблема, тоді я виправив ім'я двигуна як Innodb у батьківських та дочірніх таблицях та виправив іменне поле посилання FOREIGN KEY ( c_id) REFERENCES x9o_parent_table( c_id),
тоді воно працює нормально, і таблиці встановлені правильно. Для когось це буде повне використання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.