Oracle merge into 为何只能update不能insert ?

一、 问题描述

开发反馈遇到一个奇怪的问题,使用merge语句时只能update但不能insert,简化后语句如下

create table tmp0521("id" int,"state" int);

merge into tmp0521 a
using (select "id","state" from tmp0521 where "id" = 1) b
on (a."id" = b."id")
when matched then
    update set
        a."state"=2
when not matched then
    insert ("id", "state")
values
    (1,0);

如果表中id='1'的值存在,update能执行成功;如果不存在,语句不报错,但也不会insert,显示 0 rows merged。

 

二、 问题原因

merge into a using (...) b on (a.id=b.id),真正含义其实是a表与b表比较,如果数据在:

  • a中存在,b中不存在 --> nothing
  • a中存在,b中也存在 --> update
  • a中不存在,b中存在 --> insert (b into a)
  • a中不存在,b中也不存在 --> nothing

看回前面那个语句,会发现b表其实是a表的子集,它不可能符合数据在“a中不存在,b中存在”这种情况,如果b中没有"id"=1的数据,a中一定也没有,所以它不可能执行insert操作。

a中不存在id=1的数据,b中也不存在,不执行任何操作

 

三、 解决方法

法1. 改为分别使用update和insert

这个没啥好解释了,一定是可以的,并且逻辑也简单。

 

法2. 改写sql语句

将using中的 select "id","state" from tmp0521 where "id" = '1' 改为 select 1 "id",0 "state" from dual此时a和b是不同的表,就可能出现数据在“a中不存在,b中存在”这种情况,可以执行insert。同时建议把 insert ("id", "state") values ('1',0) 对应改为 insert ("id", "state") values (t."id",t."state")。这个改写仅针对前面的sql案例,如果改写生产环境的sql,务必确认好逻辑,进行等价改写。

改写后语句如下:

merge into tmp0521 p
using (select 1 "id",0 "state" from dual) t  -- 改为dual
on (p."id" = t."id")
when matched then
    update set
        p."state"=2
when not matched then
    insert ("id", "state")
values
    (t."id",t."state"); -- 改为插入t表中数据

测试执行:

  • a中不存在id=1的数据,b中存在,执行insert操作

  • a中存在id=1的数据,b中也存在,执行update操作

 

参考

https://ask.csdn.net/questions/351497

https://blog.csdn.net/nobody_2008/article/details/83634398

https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/MERGE.html#GUID-5692CCB7-24D9-4C0E-81A7-A22436DC968F

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hehuyi_In

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值