更新SELECT语句的结果

问题描述:

Oracle使您可以更新SELECT语句的结果.

Oracle lets you update the results of a SELECT statement.

UPDATE (<SELECT Statement>)
SET <column_name> = <value>
WHERE <column_name> <condition> <value>;

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

I suppose that this could be used for updating columns in one table based on the value of a matching row in another table.

该功能的调用方式如何,可以有效地用于大型更新,当SELECT连接多个表时是否可以正常工作?如果可以,如何运行?

How is this feature called, can it efficiently be used for large updates, does it work when the SELECT joins multiple tables, and if so, how?

我还没有看到这个的正式名称. Oracle SQL参考仅指更新子查询.我倾向于认为它是视图更新"的一种形式,子查询处于嵌入式视图中.

I haven't seen a formal name for this. The Oracle SQL Reference just refers to updating a subquery. I tend to think of it as a form of "view updating", with the subquery being in in-line view.

是的,当连接多个表时,它可以工作,但是要遵守视图更新的规则.这意味着只能更新视图的基本表之一,并且该表必须在视图中保留键":即,它的行只能在视图中出现一次.这要求通过要更新的表上的外键约束来引用视图(子查询)中的任何其他表.

Yes, it works when a number of tables are joined, but subject to the rules of view updating. This means that only one of the view's base tables can be updated, and this table must be "key-preserved" in the view: i.e. its rows should only be able to appear once in the view. This requires that any other tables in the view (subquery) are referenced via foreign key constraints on the table to be updated.

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

Some examples may help. Using the standard Oracle EMP and DEPT tables, with EMP.EMPNO being defined as the primary key of EMP, and EMP.DEPTNO being defined as a foreign key to DEPT.DEPTNO, then this update is allowed:

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

但这不是:

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

关于性能:优化器将(必须)标识在解析过程中要更新的基本表,并且将忽略与其他表的联接,因为它们与要执行的更新没有任何关系-如此AUTOTRACE输出所示:

As for performance: the optimiser will (must) identify the base table to be updated during parsing, and joins to other table will be ignored since they do not have any bearing on the update to be performed - as this AUTOTRACE output shows:

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")

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

(Note that table DEPT is never accessed even though DEPT.DNAME appears in the subquery).