删除查询中的内部连接有那么糟糕吗?

Inner join on delete query is that bad?

我目前正在尝试使用 C# 从 MySQL table 中删除一行。
我有两个非常基本的 table:'head_doc' 和 'Doc_details'。 Head_doc 包含一个名为 id_doc 的字段。 Doc_details 还有一个名为 id_doc 的字段和其他各种字段。
我正在尝试删除 Doc_details 中某个特定 id_doc 中的所有详细信息,该 id_doc 可以在 head_doc.
中找到 这是我的查询,但我被告知在 DELETE 查询上使用 INNER JOIN 是糟糕的编程。我该如何更改它?

DELETE h.*,d.* 
FROM head_doc h 
    INNER JOIN  
    doc_details d
    ON h.id_doc = d.id_doc
    WHERE h.id_doc= id_doc;

如果您只是想删除 doc_details 中没有相应父记录的记录(又名孤立记录),那么就这样做(这可以通过添加外键约束来避免. 请参阅下面的注释):

delete
from doc_details
where id_doc not in (
   select id_doc from head_doc
)

但是,如果您想删除两个 table 中具有特定 id 的所有记录,为了清楚起见,拆分删除语句可能是个好主意:

delete from doc_details where id_doc = <value>
delete from doc_head where id_doc = <value>

注意: 如果您在子 table 上设置了外键约束,并且您想要从父 table 中删除一条记录,如果未先删除子记录,数据库引擎将阻止您从父 table 中删除记录。只要有可能,设置外键约束是一个好主意,以确保在删除父记录时子 table 中没有孤立记录。

不,在 DELETE 语句中使用连接操作不是坏习惯。这是一个常见的模式。

我不确定是谁告诉你那是 "bad programming",他们是否有任何理由告诉你。

对于从多个 table 中删除行,MySQL 可能会按照导致违反外键约束的顺序执行操作(使用 InnoDB tables).

例如,MySQL 可能会尝试从 head_doc 中删除一行,然后 它会从 doc_details 中删除相关的子行。

If you use a multiple-table DELETE statement involving InnoDB tables for which there are foreign key constraints, the MySQL optimizer might process tables in an order that differs from that of their parent/child relationship. In this case, the statement fails and rolls back. Instead, you should delete from a single table and rely on the ON DELETE capabilities that InnoDB provides to cause the other tables to be modified accordingly.

参考:http://dev.mysql.com/doc/refman/5.5/en/delete.html

或者,有时我们可以通过使用 separate 语句从每个 table.

中删除来解决该问题

我们注意到问题中的查询只会从 head_doc 中删除在 doc_details 中具有相关子行的行,因为内部连接操作。如果没有任何子行,那将在 head_doc 中留下行。这不一定是糟糕的编程。但是有点奇怪。

鉴于您要从两个 table 中删除行,您可能需要一个 outer 连接,因此您甚至从 head_doc 中删除行当 doc_detais

中不存在匹配的子行时
 DELETE d.* 
      , h.*
   FROM head_doc h
   LEFT
   JOIN doc_details d 
     ON d.id_doc = h.id_doc 
  WHERE h.id_doc =  ?

鉴于您在两个 table 中都有 id_doc,一个更简单的模式是使用两个单独的 DELETE 语句,首先从子 table 中删除,然后从父中删除:

 DELETE FROM doc_details WHERE id_doc = ?
 DELETE FROM head_doc    WHERE id_doc = ?

如果要从 head_doc 中删除的行是由 id_doc 列以外的某些其他条件标识的,则 不是 的列在 doc_details 中可用,我们可以使用 JOIN 操作来识别子 table 中应该删除的行

例如首先,从子 table 中删除行(使用 JOIN 操作)

 DELETE d.*
   FROM head_doc h
   JOIN doc_details d 
     ON d.id_doc = h.id_doc 
  WHERE h.somecol  < ?
    AND h.othercol = ?

然后,从父级删除table:

 DELETE h.*
   FROM head_doc h
  WHERE h.somecol  < ?
    AND h.othercol = ?

综上所述,在DELETE中使用JOIN操作不一定"bad programming"。我们需要注意一些注意事项。有时,使用连接操作是最好的方法。这实际上取决于您想要实现的目标。