问题
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.
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?
回答1:
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.
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;
But this is not:
-- 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);
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")
(Note that table DEPT is never accessed even though DEPT.DNAME appears in the subquery).
回答2:
The form you mention has no specific name AFAIK. Just updating the result of a select statement.
There is another form called Correlated update (with single or multicolumn update)
UPDATE TABLE(<SELECT STATEMENT>) <alias>
SET <column_name> = (
SELECT <column_name>
FROM <table_name> <alias>
WHERE <alias.table_name> <condition> <alias.table_name>
);
The multicolumn form
...
SET (<column_name_list>) = (
SELECT <column_name_list>
...
There is also a from which also returning of values called Update with returning clause
And some specifics for updates with nested tables. Best is to check at least this two pages
Oracle® Database SQL Language Reference SELECT
Oracle® Database SQL Language Reference UPDATE
回答3:
Thanks for comments, I thought this was standard Sql... :(
For Oracle you can write an update on a table where you retrieve information with a join like:
UPDATE (
SELECT *
FROM table1 t1
LEFT JOIN table2 t2 ON t2.t1id = t1.ID
) SET t1.col1 = t2.col2
For Sql Server, it's:
UPDATE t1
SET col1 = t2.col2
FROM table1 t1
LEFT JOIN table2 t2 on t2.t1id = t1.id
If anyone knows a way to do this that works on Oracle, Sql Server and MySql I'd be interested.
来源:https://stackoverflow.com/questions/999812/update-the-results-of-a-select-statement