MySQL Tidak Dapat Menambahkan Batasan Kunci Asing


314

Jadi saya mencoba untuk menambahkan batasan Foreign Key ke database saya sebagai persyaratan proyek dan itu bekerja pertama atau dua kali pada tabel yang berbeda, tapi saya punya dua tabel yang saya dapatkan kesalahan ketika mencoba menambahkan batasan kunci asing. Pesan kesalahan yang saya dapatkan adalah:

GALAT 1215 (HY000): Tidak dapat menambahkan batasan kunci asing

Ini adalah SQL yang saya gunakan untuk membuat tabel, dua tabel yang menyinggung adalah Patientdan 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;

Jawaban:


779

Untuk menemukan kesalahan spesifik, jalankan ini:

SHOW ENGINE INNODB STATUS;

Dan lihat di LATEST FOREIGN KEY ERRORbagian ini.

Tipe data untuk kolom anak harus sama persis dengan kolom induk. Misalnya, karena medicalhistory.MedicalHistoryIDmerupakan INT, Patient.MedicalHistoryjuga perlu menjadi INT, bukan a SMALLINT.

Selain itu, Anda harus menjalankan kueri set foreign_key_checks=0sebelum menjalankan DDL sehingga Anda dapat membuat tabel dalam urutan acak daripada perlu membuat semua tabel induk sebelum tabel anak yang relevan.


3
Terima kasih, baik inkonsistensi tipe data dan foreign_key_checks memperbaiki masalah ini!
joshuaegclark

30
Disebabkan oleh susunan yang berbeda di atas meja untuk saya, satu adalah UTF-8 dan yang lainnya adalah latin1.
ug_

6
Juga harus memastikan saya telah memeriksa "unsigned" karena ini adalah INT unsigned meskipun jenis dan panjang saya cocok.
timbrown

1
Meja saya secara otomatis dibuat dengan mesin MyISAM! Terima kasih Ike.
Kapten Hypertext

3
Terima kasih. Saya mencoba set nullmenghapus, tetapi kolom itu not null.
Matt

143

Saya telah menetapkan satu bidang sebagai "Tidak Ditandatangani" dan yang lainnya tidak. Setelah saya atur kedua kolom ke Unsigned itu berfungsi.


lol sama. MySQL dapat menggunakan penanganan kesalahan yang lebih tepat pada hal-hal semacam ini.
dave

82
  • Mesinnya harus sama misalnya InnoDB
  • Datatype harus sama, dan dengan panjang yang sama. mis. VARCHAR (20)
  • Collars Colars charset harus sama. mis. Watchout utf8
    : Bahkan jika tabel Anda memiliki Collation yang sama, kolom masih bisa memiliki yang berbeda.
  • Unik - Kunci asing harus merujuk ke bidang yang unik (biasanya kunci utama) dalam tabel referensi.

1
Jawaban Terbaik Pernah, Setelah mencoba hampir semuanya, ternyata saya harus menambahkan secara eksplisit uniqueke kolom tabel referensi meskipun itu adalah Primary Key!!
Yahya

Ya, Jawaban terbaik yang pernah ada ... khususnya poin pertama! Dalam kasus saya, saya melakukan migrasi (memesan 2,5.14 ke bookd 2.7.2), di mana skrip migrasi tidak mengubah mesin database, jadi ketika membuat tabel baru saya mendapatkan kesalahan ini.
Bernhard

Jawab saya juga.
EngineerCoder

Akan lebih luar biasa dengan tips untuk cara memeriksa / mengubah Bagi saya itu adalah perbedaan Collation tingkat kolom (terima kasih atas idenya!) Dan ini memberi saya perbaikan: stackoverflow.com/questions/1294117/…
sjgp

18

Cobalah untuk menggunakan jenis kunci utama yang sama - int (11) - pada kunci asing - smallint (5) - juga.

Semoga ini bisa membantu!


mysql> buat index_bar_id indeks unik di foos (bar_id); ... mysql> alter foo table tambahkan constraint index_bar_id foreign key (bar_id) Reference Bar (id); sixarm.com/about/…
CookieCoder

11

Konfirmasikan bahwa pengkodean dan pengumpulan karakter untuk dua tabel adalah sama.

Dalam kasus saya sendiri, salah satu tabel menggunakan utf8dan yang lainnya menggunakanlatin1 .

Saya punya kasus lain di mana penyandiannya sama tetapi susunannya berbeda. Satuutf8_general_ci lainutf8_unicode_ci

Anda dapat menjalankan perintah ini untuk mengatur penyandian dan susunan tabel.

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Saya harap ini membantu seseorang.


Nice one @ Adegoke, jawaban yang bagus
Edwin Ikechukwu Okonkwo

7

Untuk mengatur KUNCI ASING di Tabel B Anda harus menetapkan KUNCI di tabel A.

Dalam tabel A: INDEX id(id )

Dan kemudian di tabel B,

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

Saya tidak yakin persis apa yang Anda katakan, tetapi saya menemukan bahwa sintaksis saya salah. Saya melakukan: mengubah tabel pesawat menambahkan kendala fk_somehting_unique organisasi referensi kunci asing (operator_id), tetapi seharusnya dilakukan: mengubah tabel pesawat menambahkan batasan fk_somehting_unique organisasi asing kunci (operator_id) referensi (id) ;
Michael Coxon

7

Saya memiliki masalah yang sama dan solusinya sangat sederhana. Solusi: kunci asing yang dideklarasikan dalam tabel tidak boleh diatur menjadi tidak nol.

referensi: Jika Anda menentukan tindakan SET NULL, pastikan Anda belum mendeklarasikan kolom dalam tabel anak sebagai BUKAN NULL. ( ref )


4

Periksa aturan berikut:

  • Pertama, periksa apakah nama diberikan hak untuk nama tabel

  • Jenis data kanan kedua berikan ke kunci asing?


4

Harap pastikan bahwa kedua tabel berada dalam format InnoDB. Bahkan jika seseorang berada dalam format MyISAM, maka, batasan kunci asing tidak akan berfungsi.

Juga, hal lain adalah bahwa kedua bidang harus dari jenis yang sama. Jika satu adalah INT, maka yang lain juga harus INT. Jika satu adalah VARCHAR, yang lain juga harus VARCHAR, dll.


3

Saya menghadapi masalah ini dan dapat menyelesaikannya dengan memastikan bahwa tipe data benar-benar cocok.

Saya menggunakan SequelPro untuk menambahkan kendala dan itu membuat kunci utama tidak ditandai sebagai default.


2

Periksa penandatanganan di kedua kolom tabel Anda. Jika kolom tabel rujukan DITANDATANGANI, kolom tabel referensi juga harus DITANDATANGANI.


1

CATATAN: Tabel berikut ini diambil dari beberapa situs ketika saya melakukan beberapa R&D di database. Jadi konvensi penamaan itu tidak tepat.

Bagi saya, masalahnya adalah, tabel orangtua saya memiliki set karakter yang berbeda dari yang saya buat.

Parent Table (PRODUK)

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

Tabel Anak yang memiliki masalah (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
);

DIUBAH UNTUK

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

Saya memiliki kesalahan serupa dalam membuat kunci asing di tabel Banyak ke Banyak di mana kunci utama terdiri dari 2 kunci asing dan kolom normal lainnya. Saya memperbaiki masalah ini dengan memperbaiki nama tabel yang direferensikan yaitu perusahaan, seperti yang ditunjukkan dalam kode yang diperbaiki di bawah ini:

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

Saya memiliki kesalahan yang sama dengan dua kunci asing untuk tabel yang berbeda tetapi dengan nama kunci yang sama! Saya telah mengganti nama kunci dan kesalahan telah hilang)


0

Punya kesalahan yang sama, tetapi dalam kasus saya saya tidak ada untuk menyatakan pk sebagai auto_increment.

Kalau-kalau itu bisa bermanfaat bagi siapa pun


0

Saya mendapat kesalahan yang sama. Penyebab dalam kasus saya adalah:

  1. Saya membuat cadangan database melalui phpmyadmin dengan menyalin seluruh database.
  2. Saya membuat db baru dengan nama yang sama dengan db lama dan belum memilihnya.
  3. Saya memulai skrip SQL untuk membuat tabel dan data yang diperbarui.
  4. Saya mendapat kesalahan. Juga ketika saya menonaktifkan foreign_key_checks. Meskipun basis data benar-benar kosong.

Penyebabnya adalah: Karena saya menggunakan phpmyadmin untuk membuat beberapa kunci asing di database yang diubah namanya - kunci asing di mana dibuat dengan awalan nama basis data tetapi awalan nama basis data tidak diperbarui. Jadi masih ada referensi di backup-db yang menunjuk ke db yang baru dibuat.


0

Solusi saya mungkin sedikit memalukan dan menceritakan kisah mengapa Anda kadang-kadang harus melihat apa yang ada di depan Anda alih-alih pos-pos ini :)

Saya telah menjalankan seorang insinyur maju sebelumnya, yang gagal, sehingga itu berarti bahwa database saya sudah memiliki beberapa tabel, maka saya telah duduk berusaha untuk memperbaiki kegagalan kunci asing yang berusaha memastikan bahwa semuanya sempurna, tetapi berlari melawan tabel yang sebelumnya dibuat, jadi tidak ada yang menang.


0

Salah satu penyebab tambahan kesalahan ini adalah ketika tabel atau kolom Anda berisi kata kunci yang dipesan :

Terkadang orang melupakan ini.


0

Dalam kasus saya, ada kesalahan sintaksis yang tidak diberitahukan secara eksplisit oleh konsol MySQL saat menjalankan kueri. Namun, bagian SHOW ENGINE INNODB STATUSperintah LATEST FOREIGN KEY ERRORmelaporkan,

  Syntax error close to:

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

Saya harus meninggalkan ruang kosong di antara REFERENCESdan roleuntuk membuatnya bekerja.


0

Bagi saya itu - Anda tidak bisa menghilangkan awalan tabel DB saat ini jika Anda membuat FK untuk DB tidak lancar referensi DB saat ini:

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

Jika saya menghilangkan "currrent_db." untuk tabel pengguna, saya mendapatkan kesalahan FK. Menarik bahwa MENUNJUKKAN STATUS ENGINE INNODB; tidak menunjukkan apa pun dalam hal ini.


-1

Saya memiliki masalah yang sama kemudian saya mengoreksi nama Mesin sebagai Innodb di kedua tabel induk dan anak dan mengoreksi nama bidang referensi KUNCI LUAR NEGERI ( c_id) REFERENSI x9o_parent_table( c_id)
kemudian berfungsi dengan baik dan tabel diinstal dengan benar. Ini akan digunakan penuh untuk seseorang.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.