在删除查询上的内连接是很糟糕的
本文关键字:连接 删除 查询 | 更新日期: 2023-09-27 17:50:48
我正在尝试使用c#从MySQL表中删除一行。
我有两个非常基本的表:'head_doc'和'Doc_details'。Head_doc包含一个名为id_doc的字段。Doc_details还有一个名为id_doc的字段和许多其他字段。
我试图删除Doc_details中可以在head_doc中找到的特定id_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
)
但是,如果您想要删除两个表中具有特定id的所有记录,为了清晰起见,将删除语句拆分可能是一个好主意:
delete from doc_details where id_doc = <value>
delete from doc_head where id_doc = <value>
注意:如果你在子表上设置了外键约束,并且你想从父表中删除一条记录,如果子记录没有先被删除,数据库引擎将阻止你从父表中删除这条记录。只要有可能,设置外键约束是一个好主意,可以确保在删除父记录时,子表中没有孤立的记录。
不,在DELETE
语句中使用连接操作并不是不好的做法。这是一个常见的模式。
我不知道是谁告诉你这是"糟糕的编程",如果他们有任何理由告诉你的话。
对于从多个表中删除行,MySQL可能会按照违反外键约束的顺序执行操作(对于InnoDB表)。
例如,MySQL可能会在删除doc_details
中相关的子行之前尝试从head_doc
中删除一行。
如果你使用一个包含有外键约束的InnoDB表的多表
DELETE
语句,MySQL优化器可能会以不同于父/子关系的顺序处理表。在这种情况下,语句失败并回滚。相反,你应该从单个表中删除,并依赖于InnoDB提供的ON DELETE
功能来导致其他表被相应地修改。
参考:http://dev.mysql.com/doc/refman/5.5/en/delete.html
或者,我们有时可以通过使用单独的语句从每个表中删除来解决这个问题。
我们注意到,由于内部连接操作,问题中的查询只会从head_doc
中删除doc_details
中有相关子行的行。这将留下行(s)在head_doc
,如果没有任何子行。这并不一定是糟糕的编程。但这有点奇怪。
如果您想从两个表中删除行,您可能需要一个外部连接,因此即使doc_detais
head_doc
中删除行。 DELETE d.*
, h.*
FROM head_doc h
LEFT
JOIN doc_details d
ON d.id_doc = h.id_doc
WHERE h.id_doc = ?
如果两个表中都有id_doc
,那么更简单的模式是使用两个单独的DELETE语句,首先从子表中删除,然后从父表中删除:
DELETE FROM doc_details WHERE id_doc = ?
DELETE FROM head_doc WHERE id_doc = ?
如果要从head_doc
中删除的行是由id_doc
列以外的其他条件标识的,在doc_details
中不可用的列上,我们可以使用JOIN操作来标识子表中应该删除的行
。首先,从子表中删除行(使用JOIN操作)
DELETE d.*
FROM head_doc h
JOIN doc_details d
ON d.id_doc = h.id_doc
WHERE h.somecol < ?
AND h.othercol = ?
然后从父表中删除:
DELETE h.*
FROM head_doc h
WHERE h.somecol < ?
AND h.othercol = ?
总之,在DELETE中使用JOIN操作不一定是"糟糕的编程"。我们需要注意一些注意事项。有时,使用连接操作是最好的方法。这取决于你想要达到什么效果