MySQL无法添加外键约束


314

因此,我作为项目需求试图将外键约束添加到数据库中,并且它第一次或在两个不同的表上运行,但是在尝试添加外键约束时,我在两个表上遇到了错误。我收到的错误消息是:

错误1215(HY000):无法添加外键约束

这是我用来创建表的SQL,两个有问题的表是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;

Answers:


778

要查找特定错误,请运行以下命令:

SHOW ENGINE INNODB STATUS;

并查看该LATEST FOREIGN KEY ERROR部分。

子列的数据类型必须与父列完全匹配。例如,由于medicalhistory.MedicalHistoryIDINTPatient.MedicalHistory也需要是INT,而不是SMALLINT

另外,您应该set foreign_key_checks=0在运行DDL之前运行查询,以便可以以任意顺序创建表,而不需要在相关子表之前创建所有父表。


3
谢谢,数据类型不一致和foreign_key_checks都解决了该问题!
joshuaegclark

30
对我来说,这是由于表上的排序规则不同所致,一个是UTF-8,另一个是latin1。
2015年

6
还必须确保我检查了“ unsigned”,因为这是一个无符号的INT,即使我的类型和长度都匹配。
timbrown

1
我的表是使用MyISAM引擎自动创建的!谢谢艾克。
Captain Hypertext

3
谢谢。我试图set null删除,但该列为not null
马特

142

我已将一个字段设置为“未签名”,而另一字段则未设置。将两列都设置为“无符号”后,它就起作用了。


大声笑一样。MySQL可以在这种情况下使用更精确的错误处理。
dave

81
  • 引擎应该是相同的,例如InnoDB
  • 数据类型应该相同,并且长度相同。例如VARCHAR(20)
  • 排序规则列的字符集应该相同。例如utf8
    监视:即使您的表具有相同的排序规则,列仍可以具有不同的排序规则。
  • 唯一 -外键应引用参考表中唯一的字段(通常是主键)

1
有史以来最好的答案,在尝试了几乎所有内容之后,事实证明我必须显式添加unique到参考表列中,即使它是Primary Key!!
Yahya

是的,有史以来最好的答案...尤其是第一点!在我的情况下,我进行了迁移(从2.5.14预订到2.7.2预订),其中迁移脚本没有更改数据库引擎,因此在创建新表时遇到此错误。
伯恩哈德'18

最好也回答我。
EngineerCoder

关于如何检查/更改的提示将更加出色。对我来说,这是列级排序规则的区别(感谢您的想法!),这给了我解决方法:stackoverflow.com/questions/1294117/…–
sjgp


11

确认两个表的字符编码和排序规则相同。

就我自己而言,其中一个表正在使用utf8,另一个表正在使用latin1

我还有另一种情况,其中编码是相同的,但排序规则不同。一个utf8_general_ci另一个utf8_unicode_ci

您可以运行此命令来设置表的编码和排序规则。

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

我希望这可以帮助别人。


好人@Adegoke,好答案
Edwin Ikechukwu Okonkwo

7

要在表B中设置外键,必须在表A中设置键。

在表A中:INDEX idid

然后在表B中,

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

我不确定您到底在说什么,但我发现我的语法不正确。我正在做:更改表飞机添加约束fk_somehting_unique外键(operator_id)引用组织,但应该做的事:更改表飞机添加约束fk_somehting_unique外键(operator_id)引用组织(id)
Michael Coxon

7

我有同样的问题,解决方案非常简单。解决方案:表中声明的外键不应设置为非null。

reference:如果指定SET NULL操作,请确保尚未将子表中的列声明为NOT NULL。(参考



4

请确保两个表均为InnoDB格式。即使采用MyISAM格式,外键约束也不起作用。

另外,另一件事是,两个字段应为同一类型。如果一个是INT,则另一个也应该是INT。如果一个是VARCHAR,则另一个也应该是VARCHAR,依此类推。


3

我遇到了这个问题,并能够通过确保数据类型完全匹配来解决它。

我使用SequelPro添加约束,并且默认情况下使主键设置为unsigned。


2

检查两个表列上的签名。如果引用表列为SIGNED,则引用表列也应为SIGNED。


1

注意:下表是我在数据库上进行一些研发时从某个站点获取的。因此,命名约定不合适。

对我来说,问题是,我的父表的字符集与我正在创建的字符集不同。

父表(产品)

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

子表出现问题(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
);

修改为

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

在“多对多”表中创建外键时,我遇到了类似的错误,该表的主键由2个外键和另一个普通列组成。我通过更正引用的表名即company来解决此问题,如下面的更正代码所示:

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

我遇到了同样的错误。我的原因是:

  1. 我通过复制整个数据库通过phpmyadmin创建了数据库备份。
  2. 我创建了一个新数据库,名称与旧数据库相同,并且已选择它。
  3. 我启动了一个SQL脚本来创建更新的表和数据。
  4. 我得到了错误。另外,当我禁用foreign_key_checks时。虽然数据库完全是空的。

原因是:由于我使用phpmyadmin在重命名的数据库中创建了一些外键-使用数据库名称前缀创建的外键,但数据库名称前缀未更新。因此,backup-db中仍然有指向新创建的数据库的引用。


0

我的解决方案可能有点尴尬,并讲述了一个故事,为什么您有时应该看看自己面前的东西,而不是这些帖子:)

之前我曾经运行过一个前向工程师,但是失败了,所以这意味着我的数据库已经有几个表,然后我一直在尝试解决外键约束失败,试图确保所有内容都是完美的,但是却与以前创建的表,所以这并不占优势。



0

就我而言,存在语法错误,运行查询时MySQL控制台未明确通知该错误。但是,SHOW ENGINE INNODB STATUS指挥部LATEST FOREIGN KEY ERROR报告说,

  Syntax error close to:

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

我必须在两者之间留出空白REFERENCESrole使其正常运行。


0

对我来说是-如果您为引用当前数据库的非当前数据库创建FK,则不能忽略当前数据库表的前缀:

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

如果我省略“ currrent_db”。对于用户表,我得到FK错误。有趣的是,显示引擎的INNODB状态;在这种情况下什么也不显示。


-1

我遇到了同样的问题,然后在父表和子表中都将引擎名称更正为Innodb,并更正了引用字段名称FOREIGN KEY(c_id)REFERENCES x9o_parent_tablec_id),
然后它可以正常工作并且表已正确安装。这将对某人完全使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.