merge into用法详解

MERGE语句用于基于特定条件从源表或视图更新或插入目标表的数据。它结合了UPDATE和INSERT的功能,提高了效率并避免了多次操作。当源表中有多个记录导致更新目标表同一行时,必须确保更新结果是确定的,否则会导致错误。文章通过示例展示了如何使用MERGE以及其确定性语义的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用merge语句可以从一个或多个源中选择要满足条件的行更新或插入到表或试图中,你可以指定条件来确定是更新还是插入到目标表或视图中。
该语句是组合多个操作的方便方法,效率也更高。使得你避免使用多个INSERT、UPDATE和DELETE语句。
特别要注意:MERGE是一个确定性语句。不能在同一个MERGE语句中多次更新目标表的同一行(除非多次更新结果一致)。不然会直接报错。通俗的解释就是:假如源表中的多条记录导致会去目标表中更新同一行,但是会更新出两个不同的结果则会报错,更新得到同一个结果则不报错(这也是确定性的意思)。

1. 语法

MERGE [ hint ]
   INTO [ schema. ] { table | view } [ t_alias ]
   USING { [ schema. ] { table | view }
         | subquery 
         } [ t_alias ]
   ON ( condition )
   [ merge_update_clause ]
   [ merge_insert_clause ]
   [ error_logging_clause ] ;

merge_update_clause写法:
WHEN MATCHED THEN
UPDATE SET column = { expr | DEFAULT }
           [, column = { expr | DEFAULT } ]...
[ where_clause ]
[ DELETE where_clause ]

merge_insert_clause写法:
WHEN NOT MATCHED THEN
INSERT [ (column [, column ]...) ]
VALUES ({ expr | DEFAULT }
          [, { expr | DEFAULT } ]...
       )
[ where_clause ]

where_clause写法:
WHERE condition

语法解析:
INTO子句
使用INTO子句指定要更新或插入的目标表或视图。
USING子句
使用USING子句指定要更新或插入记录的来源,即这些记录来自于哪里,可以是表或视图或子查询,注意子查询要用括号括起来。
ON子句
使用ON子句指定MERGE操作更新或插入的条件。对于目标表中搜索条件为true的每一行,Oracle数据库都会用源中的相应数据更新该行。如果任何行的条件都不为真,则数据库将根据相应的源行插入目标表。
merge_update子句
merge_update_clause子句指定目标表或视图的新列值。如果ON子句的条件为真,Oracle将执行此更新。如果执行了update子句,那么目标表上定义的所有更新触发器都将被激活。
这里还可以指定where条件,即where条件为真才更新。
merge_insert子句
如果ON子句的条件为false,则merge_insert_子句指定要插入到目标表列中的值。如果执行了insert子句,那么目标表上定义的所有插入触发器都将被激活。如果在INSERT关键字后省略列列表,则目标表中的列数必须与values子句中的值数匹配。
这里还可以指定where条件,即where条件为真才插入。

使用示例:

CREATE TABLE TY1(name varchar2(100), lev varchar2(100), age number);
CREATE TABLE TY2(name varchar2(100), lev varchar2(100), addr varchar2(100), age number);

INSERT INTO TY1('jack','level-10',23);
INSERT INTO TY1('rose','level-11',20);

INSERT INTO TY2('jack','level-9','addr1',19);
INSERT INTO TY2('hhj','level-10','addr2',18);

MERGE INTO TY1 
USING TY2 
ON (TY1.NAME = TY2.NAME)
WHEN MATCHED THEN
 UPDATE SET TY1.LEV =TY2.LEV,TY1.AGE = TY2.AGE 
WHEN NOT MATCHED THEN
 INSERT  VALUES (TY2.NAME,TY2.LEV,TY2.AGE)
 
最终TY1表里结果为:
jack,level-9,19
rose,level-11,20
hhj,level-10,18

2. 确定性语义问题示例展示

这里我们来展示一个上面说的确定性语义的问题,即在同一个MERGE语句中多次更新目标表的同一行。

正确示例:但是这里不会报错,因为多次更新同一行也是得到了一个确定性的结果(TY2里的两条jack的记录虽然更新了2次TY1,但是更新结果一致)。

清空上面的TY1和TY2表记录,重新插入:

DELETE FROM TY1;
DELETE FROM TY2;
INSERT INTO TY1('jack','level-10',23);
INSERT INTO TY1('rose','level-11',20);

INSERT INTO TY2('jack','level-9','addr1',19);
INSERT INTO TY2('jack','level-9','addr1',19);
INSERT INTO TY2('hhj','level-10','addr2',18);

MERGE INTO TY1 
USING TY2 
ON (TY1.NAME = TY2.NAME)
WHEN MATCHED THEN
 UPDATE SET TY1.LEV =TY2.LEV,TY1.AGE = TY2.AGE 
WHEN NOT MATCHED THEN
 INSERT  VALUES (TY2.NAME,TY2.LEV,TY2.AGE)

最终TY1表里结果为:
jack,level-9,19
rose,level-11,20
hhj,level-10,18

错误示例:但是这里会报错,因为多次更新同一行是得到了不同的,也就是不确定性的结果(TY2里的两条jack的记录更新了2次TY1,但是更新结果不一致,一个是level-8,一个是level-9)。
清空上面的TY1和TY2表记录,重新插入:

DELETE FROM TY1;
DELETE FROM TY2;
INSERT INTO TY1('jack','level-10',23);
INSERT INTO TY1('rose','level-11',20);

INSERT INTO TY2('jack','level-9','addr1',19);
INSERT INTO TY2('jack','level-8','addr1',19);
INSERT INTO TY2('hhj','level-10','addr2',18);

MERGE INTO TY1 
USING TY2 
ON (TY1.NAME = TY2.NAME)
WHEN MATCHED THEN
 UPDATE SET TY1.LEV =TY2.LEV,TY1.AGE = TY2.AGE 
WHEN NOT MATCHED THEN
 INSERT  VALUES (TY2.NAME,TY2.LEV,TY2.AGE)

最终TY1表里结果为:
报错

3. 根据某条数据来更新或插入示例展示

MERGE INTO TY1 t1
USING (SELECT 'jack' AS NAME, 'LEV-001' AS LEV, 34 AS AGE FROM DUAL) t2
ON (t1.NAME = t2.NAME)
WHEN MATCHED THEN
 UPDATE SET t1.LEV =t2.LEV,t1.AGE = t2.AGE 
WHEN NOT MATCHED THEN
 INSERT  VALUES (t2.NAME,t2.LEV,t2.AGE)

4. 注意点

1. 在 on里面的判断条件,假如有null或空字符串,会导致merge的时候一直是插入,不会更新。

### SQL 中 `MERGE INTO` 语句的使用方法 `MERGE INTO` 是一种强大的 SQL 数据操作语言(DML),允许在一个单一的操作中完成数据的插入、更新甚至删除。其主要功能是基于条件判断来决定对目标表执行何种操作。 #### 基本语法结构 以下是标准的 `MERGE INTO` 语句的基本形式: ```sql MERGE INTO target_table alias1 USING (source_table | view | subquery) alias2 ON (join_condition) WHEN MATCHED THEN UPDATE SET column1 = value1, column2 = value2, ... WHEN NOT MATCHED THEN INSERT (column_list) VALUES (value_list); ``` 此语法的核心部分包括以下几个组件: - **target_table**: 被修改的目标表。 - **source_table/view/subquery**: 提供数据的源表、视图或者子查询。 - **join_condition**: 定义目标表和源之间的连接条件。 - **WHEN MATCHED THEN UPDATE**: 当记录匹配时,执行更新操作。 - **WHEN NOT MATCHED THEN INSERT**: 当记录不匹配时,执行插入操作。 #### 实际应用案例 下面通过具体例子展示如何利用 `MERGE INTO` 将来自另一个表的数据同步至当前表。 假设存在两个表:一个是主用户信息表 `users`,另一个是从其他系统导入的新地址信息临时存储表 `users_updates`。我们希望将新地址信息合并到现有用户的记录里;如果某些 ID 对应的用户不存在,则新增这些用户。 ```sql -- 合并逻辑实现 MERGE INTO users AS u USING users_updates AS uu ON (u.id = uu.id) WHEN MATCHED THEN -- 更新已存在的用户地址字段 UPDATE SET u.address = uu.address WHEN NOT MATCHED THEN -- 插入新的用户条目,默认姓名为空字符串"" INSERT (id, name, address) VALUES (uu.id, '', uu.address); ``` 这段脚本解释了当两者的 id 字段相等时进行更新动作,而一旦发现有未映射的关系则触发插入行为[^3]。 值得注意的是,在实际开发过程中还需要考虑更多细节问题,比如冲突解决策略、性能优化以及事务管理等方面的内容。 #### 特殊情况处理——包含 DELETE 功能扩展 除了基本的插入与更新外,还可以进一步增强该命令的功能范围以支持行级删除。例如: ```sql MERGE INTO employees e USING department d ON (e.department_id = d.id AND d.status='inactive') WHEN MATCHED THEN DELETE; ``` 这里演示了一个场景,即移除那些所属部门状态标记为 inactive 的员工记录[^2]。 ### 总结 综上所述,`MERGE INTO` 不仅简化了复杂的 ETL 流程,而且提高了批量数据维护工作的效率。然而,在运用这项技术之前应当充分理解业务需求,并仔细测试可能产生的副作用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sf_www

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值