MySQL không thể thêm ràng buộc khóa ngoại


314

Vì vậy, tôi đang cố gắng thêm các ràng buộc Khóa ngoài vào cơ sở dữ liệu của mình như một yêu cầu của dự án và nó đã hoạt động lần đầu tiên hoặc hai trên các bảng khác nhau, nhưng tôi có hai bảng mà tôi gặp lỗi khi cố gắng thêm các ràng buộc khóa ngoài. Thông báo lỗi mà tôi nhận được là:

LRI 1215 (HY000): Không thể thêm ràng buộc khóa ngoại

Đây là SQL tôi đang sử dụng để tạo các bảng, hai bảng vi phạm là PatientAppointment.

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;

Câu trả lời:


779

Để tìm lỗi cụ thể chạy này:

SHOW ENGINE INNODB STATUS;

Và nhìn vào LATEST FOREIGN KEY ERRORphần.

Kiểu dữ liệu cho cột con phải khớp chính xác với cột cha. Ví dụ, vì medicalhistory.MedicalHistoryIDlà một INT, Patient.MedicalHistorycũng cần phải là một INT, không phải là một SMALLINT.

Ngoài ra, bạn nên chạy truy vấn set foreign_key_checks=0trước khi chạy DDL để bạn có thể tạo các bảng theo thứ tự tùy ý thay vì cần tạo tất cả các bảng cha trước các bảng con có liên quan.


3
Cảm ơn, cả hai kiểu dữ liệu không nhất quán và Foreign_key_checks đã khắc phục sự cố!
joshuaegclark

30
Được gây ra bởi một đối chiếu khác nhau trên các bảng đối với tôi, một là UTF-8 và cái kia là latin1.
ug_

6
Cũng phải đảm bảo rằng tôi đã kiểm tra "không dấu" vì đây là INT không dấu mặc dù các loại và độ dài của tôi khớp.
âm sắc

1
Các bảng của tôi đã tự động được tạo bằng công cụ MyISAM! Cảm ơn Ike.
Thuyền trưởng Hypertext

3
Cảm ơn. Tôi đã cố gắng để set nullxóa, nhưng cột là not null.
Matt

142

Tôi đã đặt một trường là "Chưa ký" và trường khác thì không. Khi tôi đặt cả hai cột thành Chưa ký, nó hoạt động.


lol giống nhau MySQL có thể sử dụng xử lý lỗi chính xác hơn đối với loại công cụ này.
dave

82
  • Công cụ nên giống nhau, ví dụ như InnoDB
  • Datatype nên giống nhau, và có cùng độ dài. ví dụ: VARCHAR (20)
  • Collation Cột charset nên giống nhau. ví dụ: Watchf utf8
    : Ngay cả khi các bảng của bạn có cùng Collation, các cột vẫn có thể có một bảng khác nhau.
  • Duy nhất - Khóa ngoại phải tham chiếu đến trường duy nhất (thường là khóa chính) trong bảng tham chiếu.

1
Câu trả lời hay nhất từ ​​trước đến giờ, sau khi thử hầu hết mọi thứ, hóa ra tôi phải thêm uniquevào cột bảng tham chiếu một cách rõ ràng mặc dù đó là một Primary Key!!
Yahya

Vâng, câu trả lời hay nhất từng có ... đặc biệt là điểm đầu tiên! Trong trường hợp của tôi, tôi đã thực hiện di chuyển (đã đặt 2.5,14 đến book 2.7.2), trong đó tập lệnh di chuyển không thay đổi công cụ cơ sở dữ liệu, vì vậy khi tạo bảng mới tôi gặp lỗi này.
Bernhard

Tốt nhất trả lời tôi quá.
EngineeringCoder

Sẽ còn tuyệt vời hơn nữa với các mẹo để kiểm tra / thay đổi. Đối với tôi, đó là sự khác biệt Collation ở cấp độ cột (cảm ơn vì ý tưởng!) Và điều này đã cho tôi cách khắc phục: stackoverflow.com/questions/1294117/
Kẻ

18

Cố gắng sử dụng cùng loại khóa chính của bạn - int (11) - trên các khóa ngoại - smallint (5) -.

Hy vọng nó giúp!


mysql tạo chỉ mục duy nhất index_bar_id trên foos (bar_id); ... mysql thay đổi foos bảng thêm ràng buộc index_bar_id thanh tham chiếu khóa ngoài (bar_id) (id); sixarm.com/about/ Kẻ
CookieCoder 17/12/13

11

Xác nhận rằng mã hóa ký tự và đối chiếu cho hai bảng là như nhau.

Trong trường hợp của riêng tôi, một trong các bảng đang sử dụng utf8và bảng còn lại đang sử dụng latin1.

Tôi đã có một trường hợp khác trong đó mã hóa là như nhau nhưng đối chiếu khác nhau. Một utf8_general_cicái khácutf8_unicode_ci

Bạn có thể chạy lệnh này để đặt mã hóa và đối chiếu cho một bảng.

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Tôi hi vọng điêu nay se giup được ai đo.


Một điều tuyệt vời @Adegoke, câu trả lời tuyệt vời
Edwin Ikechukwu Okonkwo

7

Để đặt KEY NGOẠI TỆ trong Bảng B, bạn phải đặt KEY trong bảng A.

Trong bảng A: INDEX id( id)

Và sau đó trong bảng B,

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

Tôi không chắc chính xác những gì bạn đang nói, nhưng tôi thấy rằng cú pháp của tôi không chính xác. Tôi đã thực hiện: thay đổi tổ chức tham chiếu khóa ngoài fk_somehting_unique (toán tử_id), nhưng nên thực hiện: thay đổi máy bay bảng thêm ràng buộc fk_somehting_unique tổ chức tham chiếu khóa (id) ;
Michael Coxon

7

Tôi đã có cùng một vấn đề và giải pháp rất đơn giản. Giải pháp: khóa ngoại được khai báo trong bảng không được đặt thành không rỗng.

tham khảo: Nếu bạn chỉ định một hành động SET NULL, hãy đảm bảo rằng bạn chưa khai báo các cột trong bảng con là KHÔNG NULL. (tham khảo )


4

Kiểm tra các quy tắc sau:

  • Trước tiên hãy kiểm tra xem tên có được đặt đúng cho tên bảng không

  • Kiểu dữ liệu thứ hai đúng cho khóa ngoại?


4

Vui lòng đảm bảo rằng cả hai bảng đều ở định dạng InnoDB. Ngay cả khi một trong các định dạng MyISAM, thì ràng buộc khóa ngoại sẽ không hoạt động.

Ngoài ra, một điều nữa là, cả hai trường phải cùng loại. Nếu một cái là INT, thì cái kia cũng phải là INT. Nếu một là VARCHAR, thì cái kia cũng phải là VARCHAR, v.v.


3

Tôi đã đối mặt với vấn đề này và có thể giải quyết nó bằng cách đảm bảo rằng các kiểu dữ liệu khớp chính xác.

Tôi đã sử dụng SequelPro để thêm các ràng buộc và nó đang làm cho khóa chính là không dấu theo mặc định.


2

Kiểm tra ký trên cả hai cột bảng của bạn. Nếu cột bảng tham chiếu được KÝ, thì cột bảng được tham chiếu cũng phải được ký.


1

LƯU Ý: Các bảng sau được lấy từ một số trang web khi tôi đang thực hiện một số R & D trên cơ sở dữ liệu. Vì vậy, quy ước đặt tên là không đúng.

Đối với tôi, vấn đề là, bảng cha mẹ của tôi có bộ ký tự khác với bảng mà tôi đang tạo.

Bảng phụ huynh (SẢN PHẨM)

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

Bảng con có vấn đề (GIÁE_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
);

SỬA ĐỔI

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

Vấn đề của tôi là tôi đã cố gắng tạo bảng quan hệ trước các bảng khác!


SET foreign_key_checks = 0;
LeeGee

0

Tôi đã gặp một lỗi tương tự trong việc tạo khóa ngoại trong bảng Many to Many trong đó khóa chính bao gồm 2 khóa ngoại và một cột bình thường khác. Tôi đã khắc phục sự cố bằng cách sửa tên bảng được tham chiếu tức là công ty, như được hiển thị trong mã được sửa dưới đây:

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

Tôi đã có lỗi tương tự với hai khóa ngoại cho các bảng khác nhau nhưng có cùng tên khóa! Tôi đã đổi tên khóa và lỗi đã biến mất)


0

Có một lỗi tương tự, nhưng trong trường hợp của tôi, tôi đã thiếu để khai báo pk là auto_increment.

Chỉ trong trường hợp nó có thể hữu ích cho bất cứ ai


0

Tôi đã nhận được cùng một lỗi. Nguyên nhân trong trường hợp của tôi là:

  1. Tôi đã tạo một bản sao lưu cơ sở dữ liệu thông qua phpmyadmin bằng cách sao chép toàn bộ cơ sở dữ liệu.
  2. Tôi đã tạo một db mới có cùng tên mà db cũ đã không chọn nó.
  3. Tôi đã bắt đầu một tập lệnh SQL để tạo các bảng và dữ liệu cập nhật.
  4. Tôi đã nhận được lỗi. Ngoài ra khi tôi vô hiệu hóa Foreign_key_checks. Cơ sở dữ liệu hoàn toàn trống rỗng.

Nguyên nhân là do tôi đã sử dụng phpmyadmin để tạo một số khóa ngoại trong cơ sở dữ liệu được đổi tên - các khóa ngoại được tạo bằng tiền tố tên cơ sở dữ liệu nhưng tiền tố tên cơ sở dữ liệu không được cập nhật. Vì vậy, vẫn còn các tham chiếu trong db sao lưu trỏ đến db mới được tạo.


0

Giải pháp của tôi có lẽ hơi xấu hổ và kể câu chuyện về lý do tại sao đôi khi bạn nên nhìn vào những gì bạn có trước mặt thay vì những bài đăng này :)

Tôi đã chạy một kỹ sư tiền phương trước đó, nhưng không thành công, vì vậy điều đó có nghĩa là cơ sở dữ liệu của tôi đã có một vài bảng, sau đó tôi đang cố gắng khắc phục các lỗi chống khóa ngoại, cố gắng đảm bảo rằng mọi thứ đều hoàn hảo, nhưng nó đã chạy ngược lại các bảng được tạo trước đó, vì vậy nó không thắng thế.


0

Một nguyên nhân bổ sung của lỗi này là khi các bảng hoặc cột của bạn chứa các từ khóa dành riêng :

Đôi khi người ta quên mất những điều này.


0

Trong trường hợp của tôi, có một lỗi cú pháp không được thông báo rõ ràng bởi bảng điều khiển MySQL khi chạy truy vấn. Tuy nhiên, phần SHOW ENGINE INNODB STATUScủa lệnh đã LATEST FOREIGN KEY ERRORbáo cáo,

  Syntax error close to:

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

Tôi đã phải để lại một khoảng trắng giữa REFERENCESroleđể làm cho nó hoạt động.


0

Đối với tôi đó là - bạn không thể bỏ qua tiền tố bảng DB hiện tại nếu bạn tạo FK cho DB không hiện tại tham chiếu DB hiện tại:

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

Nếu tôi bỏ qua "currentrent_db." đối với bảng người dùng, tôi nhận được lỗi FK. Điều thú vị là SHOW Engine INNODB STATUS; cho thấy không có gì trong trường hợp này.


-1

Tôi đã gặp vấn đề tương tự sau đó tôi đã sửa tên Engine là Innodb trong cả hai bảng cha và con và sửa tên trường tham chiếu FOREIGN KEY ( c_id) TÀI LIỆU THAM KHẢO x9o_parent_table( c_id)
sau đó nó hoạt động tốt và các bảng được cài đặt chính xác. Điều này sẽ được sử dụng đầy đủ cho một ai đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.