除其他外,我有三个表:account
,address
和account_address
。 account_address
表格包含account_id
和address_id
。这是你标准的多对多关系。
我有一个令人困惑的情况,我有account_address
记录,指向不存在的account
。由于account_address.account_id
上的外键指向account
,因此不应该发生这种情况,对吧?
现在让我证明这应该是不可能的事情正在发生。首先,我将向您展示我的表格定义:
CREATE TABLE `account_address` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`account_id` bigint(20) NOT NULL,
`address_id` bigint(20) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `fk_account_address_account_id` (`account_id`),
KEY `fk_account_address_address_id` (`address_id`),
KEY `index_account_address_account_id` (`account_id`) USING BTREE,
KEY `index_account_address_address_id` (`address_id`) USING BTREE,
CONSTRAINT `fk_account_address_account_id` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_account_address_address_id` FOREIGN KEY (`address_id`) REFERENCES `address` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=697173 DEFAULT CHARSET=latin1
请参阅? FOREIGN KEY (account_id) REFERENCES account (id)
。
现在,这里有一些查询显示约束失败:
select aa.account_id
from account_address aa
where aa.address_id = 15116
该查询给出了以下结果:
15116
37033
62325
71857
93774
119066
显然,地址15116附加到六个不同的帐户(一个帐户,有趣的是与地址具有相同的ID)。但请查看:
select * from account where id in (15116, 37033, 62325, 71857, 93774, 119066)
没有结果! 我的DBMS不应该告诉我,我的外键约束失败了吗?!
我只看到两种可能性:
我当然希望#1是这样的,但我不知道我可能会误解的是什么。对我来说,最高级别是一个谜。任何想法都将不胜感激。
答案 0 :(得分:1)
约束会阻止任何行为做出“邪恶”,但不会追溯确保一切都是正确的。您可以像许多导入脚本那样,因为事件发生的顺序,将这些约束的检查设置为0。
因此,如果由于某种原因信息不正确,可能会出现这种情况。然后你的DBMS没有行为不端,你也没有误解。
所以我选择选项3 :某些导入或插入行为不正常,可能使用“set foreign_key_checks = 0”。或者它是旧数据。
(来自手册:
mysql> SET foreign_key_checks = 0;
mysql> SOURCE dump_file_name;
mysql> SET foreign_key_checks = 1;
)
答案 1 :(得分:0)
MySQL确实有一个服务器变量来禁用外键检查 - set foreign_key_checks=0
,用于导入转储文件的情况,其中表可能有一个FK指向转储中的“稍后”的表尚未加载。通常这会导致导入失败,即使数据很好。禁用FK检查允许导入继续。
在禁用密钥检查期间,您的遗失记录可能会被删除。要测试密钥现在是否正常工作,请添加一些相关记录并删除一个,由于FK上的“无操作”设置,这些记录将失败。如果它继续,那么要么你不在InnoDB上(可能是它被禁用而且mysql默默地转换为MyISAM),关键检查被关闭(检查服务器变量),或者你的服务器真的搞砸了。