【问题标题】:UPDATE and DELETE in same SQL in multiple tables?在多个表中的同一 SQL 中更新和删除?
【发布时间】:2016-10-08 00:10:17
【问题描述】:

使用 Oracle DB,是否可以更新一个表并删除另一个表(匹配行)?

我尝试了各种形式的MERGE,但都得到了:

ORA-01446: 无法从具有 DISTINCT、GROUP BY 等的视图中选择 ROWID 或采样。

(可能是视图中UNION ALL引起的)

ORA-38106: 合并视图或带有 INSTEAD OF 触发器的视图不支持合并。

这(“连接视图”)表明以任何形式指定两个表对于MERGE 来说是不行的。对吗?

(使用单一语句的原因是:性能、一致性和清晰度)

我的 Oracle DB 版本为 11.2。

实际问题是这样的:

我们(图书馆)有一个 books 的(父)表和一个 content 的(子)表(每本书一个或零个,它有一个 FK books 表)。每年我们都会为每本超过 10 年的书运行一项工作(让我们简化条件,因为它与这里的问题无关)我们将一个名为 RETIRED 的列设置为 books 中的值“YES” em> 表并删除 content 表中的行(如果存在)。

PS:欢迎使用 PL/SQL 解决方案。 (无论如何,我的代码都在 PL/SQL 中)

【问题讨论】:

    标签: sql database oracle oracle11g


    【解决方案1】:

    一个事务与两个语句一起使用:

    1. 更新books 退休;
    2. 删除所有已停用书籍的content

    PL/SQL 解决方案可能是:

    DECLARE
     TYPE id_list IS TABLE OF books.id%TYPE;
     retired_list id_list;
    BEGIN
      UPDATE books
      SET retired = 'YES'
      WHERE publish_date <= add_months(TRUNC(SYSDATE), -120)
      RETURNING id BULK COLLECT INTO retired_list;
    
      FORALL id IN retired_list.FIRST .. retired_list.LAST
        DELETE content
        WHERE book_id = retired_list(id);
    
      COMMIT;
    END;
    /
    

    【讨论】:

    • 这将对books 表进行两次扫描(性能),如果删除以DELETE ... where BOOKS.RETIRED='YES' 完成,它将尝试删除已删除的(前几年)内容(再次:性能) .
    • 不一定。您可以使用RETURNING ... BULK COLLECT INTO ... 仅将更新的书籍ID 存储在集合中,并应用FORALL 仅通过这些ID 删除content。诚然,那将是 PL\SQL 解决方案,而不是 SQL。
    • FORALL代替DELETE from content WHERE book_id = IN (select value(x) from TABLE(retired_list) x);有什么好处吗?
    • 我会在DBA StackExchange 上问这个问题。 PL/SQL 和 SQL 之间的上下文切换、将数据从 PGA 移动到 SGA、潜在的并行处理以及各种需要考虑的美妙事物。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    相关资源
    最近更新 更多