web-dev-qa-db-fra.com

MySQL ne peut pas ajouter de contrainte de clé étrangère

J'essaie donc d'ajouter des contraintes de clé étrangère à ma base de données en tant qu'exigence de projet et cela a fonctionné la première fois ou deux sur des tables différentes, mais j'ai deux tables sur lesquelles une erreur se produit lorsque j'essaie d'ajouter les contraintes de clé étrangère. Le message d'erreur que je reçois est le suivant:

ERREUR 1215 (HY000): impossible d'ajouter une contrainte de clé étrangère

C'est le code SQL que j'utilise pour créer les tables. Les deux tables incriminées sont Patient et 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;
237
joshuaegclark

Pour trouver l'erreur spécifique, exécutez ceci:

SHOW ENGINE INNODB STATUS;

Et regardez dans la section LATEST FOREIGN KEY ERROR.

Le type de données de la colonne enfant doit correspondre exactement à la colonne parent. Par exemple, puisque medicalhistory.MedicalHistoryID est une INT, Patient.MedicalHistory doit également être une INT et non une SMALLINT.

En outre, vous devez exécuter la requête set foreign_key_checks=0 avant d'exécuter la DDL afin de pouvoir créer les tables dans un ordre arbitraire au lieu de devoir créer toutes les tables parent avant les tables enfants correspondantes.

619
Ike Walker

J'avais défini un champ comme "Unsigned" et un autre pas. Une fois que j'ai défini les deux colonnes sur Unsigned, cela a fonctionné.

119
Satsara Gunaratne
  • Engine devrait être identique p. Ex. InnoDB 
  • Type de données devrait être identique et de même longueur. par exemple. VARCHAR (20) 
  • Classement Le jeu de caractères des colonnes doit être identique. par exemple. utf8
    Watchout: Même si vos tables ont le même classement, les colonnes peuvent toujours en avoir un différent. 
  • Unique - La clé étrangère doit faire référence au champ unique (généralement la clé primaire) dans la table de référence. 
61
Andrew

Essayez d’utiliser le même type de vos clés primaires - int (11) - sur les clés étrangères - smallint (5) - ainsi que.

J'espère que ça aide!

15
Felypp Oliveira

Vérifiez que le codage et le classement des caractères des deux tables sont identiques. 

Dans mon cas, l’une des tables utilisait utf8 et l’autre utilisait latin1

J'ai eu un autre cas où l'encodage était le même mais le classement différent. Un utf8_general_ci l'autre utf8_unicode_ci

Vous pouvez exécuter cette commande pour définir le codage et le classement d'une table.

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

J'espère que ça aidera quelqu'un.

11
Goke Obasa

Pour définir une clé étrangère dans le tableau B, vous devez définir une clé dans le tableau A.

Dans le tableau A: INDEX id (id)

Et puis dans le tableau B,

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

J'ai eu le même problème et la solution était très simple. Solution: les clés étrangères déclarées dans la table ne doivent pas être définies comme non nulles.

reference: Si vous spécifiez une action SET NULL, assurez-vous de ne pas avoir déclaré les colonnes de la table enfant comme NOT NULL. ( ref )

5
Singh

Assurez-vous que les deux tableaux sont au format InnoDB. Même si on est au format MyISAM, alors, la contrainte de clé étrangère ne fonctionnera pas.

En outre, les deux champs doivent être du même type. Si l’un est INT, l’autre devrait aussi être INT. Si l’un est VARCHAR, l’autre devrait également être VARCHAR, etc.

4
Vijay Srinivas

Vérifiez les règles suivantes:

  • Vérifie d'abord si les noms sont donnés correctement pour les noms de table

  • Le second type de données correct donne-t-il à la clé étrangère?

3
Bhaskar Bhatt

J'ai fait face au problème et j'ai pu le résoudre en m'assurant que les types de données correspondaient exactement.

J'utilisais SequelPro pour ajouter la contrainte et la clé primaire était non signée par défaut. 

2
Learner

Vérifiez la signature sur les deux colonnes de votre table. Si la colonne de la table de référence est SIGNED, la colonne de la table référencée devrait également l'être. 

1
katwekibs

Mon problème était que j'essayais de créer la table de relations avant les autres tables!

0
Ahmad Mobaraki

Une autre cause de cette erreur est lorsque vos tables ou colonnes contiennent des keywords réservés:

Parfois, on les oublie.

0
EssGee

Une erreur similaire s'est produite lors de la création de la clé étrangère dans une table Plusieurs-Plusieurs où la clé primaire était composée de 2 clés étrangères et d'une autre colonne normale. J'ai corrigé le problème en corrigeant le nom de la table référencée, à savoir société, comme indiqué dans le code corrigé ci-dessous:

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
iltaf khalid

NOTE: Les tables suivantes ont été extraites de certains sites quand je faisais de la RD sur la base de données. Donc, la convention de nommage n'est pas appropriée.

Pour moi, le problème était, ma table parente avait un jeu de caractères différent de celui de celui que je créais.

Table des parents (PRODUITS)

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

Table d'enfants ayant un problème (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
);

MODIFIÉ POUR  

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 
0
Channaveer Hakari

J'ai eu une erreur similaire avec deux clés étrangères pour des tables différentes mais avec les mêmes noms de clé! J'ai renommé les clés et l'erreur est partie)

J'ai eu la même erreur. La cause dans mon cas était:

  1. J'ai créé une sauvegarde d'une base de données via phpmyadmin en copiant l'intégralité de la base de données.
  2. J'ai créé une nouvelle base de données avec le même nom que l'ancienne base de données et l'a sélectionnée.
  3. J'ai commencé un script SQL pour créer des tables et des données mises à jour.
  4. J'ai eu l'erreur. Aussi, quand j'ai désactivé foreign_key_checks. Bien que la base de données était complètement vide.

La cause en était: Depuis que j'ai utilisé phpmyadmin pour créer des clés étrangères dans la base de données renommée - les clés étrangères ont été créées avec un préfixe de nom de base de données mais le préfixe de nom de base de données n'a pas été mis à jour. Il y avait donc toujours des références dans la base de données de sauvegarde pointant vers la base de données nouvellement créée.

0
lsblsb

Avait une erreur similaire, mais dans mon cas, il me manquait de déclarer le pk comme auto_increment.

Juste au cas où cela pourrait être utile à n'importe qui

0
Luiz Rolim

Ma solution est peut-être un peu embarrassante et explique pourquoi vous devriez parfois regarder ce que vous avez devant vous au lieu de ces messages :) 

J'avais déjà fait appel à un ingénieur avant, ce qui signifiait que ma base de données contenait déjà quelques tables, puis je restais assis à essayer de résoudre les problèmes de contraintes de clés étrangères afin de m'assurer que tout était parfait, mais cela se heurtait à la tables précédemment créées, il était donc impossible de l'emporter.

0
DenLilleMand

Dans mon cas, une erreur de syntaxe n'a pas été explicitement notifiée par la console MySQL lors de l'exécution de la requête. Cependant, la section SHOW ENGINE INNODB STATUS de la commande LATEST FOREIGN KEY ERROR a été signalée, 

  Syntax error close to:

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

Je devais laisser un espace entre REFERENCES et role pour que cela fonctionne.

0
vicke4