MySQL nie może dodać ograniczenia klucza obcego

314

Próbuję więc dodać ograniczenia klucza obcego do mojej bazy danych jako wymóg projektu i zadziałało to po raz pierwszy lub dwa na różnych tabelach, ale mam dwie tabele, w których pojawia się błąd podczas próby dodania ograniczeń klucza obcego. Otrzymany komunikat o błędzie to:

BŁĄD 1215 (HY000): Nie można dodać ograniczenia klucza obcego

To jest SQL, którego używam do tworzenia tabel, dwie tabele obrażające to Patienti 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;
joshuaegclark
źródło

Odpowiedzi:

778

Aby znaleźć konkretny błąd, uruchom to:

SHOW ENGINE INNODB STATUS;

I spójrz w LATEST FOREIGN KEY ERRORdziale.

Typ danych dla kolumny podrzędnej musi być dokładnie zgodny z kolumną nadrzędną. Na przykład, skoro medicalhistory.MedicalHistoryIDjest INT, Patient.MedicalHistorymusi być również INT, a nie SMALLINT.

Ponadto należy uruchomić zapytanie set foreign_key_checks=0przed uruchomieniem DDL, aby można było tworzyć tabele w dowolnej kolejności, zamiast konieczności tworzenia wszystkich tabel nadrzędnych przed odpowiednimi tabelami podrzędnymi.

Ike Walker
źródło
3
Dzięki, zarówno niespójność typu danych, jak i Foreign_key_checks naprawiły problem!
joshuaegclark
30
Powodowało to dla mnie inne zestawienie na tabelach, jeden to UTF-8, a drugi to latin1.
ug_
6
Musiałem także upewnić się, że zaznaczyłem opcję „unsigned”, ponieważ była to INT bez znaku, mimo że moje typy i długość były zgodne.
timbrown
1
Moje tabele były tworzone automatycznie za pomocą silnika MyISAM! Dzięki, Ike.
Kapitan Hypertext
3
Dzięki. Próbowałem set nullusunąć, ale kolumna była not null.
Matt
142

Ustawiłem jedno pole jako „Niepodpisane”, a drugie nie. Po ustawieniu obu kolumn jako Niepodpisane zadziałało.

Satsara Gunaratne
źródło
lol to samo. MySQL może używać bardziej precyzyjnej obsługi błędów w tego typu rzeczach.
dave
81
  • Silnik powinien być taki sam, np. InnoDB
  • Typ danych powinien być taki sam i mieć tę samą długość. np. VARCHAR (20)
  • Zestaw znaków w kolumnach sortowania powinien być taki sam. np. utf8
    Watchout: nawet jeśli twoje tabele mają to samo sortowanie, kolumny nadal mogą mieć inne.
  • Unikalny - klucz obcy powinien odnosić się do pola, które jest unikalne (zwykle klucz podstawowy) w tabeli referencyjnej.
am0wa
źródło
1
Najlepsza odpowiedź: po wypróbowaniu prawie wszystkiego okazało się, że muszę wyraźnie dodać uniquekolumnę tabeli referencyjnej, mimo że jest to Primary Key!!
Yahya
Tak, najlepsza odpowiedź w historii ... szczególnie pierwszy punkt! W moim przypadku dokonałem migracji (zarezerwowałem 2.5.14 do rezerwacji 2.7.2), gdzie skrypt migracji nie zmienił silnika bazy danych, więc podczas tworzenia nowych tabel dostałem ten błąd.
Bernhard
Najlepiej też mi odpowiedz.
EngineerCoder,
Byłoby jeszcze bardziej niesamowite ze wskazówkami, jak sprawdzać / zmieniać. Dla mnie była to różnica w sortowaniu na poziomie kolumny (dzięki za pomysł!), Co dało mi poprawkę: stackoverflow.com/questions/1294117/…
sjgp
18

Spróbuj użyć tego samego typu kluczy podstawowych - int (11) - na kluczach obcych - smallint (5) - a także.

Mam nadzieję, że to pomoże!

Felypp Oliveira
źródło
mysql> utwórz unikalny indeks index_bar_id na foos (bar_id); ... mysql> zmień tablice foos dodaj ograniczenie index_bar_id klucz obcy (bar_id) odwołania bar (id); sixarm.com/about/…
CookieCoder
11

Sprawdź, czy kodowanie i sortowanie znaków dla dwóch tabel jest takie samo.

W moim przypadku jedna z tabel używała, utf8a druga używała latin1.

Miałem inny przypadek, w którym kodowanie było takie samo, ale sortowanie różne. Jeden utf8_general_cidrugiutf8_unicode_ci

Możesz uruchomić to polecenie, aby ustawić kodowanie i sortowanie dla tabeli.

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Mam nadzieję, że to komuś pomoże.

Goke Obasa
źródło
Fajny @Adegoke, świetna odpowiedź
Edwin Ikechukwu Okonkwo
7

Aby ustawić KLUCZ ZAGRANICZNY w tabeli B, należy ustawić KLUCZ w tabeli A.

W tabeli A: INDEKS id( id)

A potem w tabeli B

CONSTRAINT `FK_id` FOREIGN KEY (`id`) REFERENCES `table-A` (`id`)
użytkownik3707075
źródło
nie jestem pewien, co dokładnie mówisz, ale stwierdziłem, że moja składnia była niepoprawna. Robiłem: zmieniłem tabelę samolotów dodałem ograniczenie fk_somehting_unique referencje organizacji klucz obcy (operator_id), ale powinienem było zrobić: zmieniłem tabelę samolotów dodaj ograniczenie fk_somehting_unique referencje organizacja klucz obcy (id_operatora ) ;
Michael Coxon
7

Miałem ten sam problem, a rozwiązanie było bardzo proste. Rozwiązanie: klucze obce zadeklarowane w tabeli nie powinny mieć wartości innej niż NULL.

referencja: Jeśli określisz akcję SET NULL, upewnij się, że kolumny w tabeli potomnej nie zostały zadeklarowane jako NOT NULL. ( ref )

Singh
źródło
4

Sprawdź następujące zasady:

  • Najpierw sprawdza, czy nazwy są poprawnie nadane dla nazw tabel

  • Drugi właściwy typ danych podać kluczowi obcemu?

Bhaskar Bhatt
źródło
4

Upewnij się, że obie tabele są w formacie InnoDB. Nawet jeśli jest w formacie MyISAM, ograniczenie klucza obcego nie zadziała.

Inną rzeczą jest to, że oba pola powinny być tego samego typu. Jeśli jeden jest INT, to drugi powinien być również INT. Jeśli jednym jest VARCHAR, drugim powinien być również VARCHAR itp.

Vijay Srinivas
źródło
3

Napotkałem problem i udało mi się go rozwiązać, upewniając się, że typy danych są dokładnie zgodne.

Użyłem SequelPro do dodania ograniczenia i domyślnie sprawiał, że klucz podstawowy był bez znaku.

Uczeń
źródło
2

Sprawdź podpisywanie w obu kolumnach tabeli. Jeśli kolumna tabeli odsyłającej jest ZNAKIEM, kolumna tabeli referencyjnej również powinna zostać ZNAKOWANA.

katwekibs
źródło
1

UWAGA: Poniższe tabele zostały zaczerpnięte z niektórych witryn, kiedy przeprowadzałem badania i rozwój bazy danych. Zatem konwencja nazewnictwa jest nieprawidłowa.

Dla mnie problem polegał na tym, że moja tabela nadrzędna miała inny zestaw znaków niż ten, który tworzyłem.

Stolik nadrzędny (PRODUKTY)

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

Stolik podrzędny, który miał problem (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
);

ZMODYFIKOWANY DO

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
źródło
1

Mój problem polegał na tym, że próbowałem utworzyć tabelę relacji przed innymi tabelami!

Ahmad Mobaraki
źródło
SET foreign_key_checks = 0;
LeeGee,
0

Miałem podobny błąd podczas tworzenia klucza obcego w tabeli Wiele do wielu, gdzie klucz podstawowy składał się z 2 kluczy obcych i innej normalnej kolumny. Rozwiązałem problem, poprawiając nazwę tabeli, do której istnieje odwołanie, tj. Firmę, jak pokazano w poprawionym kodzie poniżej:

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
źródło
0

Miałem podobny błąd z dwoma kluczami obcymi dla różnych tabel, ale o tych samych nazwach kluczy! Zmieniłem nazwy kluczy i błąd zniknął)

Олег Всильдеревьев
źródło
0

Miałem podobny błąd, ale w moim przypadku brakowało mi zadeklarowania pk jako auto_increment.

Na wszelki wypadek może być pomocny dla każdego

Luiz Rolim
źródło
0

Mam ten sam błąd. Przyczyną w moim przypadku było:

  1. Utworzyłem kopię zapasową bazy danych przez phpmyadmin, kopiując całą bazę danych.
  2. Utworzyłem nowy db o tej samej nazwie, co poprzedni db i go wybrał.
  3. Uruchomiłem skrypt SQL do tworzenia zaktualizowanych tabel i danych.
  4. Dostałem błąd. Również, gdy wyłączyłem opcję Foreign_key_checks. Baza danych była jednak całkowicie pusta.

Przyczyna była taka: odkąd użyłem phpmyadmin do utworzenia niektórych kluczy obcych w bazie danych o zmienionej nazwie - klucze obce zostały utworzone z prefiksem nazwy bazy danych, ale prefiks nazwy bazy danych nie został zaktualizowany. Tak więc w kopii zapasowej db nadal znajdowały się odwołania wskazujące na nowo utworzony db.

lsblsb
źródło
0

Moje rozwiązanie jest może trochę zawstydzające i opowiada, dlaczego zamiast tych postów powinieneś czasem spojrzeć na to, co masz przed sobą :)

Wcześniej prowadziłem inżyniera do przodu, co nie powiodło się, więc oznaczało to, że moja baza danych miała już kilka tabel, a następnie siedziałem, próbując naprawić błędy związane z kluczami obcymi, próbując upewnić się, że wszystko jest idealne, ale działało przeciwko wcześniej utworzone tabele, więc nie przeważyło.

DenLilleMand
źródło
0

Dodatkową przyczyną tego błędu jest sytuacja, gdy tabele lub kolumny zawierają zastrzeżone słowa kluczowe :

Czasami zapomina się o nich.

EssGee
źródło
0

W moim przypadku wystąpił błąd składniowy, który nie został jawnie powiadomiony przez konsolę MySQL po uruchomieniu zapytania. Jednak sekcja SHOW ENGINE INNODB STATUSpolecenia LATEST FOREIGN KEY ERRORzgłoszona,

  Syntax error close to:

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

Musiałem zostawić spację między REFERENCESi, roleaby działało.

vicke4
źródło
0

Dla mnie tak było - nie można pominąć prefiksu bieżącej tabeli DB, jeśli utworzysz FK dla trwałej bazy danych odwołującej się do bieżącej bazy danych:

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

Jeśli pominę „currrent_db”. dla tabeli użytkowników pojawia się błąd FK. Interesujące, że POKAŻ STATUS INNODB SILNIKA; nic nie pokazuje w tym przypadku.

ofiarować
źródło
-1

Miałem ten sam problem, a następnie poprawiłem nazwę silnika jako Innodb zarówno w tabelach nadrzędnych, jak i podrzędnych oraz poprawiłem nazwę pola referencyjnego c_idODNOŚNIKI KLUCZA OBCYCH x9o_parent_table( c_id),
a następnie działa poprawnie i tabele są poprawnie zainstalowane. Będzie to pełne wykorzystanie dla kogoś.

subramanian
źródło