UPSERT操作在表中更新或插入一行,这取决于表中是否已经有与数据匹配的行:

if table t has a row exists that has key X:
    update t set mystuff... where mykey=X
else
    insert into t mystuff...

既然Oracle没有特定的UPSERT语句,那么最好的方法是什么呢?


当前回答

MERGE语句合并两个表之间的数据。使用双 允许我们使用此命令。请注意,这没有针对并发访问进行保护。

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;

A                      B
---------------------- ----------------------
10                     2
20                     1

其他回答

MERGE语句合并两个表之间的数据。使用双 允许我们使用此命令。请注意,这没有针对并发访问进行保护。

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;

A                      B
---------------------- ----------------------
10                     2
20                     1

关于两种解决方案的说明如下:

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

or

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

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

如果你选错了,你会得到一堆不必要的索引读取。不是什么大问题,但仍然值得考虑。

如果不存在,请插入 更新:

    
INSERT INTO mytable (id1, t1) 
  SELECT 11, 'x1' FROM DUAL 
  WHERE NOT EXISTS (SELECT id1 FROM mytble WHERE id1 = 11); 

UPDATE mytable SET t1 = 'x1' WHERE id1 = 11;

从http://www.praetoriate.com/oracle_tips_upserts.htm:

在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;

没有异常检查的另一种方法:

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;