【问题标题】:MySQL Cannot Add Foreign Key ConstraintMySQL 无法添加外键约束
【发布时间】:2013-03-10 05:19:51
【问题描述】:

所以我试图将外键约束添加到我的数据库作为项目要求,它在不同的表上第一次或两次工作,但是我有两个表在尝试添加外键时出现错误约束。 我得到的错误信息是:

ERROR 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;

【问题讨论】:

    标签: mysql sql foreign-keys


    【解决方案1】:

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

    SHOW ENGINE INNODB STATUS;
    

    并查看LATEST FOREIGN KEY ERROR 部分。

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

    此外,您应该在运行 DDL 之前运行查询 set foreign_key_checks=0,这样您就可以按任意顺序创建表,而无需在相关子表之前创建所有父表。

    【讨论】:

    • 谢谢,数据类型不一致和foreign_key_checks都解决了这个问题!
    • 对我来说是由表上的不同排序规则引起的,一个是 UTF-8,另一个是 latin1。
    • 还必须确保我检查了“无符号”,因为这是一个无符号的 INT,即使我的类型和长度匹配。
    • 我的表是使用 MyISAM 引擎自动创建的!谢谢艾克。
    • 谢谢。我试图删除set null,但该列是not null
    【解决方案2】:

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

    【讨论】:

    • 大声笑一样。 MySQL 可以对这类东西使用更精确的错误处理。
    【解决方案3】:
    • Engine 应该是相同的 e.g. InnoDB
    • Datatype 应该相同,并且具有相同的长度。 例如VARCHAR(20)
    • Collat​​ion 列字符集应该相同。 例如utf8
      注意:即使你的表有相同的排序规则,列仍然可能有不同的排序规则。
    • 唯一 - 外键应该引用引用表中唯一的字段(通常是主键)

    【讨论】:

    • 有史以来最好的答案,在尝试了几乎所有事情之后,结果发现我必须明确地将 unique 添加到引用表列中,即使它是 Primary Key!!
    • 是的,有史以来最好的答案...尤其是第一点!就我而言,我进行了迁移(预订 2.5.14 到预订 2.7.2),其中迁移脚本没有更改数据库引擎,因此在创建新表时出现此错误。
    • 最好也回答我。
    • 如果有关于如何检查/更改的提示会更棒。对我来说,这是列级排序规则的差异(感谢您的想法!),这给了我解决方法:stackoverflow.com/questions/1294117/…
    • 我遇到了数据类型问题。父表上的 ID 具有 BigInt(20),而子表上的列具有 Int(10)。我将 Int(10) 更改为 BigInt(20),然后能够创建外键约束。
    【解决方案4】:

    尝试在外键 - smallint(5) 上使用相同类型的主键 - int(11)

    希望对你有帮助!

    【讨论】:

    • mysql> 在 foos(bar_id) 上创建唯一索引 index_bar_id; ... mysql> alter table foos 添加约束 index_bar_id 外键 (bar_id) 引用 bar (id); sixarm.com/about/…
    【解决方案5】:

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

    在我自己的情况下,其中一张表使用utf8,另一张使用latin1

    我遇到了另一种情况,编码相同但排序规则不同。一个utf8_general_ci 另一个utf8_unicode_ci

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

    ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;
    

    我希望这对某人有所帮助。

    【讨论】:

    • 不错的@Adegoke,很好的答案
    【解决方案6】:

    要在表 B 中设置 FOREIGN KEY,您必须在表 A 中设置 KEY。

    在表 A 中: 索引id (id)

    然后在B表中,

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

    【讨论】:

    • 我不确定你在说什么,但我发现我的语法不正确。我在做:alter table aircraft add constraint fk_somehting_unique foreign key (operator_id) references organizations,但应该做:alter table aircraft add constraint fk_somehting_unique foreign key (operator_id) references organization (id);
    【解决方案7】:

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

    reference :如果您指定 SET NULL 操作,请确保您没有将子表中的列声明为 NOT NULL。 (ref )

    【讨论】:

      【解决方案8】:

      检查以下规则:

      • 首先检查表名是否正确

      • 第二个正确的数据类型给外键?

      【讨论】:

        【解决方案9】:

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

        另外,另一件事是,两个字段应该是相同的类型。如果一个是 INT,那么另一个也应该是 INT。如果一个是VARCHAR,另一个也应该是VARCHAR等。

        【讨论】:

          【解决方案10】:

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

          我使用 SequelPro 添加约束,它使主键默认为无符号。

          【讨论】:

            【解决方案11】:

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

            【讨论】:

              【解决方案12】:

              我的问题是我试图在其他表之前创建关系表!

              所以你有两种方法可以解决它:

              • 更改 MSQL 命令的顺序

              • 在查询之前运行它:

                SET foreign_key_checks = 0;

              【讨论】:

              • SET foreign_key_checks = 0;
              【解决方案13】:

              注意:以下表格是我在做的时候从某个网站获取的 数据库上的一些研发。所以命名约定是不合适的。

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

              父表(产品)

              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 
              

              【讨论】:

                【解决方案14】:

                此错误的另一个原因是您的表或列包含保留的keywords

                有时确实会忘记这些。

                【讨论】:

                  【解决方案15】:

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

                  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
                  );
                  

                  【讨论】:

                    【解决方案16】:

                    我对不同表的两个外键有类似的错误,但键名相同!我已经重命名了键并且错误消失了)

                    【讨论】:

                      【解决方案17】:

                      有类似的错误,但在我的情况下,我没有将 pk 声明为 auto_increment。

                      以防万一它对任何人都有帮助

                      【讨论】:

                        【解决方案18】:

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

                        1. 我通过 phpmyadmin 通过复制整个数据库创建了一个数据库备份。
                        2. 我创建了一个与旧数据库同名的新数据库,但未选择它。
                        3. 我启动了一个 SQL 脚本来创建更新的表和数据。
                        4. 我收到了错误。此外,当我禁用 foreign_key_checks 时。尽管数据库完全是空的。

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

                        【讨论】:

                          【解决方案19】:

                          我的解决方案可能有点尴尬,它讲述了为什么有时应该看看你面前的东西而不是这些帖子:)

                          我之前运行过一个正向工程师,但失败了,这意味着我的数据库已经有几个表,然后我一直在尝试修复外键约束失败,试图确保一切都很完美,但是它运行了与之前创建的表格相比,因此无法取胜。

                          【讨论】:

                            【解决方案20】:

                            在我的例子中,有一个语法错误,在运行查询时 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 之间留一个空格才能使其正常工作。

                            【讨论】:

                              【解决方案21】:

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

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

                              如果我省略“current_db”。对于用户表,我收到 FK 错误。有趣的是 SHOW ENGINE INNODB STATUS;在这种情况下不显示任何内容。

                              【讨论】:

                                【解决方案22】:

                                我的解决方案!!

                                如果我们想让table1的column1作为table2的外键,那么column1应该是table1的key。

                                例如,假设我们有departments 表,其中有dept_id 列。

                                现在假设我们有另一个名为 employees 的表,其中包含 emp_dept_id 列。

                                如果我们想使用department 表的dept_id 列作为empemp_dept_id 列的外键,那么department 表的dept_id 应该至少是 如果不是主键,则为键。

                                因此,在将dept_iddepratment 用作另一个表的外键之前,请确保它是主键或唯一键。

                                【讨论】:

                                  【解决方案23】:

                                  如果您在使用 PhpMyAdmin 时遇到此错误,请在导入 SQL 文件之前禁用外键检查。

                                  【讨论】:

                                    【解决方案24】:

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

                                    【讨论】:

                                      猜你喜欢
                                      • 2021-11-05
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 2014-07-27
                                      • 2015-02-04
                                      相关资源
                                      最近更新 更多