6

Oracle では、SELECT ステートメントの結果を更新できます。

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

これは、別のテーブルの一致する行の値に基づいて、あるテーブルの列を更新するために使用できると思います。

この機能はどのように呼び出されますか、大規模な更新に効率的に使用できますか、SELECT が複数のテーブルを結合するときに機能しますか? もしそうなら、どのように機能しますか?

4

3 に答える 3

5

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

于 2009-06-16T09:16:40.050 に答える
1

コメントありがとうございます。これは標準の SQL だと思いました... :(

Oracle の場合、次のような結合で情報を取得するテーブルに更新を書き込むことができます。

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

SQL Server の場合は次のとおりです。

UPDATE t1
SET col1 = t2.col2
FROM table1 t1
LEFT JOIN table2 t2 on t2.t1id = t1.id

Oracle、Sql Server、およびMySqlで機能するこれを行う方法を知っている人がいれば、興味があります。

于 2009-06-16T06:36:06.683 に答える
1

あなたが言及したフォームには、AFAIKという特定の名前はありません。select ステートメントの結果を更新するだけです。

相関更新と呼ばれる別の形式があります(単一または複数列の更新を使用)

UPDATE TABLE(<SELECT STATEMENT>) <alias>
SET <column_name> = (
  SELECT <column_name>
  FROM <table_name> <alias>
  WHERE <alias.table_name> <condition> <alias.table_name>
);

複数列フォーム

...
SET (<column_name_list>) = (
  SELECT <column_name_list>
...

また、returning 句を使用して Update と呼ばれる値を返すものもあります。

ネストされたテーブルを使用した更新の詳細。少なくともこの 2 ページを確認することをお勧めします

Oracle® Database SQL言語リファレンス SELECT

Oracle® Database SQL言語リファレンス UPDATE

于 2009-06-16T06:42:22.700 に答える