我正在努力澄清外键约束的正确使用,并在"ON DELETE"NO ACTION"时保持空白我将保持通用性,因为它非常简单,不需要深入到有限的细节中。
我有一个父表,它有5个子表-存在所有表中的数据(这不是新的DB构建(。我想设置一切都合乎逻辑,以满足我的客户的需求和我的期望!所有父表到子表都存在一对多关系因此:可以有零个或多个与父表相关的记录主键记录。永远不可能有不与父记录相关(我已经检查过以确保是这样(。
由于现在任何子表中可能(也可能(没有和子记录的父记录,因此设置"父-子"约束失败,好吧,我理解原因,没问题。如此糟糕地设置了儿童对父母的约束:
- 如果更新了子记录(Fk(,则将父记录(PK(更新为相同记录
- 如果删除了子记录(Fk(,则允许删除该子记录,但不对父记录(Pk(采取任何操作(非常重要!(
- 如果删除了父记录,则删除该记录以及所有子表中的所有相关子记录
然而,我在SO和MySQL文档上读取的线程中说"NO ACTION"与"RESTRICT"相同,如果我不能删除子记录,这将导致问题。我在PHP代码中主要使用"INSERT INTO"语句和"ON DUPLICATE KEY UPDATE"语句。我倾向于从DB级别完全删除外键约束,并强制执行我在PHP/PDO中想要实现的目标。我实际上是在使用外键约束,因为我认为我必须这样做,但并没有真正理解这一点,因为无论如何都不应该更新主键。
最好的方法是什么。如果"不采取行动"实际上是预防而不是保护,那么它是一个好的用例。
"NO ACTION"与"RESTRICT"相同,如果我不能删除子记录,这将导致问题。
这不是那个条件的意思。它不会阻止您删除子记录,当且仅当存在依赖于父记录的子记录时,它会阻止您删除父纪录。
示例:
表Orders
与LineItems
具有一对多关系,而LineItems
中的外键具有restrict选项。
CREATE TABLE Orders (
order_id INT NOT NULL,
PRIMARY KEY (order_id)
);
CREATE TABLE LineItems (
lineitem_id INT NOT NULL,
order_id INT NOT NULL,
PRIMARY KEY (lineitem_id),
FOREIGN KEY (order_id) REFERENCES Orders (order_id) ON DELETE RESTRICT
);
创建一些测试数据:
mysql> INSERT INTO Orders SET order_id = 123;
Query OK, 1 row affected (0.02 sec)
mysql> INSERT INTO LineItems SET lineitem_id = 1, order_id = 123;
Query OK, 1 row affected (0.02 sec)
我们无法删除订单记录,因为有一个LineItem依赖于它:
mysql> DELETE FROM Orders WHERE order_id = 123;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`lineitems`, CONSTRAINT `lineitems_ibfk_1` FOREIGN KEY (`order_id`) REFERENCES `Orders` (`order_id`))
但我们可以随时删除LineItems记录:
mysql> DELETE FROM LineItems WHERE order_id = 123;
Query OK, 1 row affected (0.01 sec)
现在没有引用订单记录的LineItems记录,我们也可以删除该记录:
mysql> DELETE FROM Orders WHERE order_id = 123;
Query OK, 1 row affected (0.01 sec)
@Bill Karwin和这个问题的贡献者。从那以后,我意识到数据库设置不正确,这就是为什么我需要删除FK约束才能使用它。数据库是从MS Access迁移的,除了一些数据类型差异外,在将数据库导入mySQL时,外键约束检查被关闭,而不进行此导入是不可能的。仅此一点就表明MS Access中设置的约束规则存在问题。
现在在MySQL中使用导出的数据库显示了许多孤立记录和索引字段,这些记录和字段已经违反了FK约束,为null或空!-关于修复这些问题并正确规范DB/表,这里的建议是成立的。
感谢您的意见。