MySQL Impossibile aggiungere vincolo di chiave esterna


314

Quindi sto cercando di aggiungere vincoli di chiave esterna al mio database come requisito di progetto e ha funzionato la prima volta o due su tabelle diverse, ma ho due tabelle su cui ottengo un errore quando provo ad aggiungere i vincoli di chiave esterna. Il messaggio di errore che ricevo è:

ERRORE 1215 (HY000): impossibile aggiungere il vincolo di chiave esterna

Questo è l'SQL che sto usando per creare le tabelle, le due tabelle offensive sono Patiente 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;

Risposte:


779

Per trovare l'errore specifico eseguire questo:

SHOW ENGINE INNODB STATUS;

E guarda nella LATEST FOREIGN KEY ERRORsezione.

Il tipo di dati per la colonna figlio deve corrispondere esattamente alla colonna padre. Ad esempio, poiché medicalhistory.MedicalHistoryIDè un INT, Patient.MedicalHistorydeve anche essere un INT, non un SMALLINT.

Inoltre, è necessario eseguire la query set foreign_key_checks=0prima di eseguire il DDL in modo da poter creare le tabelle in un ordine arbitrario anziché dover creare tutte le tabelle padre prima delle relative tabelle figlio.


3
Grazie, sia l'incoerenza del tipo di dati che foreign_key_checks hanno risolto il problema!
joshuaegclark,

30
È stato causato da una diversa collazione sui tavoli per me, uno era UTF-8 e l'altro era latino1.
ug_

6
Inoltre, dovevo assicurarmi di aver selezionato "unsigned" poiché si trattava di un INT senza segno anche se i miei tipi e la lunghezza corrispondevano.
timbrown,

1
Le mie tabelle venivano create automaticamente con il motore MyISAM! Grazie Ike.
Capitano Hypertext,

3
Grazie. Stavo cercando di set nulleliminare, ma la colonna era not null.
Matt

143

Avevo impostato un campo come "Non firmato" e l'altro no. Una volta ho impostato entrambe le colonne su Unsigned ha funzionato.


lol stesso. MySQL potrebbe utilizzare una gestione degli errori più precisa su questo tipo di cose.
dave,

82
  • Il motore dovrebbe essere lo stesso, ad es. InnoDB
  • Il tipo di dati dovrebbe essere lo stesso e con la stessa lunghezza. ad es. VARCHAR (20)
  • Il set di caratteri delle colonne di confronto dovrebbe essere lo stesso. ad es. utf8
    Watchout: anche se i tuoi tavoli hanno le stesse regole di confronto, le colonne potrebbero averne uno diverso.
  • Unico : la chiave esterna deve fare riferimento al campo univoco (in genere chiave primaria) nella tabella di riferimento.

1
La migliore risposta di sempre, dopo aver provato quasi tutto, ho scoperto che devo aggiungere esplicitamente uniquealla colonna della tabella di riferimento anche se è unaPrimary Key !!
Yahya,

Sì, la migliore risposta di sempre ... in particolare il primo punto di abete! Nel mio caso ho effettuato una migrazione (prenotato dal 2.5.14 a bookd 2.7.2), in cui lo script di migrazione non ha modificato il motore di database, quindi durante la creazione di nuove tabelle ho riscontrato questo errore.
Bernhard,

Migliore risposta anche a me.
EngineerCoder

Sarebbe ancora più fantastico con suggerimenti su come controllare / cambiare. Per me è stata una differenza di regole di confronto a livello di colonna e questo mi ha dato la correzione (grazie per l'idea!): Stackoverflow.com/questions/1294117/...
sjgp

18

Prova a utilizzare lo stesso tipo di chiavi primarie - int (11) - anche sulle chiavi esterne - smallint (5) -.

Spero che sia d'aiuto!


mysql> crea un indice univoco index_bar_id su foos (bar_id); ... mysql> modifica tabella foos aggiungi vincolo index_bar_id chiave esterna (bar_id) riferimenti bar (id); sixarm.com/about/…
CookieCoder il

11

Verificare che la codifica e le regole di confronto dei caratteri per le due tabelle siano uguali.

Nel mio caso, uno dei tavoli stava usando utf8e l'altro stava usandolatin1 .

Ho avuto un altro caso in cui la codifica era la stessa ma la fascicolazione diversa. Uno utf8_general_cil'altroutf8_unicode_ci

È possibile eseguire questo comando per impostare la codifica e le regole di confronto per una tabella.

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Spero che questo aiuti qualcuno.


Nice one @Adegoke, great response
Edwin Ikechukwu Okonkwo

7

Per impostare un TASTO ESTERO nella Tabella B è necessario impostare un TASTO nella tabella A.

Nella tabella A: INDICE id( id)

E poi nella tabella B,

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

non sono sicuro di quello che stai dicendo, ma ho scoperto che la mia sintassi non era corretta. Stavo facendo: altera velivolo da tavolo aggiungi vincolo fk_somehting_unique riferimento a chiave esterna (operator_id) organizzazione, ma avrei dovuto farlo: altera velivolo da tavolo aggiungi vincolo fk_somehting_unique chiave esterna (operator_id) referenze organizzazione (id) ;
Michael Coxon,

7

Ho avuto lo stesso problema e la soluzione era molto semplice. Soluzione: le chiavi esterne dichiarate nella tabella non devono essere impostate su non null.

riferimento: se si specifica un'azione SET NULL, assicurarsi di non aver dichiarato le colonne nella tabella figlio come NOT NULL. ( rif )


4

Controlla le seguenti regole:

  • Innanzitutto controlla se i nomi sono indicati correttamente per i nomi delle tabelle

  • Secondo tipo di dati di destra dato alla chiave esterna?


4

Assicurati che entrambe le tabelle siano in formato InnoDB. Anche se uno è in formato MyISAM, il vincolo di chiave esterna non funzionerà.

Inoltre, un'altra cosa è che entrambi i campi dovrebbero essere dello stesso tipo. Se uno è INT, anche l'altro dovrebbe essere INT. Se uno è VARCHAR, l'altro dovrebbe anche essere VARCHAR, ecc.


3

Ho affrontato il problema e sono stato in grado di risolverlo assicurandomi che i tipi di dati corrispondessero esattamente.

Stavo usando SequelPro per aggiungere il vincolo e stava rendendo la chiave primaria come non firmata per impostazione predefinita.


2

Controlla la firma su entrambe le colonne della tabella. Se la colonna della tabella di riferimento è SIGNED, anche la colonna della tabella di riferimento deve essere SIGNED.


1

NOTA: Le seguenti tabelle sono state prese da alcuni siti mentre stavo facendo un po 'di ricerca e sviluppo nel database. Quindi la convenzione di denominazione non è corretta.

Per me, il problema era che la mia tabella padre aveva un set di caratteri diverso da quello che stavo creando.

Tabella padre (PRODOTTI)

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

Tabella figlio che ha riscontrato un problema (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
);

MODIFICATO A

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

Il mio problema era che stavo cercando di creare la tabella delle relazioni prima di altre tabelle!


SET foreign_key_checks = 0;
LeeGee,

0

Ho riscontrato un errore simile nella creazione della chiave esterna in una tabella Many to Many in cui la chiave primaria era composta da 2 chiavi esterne e un'altra colonna normale. Ho risolto il problema correggendo il nome della tabella di riferimento, ovvero la società, come mostrato nel codice corretto di seguito:

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

Si è verificato un errore simile, ma nel mio caso mi mancava dichiarare il pk come auto_increment.

Nel caso in cui potesse essere utile a chiunque


0

Ho avuto lo stesso errore. La causa nel mio caso è stata:

  1. Ho creato un backup di un database tramite phpmyadmin copiando l'intero database.
  2. Ho creato un nuovo db con lo stesso nome che il vecchio db non aveva selezionato.
  3. Ho avviato uno script SQL per creare tabelle e dati aggiornati.
  4. Ho ricevuto l'errore. Anche quando ho disabilitato foreign_key_checks. Anche se il database era completamente vuoto.

La causa è stata: poiché ho usato phpmyadmin per creare alcune chiavi esterne nel database rinominato, le chiavi esterne sono state create con un prefisso del nome del database ma il prefisso del nome del database non è stato aggiornato. Quindi c'erano ancora riferimenti nel db di backup che puntavano al db appena creato.


0

La mia soluzione è forse un po 'imbarazzante e racconta la storia del perché a volte dovresti guardare quello che hai davanti a te invece di questi post :)

Avevo già diretto un ingegnere avanzato, il che non ha funzionato, quindi ciò significa che il mio database aveva già alcune tabelle, quindi sono rimasto seduto a cercare di correggere errori di contrapposizione di chiavi esterne cercando di assicurarmi che tutto fosse perfetto, ma si è imbattuto nel tabelle precedentemente create, quindi non ha prevalso.


0

Un'ulteriore causa di questo errore è quando le tue tabelle o colonne contengono parole chiave riservate :

A volte si dimenticano questi.


0

Nel mio caso, si è verificato un errore di sintassi che non è stato esplicitamente notificato dalla console MySQL durante l'esecuzione della query. Tuttavia, SHOW ENGINE INNODB STATUSla LATEST FOREIGN KEY ERRORsezione del comando riportava,

  Syntax error close to:

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

Ho dovuto lasciare uno spazio bianco tra REFERENCESe rolefarlo funzionare.


0

Per me lo era - non puoi omettere il prefisso della tabella DB corrente se crei un FK per un DB non corrente che fa riferimento al DB corrente:

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

Se ometto "currrent_db". per la tabella degli utenti, ottengo l'errore FK. Interessante che MOSTRARE LO STATO INNODB DEL MOTORE; non mostra nulla in questo caso.


-1

Ho avuto lo stesso problema, quindi ho corretto il nome del motore come Innodb in entrambe le tabelle padre e figlio e ho corretto il nome del campo di riferimento FOREIGN KEY ( c_id) REFERENCES x9o_parent_table( c_id),
quindi funziona correttamente e le tabelle sono installate correttamente. Questo sarà pieno per qualcuno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.