外键约束失败

时间:2012-01-23 18:28:37

标签: php mysql database

我有以下表格:

CREATE TABLE IF NOT EXISTS `Person_Categories` (
  `PrsCatID` int(11) NOT NULL auto_increment,
  `PrsCategory` varchar(45) NOT NULL,
  PRIMARY KEY  (`PrsCatID`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;

CREATE TABLE IF NOT EXISTS `Persons` (
  `PersonID` int(11) NOT NULL auto_increment,
  `FirstName` varchar(45) NOT NULL,
  `LastName` varchar(45) NOT NULL,
  `OrderName` varchar(45) default NULL,
  `Email` varchar(45) NOT NULL,
  `Telephone` varchar(20) default NULL,
  `Mobile` varchar(20) default NULL,
  `StreetAddress` varchar(45) NOT NULL,
  `City` varchar(45) NOT NULL,
  `RegionID` int(2) NOT NULL,
  `PostCode` varchar(10) NOT NULL,
  `CountryID` int(11) NOT NULL,
  `TitleID` int(11) NOT NULL,
  `CIC_MailingList` tinyint(1) NOT NULL,
  `FoundationMember` tinyint(1) NOT NULL,
  `PersonCmts` mediumtext,
  PRIMARY KEY  (`PersonID`),
  KEY `TitleID` (`TitleID`),
  KEY `RegionID` (`RegionID`),
  KEY `CountryID` (`CountryID`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;


CREATE TABLE IF NOT EXISTS `Persons_PersonCategories` (
  `PersonID` int(11) NOT NULL,
  `PrsCatID` int(11) NOT NULL,
  PRIMARY KEY  (`PersonID`,`PrsCatID`),
  KEY `PrsCatID` (`PrsCatID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 Constraints for the tables
--
ALTER TABLE `Persons`
  ADD CONSTRAINT `Persons_ibfk_12` FOREIGN KEY (`TitleID`) REFERENCES `Job_Titles` (`TitleID`),
  ADD CONSTRAINT `Persons_ibfk_14` FOREIGN KEY (`CountryID`) REFERENCES `Countries` (`CountryID`),
  ADD CONSTRAINT `Persons_ibfk_15` FOREIGN KEY (`RegionID`) REFERENCES `Regions` (`RegionID`);

ALTER TABLE `Persons_PersonCategories`
  ADD CONSTRAINT `Persons_PersonCategories_ibfk_8` FOREIGN KEY (`PrsCatID`) REFERENCES `Person_Categories` (`PrsCatID`),
  ADD CONSTRAINT `Persons_PersonCategories_ibfk_7` FOREIGN KEY (`PersonID`) REFERENCES `Persons` (`PersonID`);

Persons_PersonCateogires是n:m关系的链接表。当我尝试通过我的php应用程序将PersonID和PrsCatID插入Persons_PersonCategories时,我收到以下错误:

  

插入期间发生错误:

     

无法添加或更新子行:外键约束失败   (ubarry09_andrew/Persons_PersonCategories,CONSTRAINT   Persons_PersonCategories_ibfk_7 FOREIGN KEY(PersonID)参考   PersonsPersonID))

这是插入语句:

INSERT INTO Persons_PersonCategories
VALUES (PersonID, PrsCatID)

Persons和Persons_Categories表填充了数据。

非常感谢,zan

2 个答案:

答案 0 :(得分:3)

以下SQL语句是合法的,但它可能不符合您的意图:

INSERT INTO Persons_PersonCategories
VALUES (PersonID, PrsCatID);

这基本上尝试插入(NULL, NULL),因为它在创建行之前评估VALUES子句中的表达式。但是表达式在尚未创建的行的上下文中命名列,因此没有值可供使用。因此它对两者都使用NULL。

PRIMARY KEY列中不允许使用NULL,当您将它们用于主键列时,MySQL会自动提升NULL值。在这种情况下,它将它们提升为整数值0.Persons和PersonCategories表中没有值0,因此您得到FK错误。

尝试此实验:

CREATE TABLE IF NOT EXISTS `Persons_PersonCategories2` (
  `PersonID` int(11) NOT NULL,
  `PrsCatID` int(11) NOT NULL,
  PRIMARY KEY  (`PersonID`,`PrsCatID`),
  KEY `PrsCatID` (`PrsCatID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

也就是说,一个像您创建的表,但没有FK约束。

INSERT INTO Persons_PersonCategories2
VALUES (PersonID, PrsCatID);

SELECT * FROM Persons_PersonCategories2;
+----------+----------+
| PersonID | PrsCatID |
+----------+----------+
|        0 |        0 |
+----------+----------+

当您尝试在父级的引用PK列中不存在的FK列中插入值时,会出现外键约束错误。零通常不会被自动增量主键使用,因此它必然会失败。

您需要做的是为此INSERT提供您要引用的相应表中的主要值。像这样:

$stmt = $pdo->prepare("INSERT INTO Persons_PersonCategories (PersonID, PrsCatID) 
    VALUES (?, ?)");

使用prepared statements很简单,它有助于防止SQL注入错误。然后在执行时从其他表中提供值。这些值自动绑定到您在准备好的查询中使用的?占位符:

$stmt->execute( array(1234, 5678) );

只要这些值1234和5678对应于引用的表Persons和PersonCategories中的现有行,就会满足外键约束。

答案 1 :(得分:2)

看起来您在Persons_PersonCategories表上设置了一个FOREIGN KEY约束,该约束不允许您将任何PersonID添加到Persons表中尚不存在的Persons_PersonCategories表中。您的Persons_PersonCategories表上还有另一个FOREIGN KEY,它只允许您添加Person_Categories表中已存在的PrsCatID。好像你试图将PersonID添加到Persons表中不存在的Persons_Categories表中。

在尝试将记录添加到Persons_PersonCategories表之前,请确保您要添加到Persons_PersonCategories表中的PersonID存在于Persons表中。将PrsCatID添加到此表也是如此;首先确保Person_Category表中存在PrsCatID。如果您不希望Persons_PersonCategories表阻止您插入Persons和Person_Category表中尚不存在的值,则必须删除FOREIGN KEYS(或代码示例中显示的CONSTRAINT)。要删除CONSTRAINT,请使用以下行:

ALTER TABLE [TABLE_NAME] DROP FOREIGN KEY [CONSTRAINT_NAME]