关于sql:MySQL无法添加外键约束

MySQL Cannot Add Foreign Key Constraint

因此,我正试图将外键约束作为一个项目需求添加到我的数据库中,它第一次或两次在不同的表上工作,但是我有两个表,当试图添加外键约束时,在这两个表上会出现错误。我得到的错误消息是:

ERROR 1215 (HY000): Cannot add foreign key constraint

这是我用来创建表的SQL,两个有问题的表是PatientAppointment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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;

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

看一下LATEST FOREIGN KEY ERROR部分。

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

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


我设置了一个字段为"unsigned",而另一个字段不是。一旦我将这两列都设置为无符号,它就工作了。


  • 发动机应相同,例如InnoDB
  • 数据类型应相同,且长度相同。例如varchar(20)
  • 排序规则列的字符集应相同。例如UTF8注意:即使您的表具有相同的排序规则,列也可能具有不同的排序规则。
  • 唯一-外键应引用引用引用表中唯一(通常是主键)的字段。


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

希望它有帮助!


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

在我自己的例子中,其中一个表使用utf8,另一个表使用latin1

我有另一个例子,编码相同,但排序规则不同。一个是utf8_general_ci,另一个是utf8_unicode_ci

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

1
ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

我希望这能帮助别人。


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

表A:指数id(id)

然后在B表中,

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


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

引用:如果指定了set null操作,请确保没有将子表中的列声明为not null。(参考文献))


请确保这两个表都是InnoDB格式。即使其中一个是myisam格式,那么,外键约束也不会起作用。

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


检查以下规则:

  • 首先检查是否为表名赋予了正确的名称

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


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

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


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


我也犯了同样的错误。在我的案例中,原因是:

  • 我通过phpmyadmin复制整个数据库创建了一个数据库备份。
  • 我创建了一个新数据库,名称与旧数据库所选名称相同。
  • 我启动了一个SQL脚本来创建更新的表和数据。
  • 我弄错了。当我禁用了外置钥匙检查时。尽管数据库是完全空的。
  • 原因是:因为我使用phpmyadmin在重命名的数据库中创建了一些外键-使用数据库名称前缀创建但未更新数据库名称前缀的外键。所以备份数据库中仍然有指向新创建的数据库的引用。


    NOTE: The following tables were taken from some site when I was doing
    some R&D on the database. So the naming convention is not proper.

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

    父表(产品)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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

    有问题的子表(价格日志)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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
    );

    修改为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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

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

    我以前曾运行过一个转发工程师,但失败了,这意味着我的数据库已经有几个表了,然后我一直坐在那里试图修复外键约束失败,试图确保一切都是完美的,但它与以前创建的表不符,所以它无法获胜。


    有一个类似的错误,但在我的例子中,我没有声明pk为自动增量。

    以防对任何人都有帮助


    对于不同的表,但具有相同的键名的两个外键,我也有类似的错误!我已重命名密钥,错误已消失)


    此错误的另一个原因是当表或列包含保留关键字时:

    有时人们会忘记这些。


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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
    );

    在我的例子中,有一个语法错误,MySQL控制台在运行查询时没有明确通知它。但是,SHOW ENGINE INNODB STATUS司令部的LATEST FOREIGN KEY ERROR科报告,

    1
    2
    3
      Syntax error close to:

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

    我不得不在REFERENCESrole之间留一个空白,以使它起作用。


    我有同样的问题,然后在父表和子表中更正了与innodb相同的引擎名,并更正了引用字段名。外键(c_id引用x9o_parent_table(c_id)然后工作正常,工作台安装正确。这将对某人完全使用。