如何使用 Where 子句从多个表中删除多行?

Posted

技术标签:

【中文标题】如何使用 Where 子句从多个表中删除多行?【英文标题】:How to delete multiple rows from multiple tables using Where clause? 【发布时间】:2015-08-31 16:35:46 【问题描述】:

使用 Oracle 数据库,我需要从存在条件的表中选择所有 ID,然后从存在该 ID 的多个表中删除行。伪代码类似于:

SELECT ID FROM TABLE1 WHERE AGE > ?
DELETE FROM TABLE1 WHERE ID = <all IDs received from SELECT>
DELETE FROM TABLE2 WHERE ID = <all IDs received from SELECT>
DELETE FROM TABLE3 WHERE ID = <all IDs received from SELECT>

最好和最有效的方法是什么?

我正在考虑类似以下的事情,但想知道是否有更好的方法。

PreparedStatement selectStmt = conn.prepareStatment("SELECT ID FROM TABLE1 WHERE AGE > ?");
selectStmt.setInt(1, age);
ResultSet rs = selectStmt.executeQuery():

PreparedStatement delStmt1 = conn.prepareStatment("DELETE FROM TABLE1 WHERE ID = ?");
PreparedStatement delStmt2 = conn.prepareStatment("DELETE FROM TABLE2 WHERE ID = ?");
PreparedStatement delStmt3 = conn.prepareStatment("DELETE FROM TABLE3 WHERE ID = ?");

while(rs.next())

    String id = rs.getString("ID");

    delStmt1.setString(1, id);
    delStmt1.addBatch();

    delStmt2.setString(1, id);
    delStmt2.addBatch();

    delStmt3.setString(1, id);
    delStmt3.addBatch();


delStmt1.executeBatch();
delStmt2.executeBatch();
delStmt3.executeBatch();

有没有更好/更有效的方法?

【问题讨论】:

你用的是什么关系型数据库? 你可以使用WHERE id IN (...) 在 for 循环中多次向数据库发送命令而不是发送一次更愚蠢,而且性能大大提高。如果性能(效率)不是您的目标,那么就这样做吧。 它不是标签,它是我问题的重要部分。我在问如何在 Java 中做这个特殊的事情。同样,这已经在标签中说明了。无需在标题中添加标签。而且,最后,你只是在执行普通的 sql 语句...... 【参考方案1】:

如果您的 3 个表中的两个(例如“table2”和“table3”)是具有“ON DELETE CASCADE”的父表(例如“table1”)的子表,您可以使用一个 DELETE 语句执行此操作选项。

这意味着两个子表有一个列(例如“table2”和“table3”的列“id”),该列具有引用父主键列的“ON DELETE CASCADE”选项的外键约束表(“table1”的示例列“id”)。这样只有从父表中删除才会自动删除子表中的关联行。

查看更多详细信息:http://www.techonthenet.com/oracle/foreign_keys/foreign_delete.php

【讨论】:

【参考方案2】:

如果只删除大表中的几条记录,请确保 列 ID 已定义。

要从表 TABLE2 和 3 中删除记录,最好的策略是使用 CASCADE DELETE,如 @ivanzg - 如果这不可能,请参见下文。

要从 TABLE1 中删除一个基于行的批量删除的优越选项,请使用基于年龄的谓词使用signle delete:

 PreparedStatement stmt = con.prepareStatement("DELETE FROM TABLE1 WHERE age > ?")
 stmt.setInt(1,60)
 Integer rowCount = stmt.executeUpdate()

如果不能级联删除,则表2和表3使用与上述相同的概念,但语句如下:

 DELETE FROM TABLE2/*or 3*/ WHERE ID in (SELECT ID FROM TABLE1 WHERE age > ?)

一般最佳实践 - 客户端中的最小逻辑,数据库服务器中的整个逻辑。数据库应该能做合理的执行计划 - 见上面的索引说明。

【讨论】:

【参考方案3】:

DELETE statement 每个语句操作一个表。然而,主要实现支持触发器或其他执行从属修改的机制。例如Oracle's CREATE TRIGGER。

但是,开发人员最终可能会弄清楚数据库在背后做什么。 (When/Why to use Cascading in SQL Server?)

或者,如果您需要在删除语句中使用中间结果。您可以在批处理中使用时态表(如建议的here)。


附带说明,我在您的示例代码中看不到事务控制(setAutoCommit(false) ... commit()。我想这可能是为了简单起见。

此外,您正在执行 3 个不同的删除批次(每个表一个)而不是一个。这可能会抵消使用PreparedStatement 的好处。

【讨论】:

以上是关于如何使用 Where 子句从多个表中删除多行?的主要内容,如果未能解决你的问题,请参考以下文章

如何在从多个表中获取多行的同时删除 sql JOIN 中的重复项

如何使用引用多个表的 WHERE 子句删除 sqlite 中的行?

如何选择具有多个选择值的数据作为 where 子句? - Ajax Codeigniter

使用多个where子句在spring数据jpa中删除

如何使用 where 子句从 Firestore 中删除文档

每个总和都带有 WHERE 子句的 SUM 函数?