关于UPDATE级MERGE关联表进行UPDATE的说明

简介: 1、建立测试表  SQL> select * from test1;  ID NAME  ----------- --------------------  1 gaopeng  2 gaopeng1  3 gaopeng2  4 gaope...
1、建立测试表 
SQL> select * from test1; 
ID NAME 
----------- -------------------- 
1 gaopeng 
2 gaopeng1 
3 gaopeng2 
4 gaopeng3 

SQL> select * from test2; 
ID NAME 
----------- -------------------- 
1 yanlei 
2 yanlei1 
2、目标 根据ID进行更改将TEST1中的name字段更改为TEST2中的NAME字段 
3、写法 
---UPDATE错误写法 
update test1 t1 set name=(select name from test2 t2 where t1.id=t2.id) ; 
结果为 
SQL> update test1 t1 set name=(select name from test2 t2 where t1.id=t2.id) ; 
4 rows updated 

SQL> select * from test1; 
ID NAME 
----------- -------------------- 
1 yanlei 
2 yanlei1 
3 
4 
可以看到TEST1中ID不与TEST2中匹配的行赋予了正确的值,不匹配的行赋予了空值,这不是我们需要的。 
---UPDATE正确的写法 
SQL> update test1 t1 set name=(select name from test2 t2 where t1.id=t2.id) 
2 where exists (select 1 
3 from test2 t2 
4 where t1.id=t2.id 
5 ) 
6 ; 
2 rows updated 

SQL> select * from test1; 
ID NAME 
----------- -------------------- 
1 yanlei 
2 yanlei1 
3 gaopeng2 
4 gaopeng3 
可以看到这种写法达到了我们的要求,因为首先通过EXISTS语句过滤掉了不匹配的行,如果需要对TEST1表进行WHERE 条件限制可以如下: 
update test1 t1 set name=(select name from test2 t2 where t1.id=t2.id) 
where exists (select 1 
from test2 t2 
where t1.id=t2.id 
) 
and t1.id=1; 


---MERGE正确写法 
SQL> merge into test1 t1 
2 using 
3 test2 t2 
4 on(t1.id=t2.id) 
5 when matched then 
6 update 
7 set t1.name=t2.name 
8 ; 
2 rows merged 


SQL> select * from test1 order by id; 
ID NAME 
----------- -------------------- 
1 yanlei 
2 yanlei1 
3 gaopeng2 
4 gaopeng3 

可以看到这种写法也达到了我们要的求。如果需要对TEST1表进行限制条件可以 

merge into test1 t1 
using 
test2 t2 
on(t1.id=t2.id) 
when matched then 
update 
set t1.name=t2.name 
where t1.id=2; 


注意:对于如上的更改的要求TEST2表中ID列必须唯一键 
如果不唯一都会报错 
在TEST2表中增加一行 
SQL> insert into test2 values(1,'yanlei1'); 
1 row inserted 

SQL> commit; 
Commit complete 

SQL> select * from test2; 
ID NAME 
----------- -------------------- 
2 yanlei1 
1 yanlei 
1 yanlei1 


update 会报错 
update test1 t1 set name=(select name from test2 t2 where t1.id=t2.id) 
where exists (select 1 
from test2 t2 
where t1.id=t2.id 
) 
ORA-01427: single-row subquery returns more than one row 
merger 会报错 
ORA-30926: unable to get a stable set of rows in the source tables 

对于执行性能而言: 
MERGE 可以对执行计划进行控制,更改其连接方式提高性能,但是UPDATE首先会做WHERE条件后的子查询,通过关联子查询过滤出相应的行数(关联子查询由外层表驱动内层表 
换句话说外层表有多少行就会驱动多少次,虽然ORACLE做了SEMI ANTI等半连接但性能还是大数据量的情况下任然很慢),然后通过查询出来的行数和 
更改表做连接进行更改数据(次连接为NEST LOOP类型),不仅多一个步骤而且无法通过更改连接方式进行提高性能。 

UPDATE执行计划: 
---------------------------------------------------------------------------------------
| Id  | Operation           | Name  | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT    |       |      1 |        |      0 |00:00:00.01 |      32 |
|   1 |  UPDATE             | TEST1 |      1 |        |      0 |00:00:00.01 |      32 |                  --第二次驱动
|*  2 |   HASH JOIN SEMI    |       |      1 |      2 |      2 |00:00:00.01 |      14 |                --第一次驱动
|   3 |    TABLE ACCESS FULL| TEST1 |      1 |      4 |      4 |00:00:00.01 |       7 |
|   4 |    TABLE ACCESS FULL| TEST2 |      1 |      2 |      2 |00:00:00.01 |       7 |
|*  5 |   TABLE ACCESS FULL | TEST2 |      2 |      1 |      2 |00:00:00.01 |      14 |
---------------------------------------------------------------------------------------

MERGE执行计划 

PLAN_TABLE_OUTPUT 
-------------------------------------------------------------------------------- 
Plan hash value: 520388833 
------------------------------------------------------------------------------ 
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | 
------------------------------------------------------------------------------ 
| 0 | MERGE STATEMENT | | 2 | 100 | 7 (15)| 00:00:01 | 
| 1 | MERGE | TEST1 | | | | | 
| 2 | VIEW | | | | | | 
|* 3 | HASH JOIN | | 2 | 124 | 7 (15)| 00:00:01 | --仅驱动一次,这一步是可以使用HINT更改连接方式的 
| 4 | TABLE ACCESS FULL| TEST2 | 2 | 50 | 3 (0)| 00:00:01 | 
| 5 | TABLE ACCESS FULL| TEST1 | 4 | 148 | 3 (0)| 00:00:01 | 
------------------------------------------------------------------------------


谢谢!

相关文章
|
21天前
|
Oracle 关系型数据库 MySQL
【MySQL】8. 基本查询(update/delete/聚合/分组)
【MySQL】8. 基本查询(update/delete/聚合/分组)
35 0
|
2月前
|
SQL 测试技术 数据库
`SELECT ... FOR UPDATE` 语句是如何工作的?
`SELECT ... FOR UPDATE` 语句是如何工作的?
83 0
|
7月前
数据更新语句INSERT语句、UPDATE语句、DELETE语句等,用于向数据表中插入、更新或删除数据。示例
数据更新语句INSERT语句、UPDATE语句、DELETE语句等,用于向数据表中插入、更新或删除数据。示例
54 1
|
10月前
|
SQL 关系型数据库 MySQL
使用tkmapper避免更新on update字段
使用tkmapper避免更新on update字段
100 0
|
11月前
|
关系型数据库 MySQL
Mysql中通过关联update将一张表的一个字段更新到另外一张表中
Mysql中通过关联update将一张表的一个字段更新到另外一张表中
990 0
|
SQL Java 数据库连接
INSERT操作
INSERT操作
68 0
|
关系型数据库 MySQL 数据库
插入命令 insert 和查询命令 select 的组合使用|学习笔记
快速学习插入命令 insert 和查询命令 select 的组合使用
1646 0
|
SQL
在同一个workprocess里对两张表分别使用online update和update function module update
在同一个workprocess里对两张表分别使用online update和update function module update
127 0
在同一个workprocess里对两张表分别使用online update和update function module update
|
关系型数据库 PostgreSQL
PostgreSQL merge insert(upsert/insert into on conflict) 如何区分数据是INSERT还是UPDATE
标签 PostgreSQL , merge insert , upsert , insert into on conflict , 区分 insert update , xmin , xmax 背景 使用insert into on conflict update语法,可以支持UPSERT的功能,但是到底这条SQL是插入的还是更新的呢?如何判断 通过xmax字段的值是否不为0,可以判断,如果是UPDATE,XMAX里面会填充更新事务号。
2051 0