更新SELECT语句的结果

Thi*_*ilo 6 sql oracle bulk sql-update

Oracle允许您更新SELECT语句的结果.

UPDATE (<SELECT Statement>)
SET <column_name> = <value>
WHERE <column_name> <condition> <value>;
Run Code Online (Sandbox Code Playgroud)

我想这可以用于根据另一个表中匹配行的值更新一个表中的列.

如何调用此功能,它是否可以有效地用于大型更新,当SELECT连接多个表时是否有效,如果是,如何?

Ton*_*ews 5

我还没有看到这个正式名称.在甲骨文SQL参考只是指的是更新的子查询.我倾向于将其视为"视图更新"的一种形式,子查询处于内联视图中.

是的,它在多个表连接时有效,但受视图更新规则的限制.这意味着只能更新视图的一个基表,并且该表必须在视图中"密钥保留":即它的行应该只能在视图中出现一次.这要求视图中的任何其他表(子查询)通过要更新的表上的外键约束来引用.

一些例子可能有帮助.使用标准Oracle EMP和DEPT表,将EMP.EMPNO定义为EMP的主键,并将EMP.DEPTNO定义为DEPT.DEPTNO的外键,则允许此更新:

update (select emp.empno, emp.ename, emp.sal, dept.dname
        from   emp join dept on dept.deptno = emp.deptno
       )
set sal = sal+100;
Run Code Online (Sandbox Code Playgroud)

但这不是:

-- DEPT is not "key-preserved" - same DEPT row may appear
-- several times in view
update (select emp.ename, emp.sal, dept.deptno, dept.dname
        from   emp join dept on dept.deptno = emp.deptno
       )
set dname = upper(dname);
Run Code Online (Sandbox Code Playgroud)

至于性能:优化器将(必须)识别在解析期间要更新的基表,并且将忽略与其他表的连接,因为它们对要执行的更新没有任何影响 - 因为此AUTOTRACE输出显示:

SQL> update (select emp.ename, emp.sal, dept.dname
  2              from   emp join dept on dept.deptno = emp.deptno
  3             )
  4      set sal = sal-1;

33 rows updated.


Execution Plan
----------------------------------------------------------
Plan hash value: 1507993178

------------------------------------------------------------------------------------
| Id  | Operation           | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT    |              |    33 |   495 |     3   (0)| 00:00:01 |
|   1 |  UPDATE             | EMP          |       |       |            |          |
|   2 |   NESTED LOOPS      |              |    33 |   495 |     3   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| EMP          |    33 |   396 |     3   (0)| 00:00:01 |
|*  4 |    INDEX UNIQUE SCAN| SYS_C0010666 |     1 |     3 |     0   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("EMP"."DEPTNO"="DEPT"."DEPTNO")
Run Code Online (Sandbox Code Playgroud)

(请注意,即使DEPT.DNAME出现在子查询中,也永远不会访问表DEPT).


And*_*mar 0

感谢您的评论,我认为这是标准的 Sql...:(

对于 Oracle,您可以在表上编写更新,在该表上使用以下联接检索信息:

UPDATE (
    SELECT * 
    FROM table1 t1 
    LEFT JOIN table2 t2 ON t2.t1id = t1.ID
) SET t1.col1 = t2.col2
Run Code Online (Sandbox Code Playgroud)

对于 Sql Server 来说,它是:

UPDATE t1
SET col1 = t2.col2
FROM table1 t1
LEFT JOIN table2 t2 on t2.t1id = t1.id
Run Code Online (Sandbox Code Playgroud)

如果有人知道一种适用于 Oracle、Sql Server 和 MySql 的方法,我会很感兴趣。