Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update the results of a SELECT statement

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?

like image 814
Thilo Avatar asked Jun 16 '09 06:06

Thilo


People also ask

Can we do an update from a SELECT statement?

The UPDATE from SELECT query structure is the main technique for performing these updates. An UPDATE query is used to change an existing row or rows in the database. UPDATE queries can change all tables' rows, or we can limit the update statement affects for certain rows with the help of the WHERE clause.

How do you update a SQL query result?

The SQL UPDATE Query is used to modify the existing records in a table. You can use the WHERE clause with the UPDATE query to update the selected rows, otherwise all the rows would be affected.

What is for update clause in SELECT statement?

The FOR UPDATE clause is an optional part of a SELECT statement. Cursors are read-only by default. The FOR UPDATE clause specifies that the cursor should be updatable, and enforces a check during compilation that the SELECT statement meets the requirements for an updatable cursor.

How do I use update SELECT?

The SELECT FOR UPDATE statement is used to order transactions by controlling concurrent access to one or more rows of a table. It works by locking the rows returned by a selection query, such that other transactions trying to access those rows are forced to wait for the transaction that locked the rows to finish.


2 Answers

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

like image 106
Tony Andrews Avatar answered Oct 08 '22 09:10

Tony Andrews


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

like image 27
jitter Avatar answered Oct 08 '22 09:10

jitter