繁体   English   中英

带有外键约束的sql删除

[英]sql delete with foreign key constraint

我有三个表,其中一个是关系表,例如:

具有主键:人id ;
宠物有主键: 皮蒂 ;
Table Own有两个外键: peopleidpetid ,它们一起用作Table Own的主键

现在
我正在尝试从给定peopleid的 Table People中删除一个人,与此同时,应该删除该人拥有的宠物以及存储在Own表中的关系

请说明一下,预先感谢!

编辑:我的问题是如何编写sql以实现此目的。

一种选择是使用多表DELETE语句,从所有三个表中删除行,例如:

DELETE o.*
     , t.*
     , p.*
  FROM pet t
  JOIN own o
    ON o.petid = t.petid
  JOIN people p
    ON p.peopleid = o.peopleid
 WHERE p.peopleid = :b_peopleid

但是...外键存在问题。 可以按导致违反外键约束的顺序删除行。 MyISAM没问题,因为它不强制使用外键。 但是使用InnoDB时,如果定义了外键约束,这可能是个问题。不幸的是,InnoDB不(还?)支持可延期约束,因此最接近的解决方法是暂时禁用外键检查...

SET foreign_key_checks = 0 ;

然后是DELETE语句,然后重新启用外键检查...

SET foreign_key_checks = 1; 

但这会禁用会话中的所有外键检查,而不仅是在DELETE中引用的表上定义的外键。 因此,这种方法不太理想,因为可能会引入不一致的数据。

(例如,如果存在另一个带有引用pet.petid的外键的表,并且我们从pet中删除了“父”行,则可能会在“子”表中留下引用不存在的键的行。)

pet删除行?

数据模型表明, pet可能与一个以上的people 例如:

pet:    petid    petname
            ------   -------
            1        Spot

    people: peopleid name
            -------- ------
            2        Jack
            3        Jill

    own:    petid    peopleid
            -------  --------
            1        2
            1        3

如果要删除“ Jack”,则可以删除“ own”中的关联行(“ Jack”和“ Spot”之间的关系。但是在这种情况下,“ Spot”也与“ Jill”相关。还有另一行own引用了“ Spot”,因此如果不删除“ Spot”与“ Jill”的关系,我们将无法删除“ Spot”。

因此,问题是,在这种情况下,我们真的要删除“ Spot”吗?

如果确实要删除“ Spot”,则也需要从own那一行中删除另一行,即与“ Spot”和“ Jill”相关的那一行。 我们可以使用对own表的两个引用来完成此操作。 一个用于获取“ Jack”和他所拥有的pet之间的关系,另一个用于获取所有引用“ Spot”的own行。

DELETE r.*
     , t.*
     , p.*
  FROM pet t
  JOIN own r
    ON r.petid = t.petid
  JOIN own o
    ON o.petid = t.petid
  JOIN people p
    ON p.peopleid = o.peopleid
 WHERE p.peopleid = :b_peopleid

在另一方面,如果我们不希望删除“点”,因为“吉尔” /“点”行own也引用“点”,我们也许能够做一些非常相似。 (我没有为此的SQL示例。)


在您的用例中可能有用的处理外键关系的其他一些选项是DELETE触发器之前,和/或关于外键约束的ON DELETE规则。)

如果我们对删除的外键从已定义CASCADE规则, own是参照peoplepet ,我们可以允许从删除的行own

然后,我们可以在答案中使用第一个示例DELETE语句,并且可以省略DELETE列表中对o.*的引用,而只需指定t.*p.* (我们仍然需要在FROM子句中引用own表,以获取people (“杰克”)和pet (“ Spot”)之间的关系,因此我们知道要删除pet哪些行。


否则,您可以运行三个单独的DELETE语句。 但是执行DELETE语句的顺序实际上可能会删除您需要的信息,以确定需要删除其他表中的哪些行。 这意味着您可能需要查询表以找到要删除的行,保存该信息,然后以适当的顺序执行所需的删除。


解决此类“删除”问题的另一种可行方法是模拟删除,并在行上更新“ deleted_flag”类型列。

也就是说,应用程序不是发出DELETE语句,而是发出UPDATE以在每一行上设置特殊用途的“ deleted_flag”。 但是,必须为此设计应用程序用例,并且几乎所有查找“未删除”数据的查询都需要包含排除“已删除”行的谓词。 如果实际上确实需要从表中删除逻辑删除的行,则可以通过单独的批处理过程运行DELETE语句。

我认为您需要的是ON DELETE CASCADE
使用此方法,如果删除主键行,则可以自动删除所有表引用。

在你的情况,如果你删除使用一个人peopleid ,它会自动删除引用Own表。

示例SQL语句

CREATE TABLE Own (
peopleid int(11) NOT NULL,
KEY peopleid (peopleid),
FOREIGN KEY (peopleid)
REFERENCES People (peopleid)
ON DELETE CASCADE
) ENGINE=InnoDB;  

由于宠物表没有到人员表的外键,因此您需要定义一个触发器,以便在删除人员条目时自动删除宠物条目。

CREATE TRIGGER pet_delete AFTER DELETE on own
FOR EACH ROW
BEGIN
    DELETE FROM Pet
    WHERE Pet.petid = old.petid;
END  

定义级联规则和触发器后,如果执行:

DELETE FROM People WHERE peopleid = 3  

它会自动删除条目ownpeopleid = 3和相应的petidPet表。

检查此链接以获取更多详细信息。
http://www.mysqltutorial.org/mysql-on-delete-cascade/
MySQL触发器:删除后从表中删除

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM