MySQL kann keine Fremdschlüsseleinschränkung hinzufügen

314

Ich versuche also, meiner Datenbank als Projektanforderung Fremdschlüsseleinschränkungen hinzuzufügen, und es hat beim ersten oder zweiten Mal in verschiedenen Tabellen funktioniert, aber ich habe zwei Tabellen, bei denen beim Versuch, die Fremdschlüsseleinschränkungen hinzuzufügen, eine Fehlermeldung angezeigt wird. Die Fehlermeldung, die ich erhalte, lautet:

FEHLER 1215 (HY000): Fremdschlüsseleinschränkung kann nicht hinzugefügt werden

Dies ist das SQL, mit dem ich die Tabellen erstelle. Die beiden fehlerhaften Tabellen sind Patientund 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;
Joshuegclark
quelle

Antworten:

778

Um den spezifischen Fehler zu finden, führen Sie Folgendes aus:

SHOW ENGINE INNODB STATUS;

Und schauen Sie in den LATEST FOREIGN KEY ERRORAbschnitt.

Der Datentyp für die untergeordnete Spalte muss genau mit der übergeordneten Spalte übereinstimmen. Zum Beispiel, da medicalhistory.MedicalHistoryIDist ein INT, Patient.MedicalHistorymuss auch ein sein INT, nicht ein SMALLINT.

Außerdem sollten Sie die Abfrage ausführen, set foreign_key_checks=0bevor Sie die DDL ausführen, damit Sie die Tabellen in einer beliebigen Reihenfolge erstellen können, anstatt alle übergeordneten Tabellen vor den entsprechenden untergeordneten Tabellen erstellen zu müssen.

Ike Walker
quelle
3
Vielen Dank, sowohl die Inkonsistenz des Datentyps als auch Foreign_key_checks haben das Problem behoben!
Joshuaegclark
30
Wurde durch eine andere Zusammenstellung auf den Tabellen für mich verursacht, eine war UTF-8 und die andere war Latin1.
ug_
6
Außerdem musste ich sicherstellen, dass ich "unsigned" aktiviert hatte, da dies ein nicht signiertes INT war, obwohl meine Typen und Längen übereinstimmten.
Timbrown
1
Meine Tabellen wurden automatisch mit der MyISAM-Engine erstellt! Danke Ike.
Kapitän Hypertext
3
Vielen Dank. Ich habe versucht zu set nulllöschen, aber die Spalte war not null.
Matt
142

Ich hatte ein Feld als "Unsigned" gesetzt und das andere nicht. Nachdem ich beide Spalten auf Unsigned gesetzt hatte, funktionierte es.

Satsara Gunaratne
quelle
lol gleich. MySQL könnte eine genauere Fehlerbehandlung für diese Art von Dingen verwenden.
Dave,
81
  • Motor sollte der gleiche sein, zB InnoDB
  • Der Datentyp sollte gleich und gleich lang sein. zB VARCHAR (20)
  • Der Zeichensatz für Kollatierungsspalten sollte identisch sein. zB utf8
    Watchout: Auch wenn Ihre Tabellen dieselbe Sortierung haben, können Spalten dennoch eine andere haben.
  • Eindeutig - Der Fremdschlüssel sollte sich auf ein Feld beziehen, das in der Referenztabelle eindeutig ist (normalerweise der Primärschlüssel) .
am0wa
quelle
1
Beste Antwort aller Zeiten, Nachdem ich fast alles ausprobiert hatte, stellte sich heraus, dass ich die uniqueSpalte der Referenztabelle explizit hinzufügen muss , obwohl es ein Primary Key!!
Yahya
Ja, die beste Antwort aller Zeiten ... insbesondere der erste Punkt! In meinem Fall habe ich eine Migration durchgeführt (gebucht 2.5.14 bis bookd 2.7.2), bei der das Migrationsskript das Datenbankmodul nicht geändert hat. Beim Erstellen neuer Tabellen wurde dieser Fehler angezeigt.
Bernhard
Am besten antworte mir auch.
EngineerCoder
Wäre noch großartiger mit Tipps zum Überprüfen / Ändern. Für mich war es ein Unterschied auf Spaltenebene (danke für die Idee!) Und dies gab mir den Fix: stackoverflow.com/questions/1294117/…
sjgp
18

Versuchen Sie, den gleichen Typ Ihrer Primärschlüssel - int (11) - auch für die Fremdschlüssel - smallint (5) - zu verwenden.

Ich hoffe es hilft!

Felypp Oliveira
quelle
mysql> Erstelle einen eindeutigen Index index_bar_id für foos (bar_id); ... mysql> alter table foos add Constraint index_bar_id Fremdschlüssel (bar_id) referenziert Balken (id); sixarm.com/about/…
CookieCoder
11

Stellen Sie sicher, dass die Zeichenkodierung und Sortierung für die beiden Tabellen identisch ist.

In meinem Fall wurde eine der Tabellen verwendet utf8und die andere latin1.

Ich hatte einen anderen Fall, in dem die Codierung gleich war, die Sortierung jedoch unterschiedlich. Eins utf8_general_cidas andereutf8_unicode_ci

Sie können diesen Befehl ausführen, um die Codierung und Sortierung für eine Tabelle festzulegen.

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Ich hoffe das hilft jemandem.

Goke Obasa
quelle
Netter @Adegoke, tolle Antwort
Edwin Ikechukwu Okonkwo
7

Um einen AUSLÄNDISCHEN SCHLÜSSEL in Tabelle B festzulegen, müssen Sie einen SCHLÜSSEL in Tabelle A festlegen.

In Tabelle A: INDEX id( id)

Und dann in der Tabelle B,

CONSTRAINT `FK_id` FOREIGN KEY (`id`) REFERENCES `table-A` (`id`)
user3707075
quelle
Ich bin mir nicht sicher, was Sie genau sagen, aber ich habe festgestellt, dass meine Syntax falsch war. Ich habe Folgendes getan: Ändern von Tabellenflugzeugen Hinzufügen einer Einschränkung fk_somehting_unique Fremdschlüssel (operator_id) referenziert Organisation, hätte aber Folgendes tun sollen: Ändern von Tabellenflugzeugen Hinzufügen einer Einschränkung fk_somehting_unique Fremdschlüssel (operator_id) referenziert Organisation (id) ;
Michael Coxon
7

Ich hatte das gleiche Problem und die Lösung war sehr einfach. Lösung: In der Tabelle deklarierte Fremdschlüssel sollten nicht auf null gesetzt werden.

Referenz: Wenn Sie eine SET NULL-Aktion angeben, stellen Sie sicher, dass Sie die Spalten in der untergeordneten Tabelle nicht als NOT NULL deklariert haben. ( ref )

Singh
quelle
4

Überprüfen Sie die folgenden Regeln:

  • Überprüft zunächst, ob Namen für Tabellennamen richtig angegeben sind

  • Zweiter richtiger Datentyp für Fremdschlüssel?

Bhaskar Bhatt
quelle
4

Bitte stellen Sie sicher, dass beide Tabellen im InnoDB-Format vorliegen. Selbst wenn eines im MyISAM-Format vorliegt, funktioniert die Fremdschlüsseleinschränkung nicht.

Eine andere Sache ist, dass beide Felder vom gleichen Typ sein sollten. Wenn einer INT ist, sollte der andere ebenfalls INT sein. Wenn einer VARCHAR ist, sollte der andere auch VARCHAR usw. sein.

Vijay Srinivas
quelle
3

Ich war mit dem Problem konfrontiert und konnte es beheben, indem ich sicherstellte, dass die Datentypen genau übereinstimmten.

Ich habe SequelPro zum Hinzufügen der Einschränkung verwendet und den Primärschlüssel standardmäßig als vorzeichenlos festgelegt.

Lerner
quelle
2

Überprüfen Sie die Signatur in beiden Tabellenspalten. Wenn die referenzierende Tabellenspalte SIGNIERT ist, sollte auch die referenzierte Tabellenspalte SIGNIERT sein.

Katwekibs
quelle
1

HINWEIS: Die folgenden Tabellen stammen von einer Website, als ich Forschungs- und Entwicklungsarbeiten an der Datenbank durchgeführt habe. Die Namenskonvention ist also nicht richtig.

Für mich war das Problem, dass meine übergeordnete Tabelle einen anderen Zeichensatz hatte als der, den ich erstellt habe.

Elterntabelle (PRODUKTE)

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

Untergeordnete Tabelle, bei der ein Problem aufgetreten ist (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
);

GEÄNDERT AUF

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 
Channaveer Hakari
quelle
1

Mein Problem war, dass ich versucht habe, die Beziehungstabelle vor anderen Tabellen zu erstellen!

Ahmad Mobaraki
quelle
SET foreign_key_checks = 0;
LeeGee
0

Ich hatte einen ähnlichen Fehler beim Erstellen eines Fremdschlüssels in einer Many to Many-Tabelle, in der der Primärschlüssel aus 2 Fremdschlüsseln und einer weiteren normalen Spalte bestand. Ich habe das Problem behoben, indem ich den Namen der referenzierten Tabelle, dh Firma, korrigiert habe, wie im korrigierten Code unten gezeigt:

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
);
iltaf khalid
quelle
0

Ich hatte einen ähnlichen Fehler mit zwei Fremdschlüsseln für verschiedene Tabellen, aber mit denselben Schlüsselnamen! Ich habe Schlüssel umbenannt und der Fehler war verschwunden.

Олег Всильдеревьев
quelle
0

Hatte einen ähnlichen Fehler, aber in meinem Fall fehlte es mir, das pk als auto_increment zu deklarieren.

Nur für den Fall, dass es für jemanden hilfreich sein könnte

Luiz Rolim
quelle
0

Ich habe den gleichen Fehler bekommen. Die Ursache in meinem Fall war:

  1. Ich habe eine Sicherung einer Datenbank über phpmyadmin erstellt, indem ich die gesamte Datenbank kopiert habe.
  2. Ich habe eine neue Datenbank mit demselben Namen erstellt, die die alte Datenbank hatte, und sie ausgewählt.
  3. Ich habe ein SQL-Skript gestartet, um aktualisierte Tabellen und Daten zu erstellen.
  4. Ich habe den Fehler bekommen. Auch wenn ich Foreign_key_checks deaktiviert habe. Obwohl die Datenbank vollständig leer war.

Die Ursache war: Da ich phpmyadmin verwendet habe, um einige Fremdschlüssel in der umbenannten Datenbank zu erstellen, wurden die Fremdschlüssel mit einem Datenbanknamenpräfix erstellt, aber das Datenbanknamenpräfix wurde nicht aktualisiert. Es gab also immer noch Verweise in der Backup-Datenbank, die auf die neu erstellte Datenbank verweisen.

lsblsb
quelle
0

Meine Lösung ist vielleicht etwas peinlich und erzählt die Geschichte, warum Sie manchmal auf das schauen sollten, was Sie vor sich haben, anstatt auf diese Beiträge :)

Ich hatte zuvor einen Forward Engineer ausgeführt, was fehlgeschlagen war. Das bedeutete, dass meine Datenbank bereits einige Tabellen enthielt. Dann habe ich versucht, Fehler bei Fremdschlüsselbeschränkungen zu beheben, um sicherzustellen, dass alles perfekt war, aber es lief gegen die zuvor erstellte Tabellen, so dass es keine Vorherrschaft gab.

DenLilleMand
quelle
0

Eine weitere Ursache für diesen Fehler ist, wenn Ihre Tabellen oder Spalten reservierte Schlüsselwörter enthalten :

Manchmal vergisst man diese.

EssGee
quelle
0

In meinem Fall gab es einen Syntaxfehler, der von der MySQL-Konsole beim Ausführen der Abfrage nicht explizit benachrichtigt wurde. Der SHOW ENGINE INNODB STATUSBefehlsabschnitt LATEST FOREIGN KEY ERRORberichtete jedoch:

  Syntax error close to:

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

Ich musste ein Leerzeichen dazwischen lassen REFERENCESund rolees funktionieren lassen.

vicke4
quelle
0

Für mich war es - Sie können das Präfixieren der aktuellen DB-Tabelle nicht auslassen, wenn Sie eine FK für eine nicht aktuelle DB erstellen, die auf die aktuelle DB verweist:

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

Wenn ich "currrent_db" weglasse. Für die Benutzertabelle erhalte ich den FK-Fehler. Interessant, dass SHOW ENGINE INNODB STATUS; zeigt in diesem Fall nichts.

Bearoff
quelle
-1

Ich hatte das gleiche Problem, dann habe ich den Engine-Namen als Innodb sowohl in der übergeordneten als auch in der untergeordneten Tabelle korrigiert und den Referenzfeldnamen FOREIGN KEY ( c_id) REFERENCES x9o_parent_table( c_id) korrigiert.
Dann funktioniert es einwandfrei und die Tabellen sind korrekt installiert. Dies wird für jemanden voll genutzt.

Subramanian
quelle