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

How to delete multiple rows from multiple tables using Where clause?

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

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();

有better/more有效的方法吗?

DELETE statement operates a table per statement. However the main implementations support triggers or other mechanisms that perform subordinate modifications. For example Oracle's CREATE TRIGGER

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

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


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

您还执行了 3 个不同的删除批次(每个 table 一个)而不是一个。这可能会抵消使用 PreparedStatement.

的好处

如果您的 3 个 table 中的两个(例如 "table2" 和 "table3")是父 table 的子 table,则您可以使用一个 DELETE 语句来完成table(例如 "table1")具有 "ON DELETE CASCADE" 选项。

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

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

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

要从 table 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()

如果您不能级联删除,请对 table2 和 3 使用与上述相同的概念,但使用以下语句:

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

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