oracle 编程怎么更新一行,Oracle:如何UPSERT(更新或插入表)?

MERGE语句在两个表之间合并数据。 使用DUAL允许我们使用这个命令。

create or replace procedure ups(xa number) as begin merge into mergetest m using dual on (a = xa) when not matched then insert (a,b) values (xa,1) when matched then update set b = b+1; end ups; / drop table mergetest; create table mergetest(a number, b number); call ups(10); call ups(10); call ups(20); select * from mergetest; AB ---------------------- ---------------------- 10 2 20 1

上面的PL / SQL的双重例子是伟大的,因为我想要做类似的事情,但我想它的客户端…所以这里是我用来发送类似的声明直接从一些C#

MERGE INTO Employee USING dual ON ( "id"=2097153 ) WHEN MATCHED THEN UPDATE SET "last"="smith" , "name"="john" WHEN NOT MATCHED THEN INSERT ("id","last","name") VALUES ( 2097153,"smith", "john" )

然而,从C#的角度来看,这比提供更新要慢一些,看看受影响的行是否为0,如果是的话进行插入。

没有例外检查的另一种选择:

UPDATE tablename SET val1 = in_val1, val2 = in_val2 WHERE val3 = in_val3; IF ( sql%rowcount = 0 ) THEN INSERT INTO tablename VALUES (in_val1, in_val2, in_val3); END IF;

MERGE的另一种选择(“老式的方式”):

begin insert into t (mykey, mystuff) values ('X', 123); exception when dup_val_on_index then update t set mystuff = 123 where mykey = 'X'; end;

插入如果不存在

更新:

INSERT INTO mytable(id1,t1)

选择11,'x1'从双

WHERE NOT EXISTS(SELECT id1 FROM mytble WHERE id1 = 11);

更新mytable SET t1 ='x1'WHERE id1 = 11;

正如Tim Sylvester的评论所指出的,迄今为止所给出的答案在面对同时访问时是安全的,并且会在种族方面提出例外。 为了解决这个问题,insert / update组合必须被包装在某种循环语句中,以便在发生异常的情况下重试整个事件。

作为一个例子,下面是Grommit的代码如何在一个循环中打包,以便在并发运行时保证安全:

PROCEDURE MyProc ( ... ) IS BEGIN LOOP BEGIN MERGE INTO Employee USING dual ON ( "id"=2097153 ) WHEN MATCHED THEN UPDATE SET "last"="smith" , "name"="john" WHEN NOT MATCHED THEN INSERT ("id","last","name") VALUES ( 2097153,"smith", "john" ); EXIT; -- success? -> exit loop EXCEPTION WHEN NO_DATA_FOUND THEN -- the entry was concurrently deleted NULL; -- exception? -> no op, ie continue looping WHEN DUP_VAL_ON_INDEX THEN -- an entry was concurrently inserted NULL; -- exception? -> no op, ie continue looping END; END LOOP; END;

NB在交易模式SERIALIZABLE ,我不推荐顺便说一句,你可能会遇到ORA-08177:不能序列化访问这个事务异常,而不是。

我想Grommit的回答,除了它需要dupe值。 我发现解决方案可能会出现一次: http : //forums.devshed.com/showpost.php?p=1182653&postcount=2

MERGE INTO KBS.NUFUS_MUHTARLIK B USING ( SELECT '028-01' CILT, '25' SAYFA, '6' KUTUK, '46603404838' MERNIS_NO FROM DUAL ) E ON (B.MERNIS_NO = E.MERNIS_NO) WHEN MATCHED THEN UPDATE SET B.CILT = E.CILT, B.SAYFA = E.SAYFA, B.KUTUK = E.KUTUK WHEN NOT MATCHED THEN INSERT ( CILT, SAYFA, KUTUK, MERNIS_NO) VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO);

关于两个解决方案的说明建议:

1)插入,如果异常则更新,

要么

2)更新,如果sql%rowcount = 0,然后插入

是否插入或更新的问题也取决于应用程序。 你期望更多的插入或更新? 最有可能成功的人应该先走。

如果你选错了,你会得到一堆不必要的索引读取。 没有什么大不了的,但还是需要考虑。

我一直在使用第一个代码示例多年。 没有发现通知,而不是计数。

UPDATE tablename SET val1 = in_val1, val2 = in_val2 WHERE val3 = in_val3; IF ( sql%notfound ) THEN INSERT INTO tablename VALUES (in_val1, in_val2, in_val3); END IF;

下面的代码是可能是新的和改进的代码

MERGE INTO tablename USING dual ON ( val3 = in_val3 ) WHEN MATCHED THEN UPDATE SET val1 = in_val1, val2 = in_val2 WHEN NOT MATCHED THEN INSERT VALUES (in_val1, in_val2, in_val3)

在第一个示例中,更新执行索引查找。 它必须,为了更新正确的行。 Oracle打开一个隐式游标,我们用它来包装一个相应的插入,所以我们知道插入只有当密钥不存在时才会发生。 但插入是一个独立的命令,它必须做第二次查找。 我不知道合并命令的内部工作原理,但由于命令是一个单元,因此Oracle可以通过单个索引查找执行正确的插入或更新。

我认为当你需要完成一些处理时,合并会更好,这意味着从某些表中获取数据并更新表,可能会插入或删除行。 但是对于单行情况,您可能会考虑第一种情况,因为语法更常见。

复制并粘贴示例将一个表插入另一个表,使用MERGE:

CREATE GLOBAL TEMPORARY TABLE t1 (id VARCHAR2(5) , value VARCHAR2(5), value2 VARCHAR2(5) ) ON COMMIT DELETE ROWS; CREATE GLOBAL TEMPORARY TABLE t2 (id VARCHAR2(5) , value VARCHAR2(5), value2 VARCHAR2(5)) ON COMMIT DELETE ROWS; ALTER TABLE t2 ADD CONSTRAINT PK_LKP_MIGRATION_INFO PRIMARY KEY (id); insert into t1 values ('a','1','1'); insert into t1 values ('b','4','5'); insert into t2 values ('b','2','2'); insert into t2 values ('c','3','3'); merge into t2 using t1 on (t1.id = t2.id) when matched then update set t2.value = t1.value, t2.value2 = t1.value2 when not matched then insert (t2.id, t2.value, t2.value2) values(t1.id, t1.value, t1.value2); select * from t2

结果:

b 4 5

c 3 3

1 1

尝试这个,

insert into b_building_property ( select 'AREA_IN_COMMON_USE_DOUBLE','Area in Common Use','DOUBLE', null, 9000, 9 from dual ) minus ( select * from b_building_property where id = 9 ) ;

“在Oracle9i中,UPSERT可以用一个语句完成这个任务:”

INSERT FIRST WHEN credit_limit >=100000 THEN INTO rich_customers VALUES(cust_id,cust_credit_limit) INTO customers ELSE INTO customers SELECT * FROM new_customers;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值