插入如果不存在oracle

我需要能够运行一个Oracle查询插入一些行,但它也检查是否存在一个主键,如果它确实,然后跳过插入。 就像是:

INSERT ALL IF NOT EXISTS( SELECT 1 WHERE fo.primary_key='bar' ) ( INSERT INTO schema.myFoo fo ( primary_key, value1, value2 ) VALUES ('bar','baz','bat') ), IF NOT EXISTS( SELECT 1 WHERE fo.primary_key='bar1' ) ( INSERT INTO schema.myFoo fo ( primary_key, value1, value2 ) VALUES ('bar1','baz1','bat1') ) SELECT * FROM schema.myFoo; 

Oracle有这个可能吗?

如果你能告诉我如何在PostgreSQL或MySQL中做到这一点,奖励点。

声明被称为MERGE。 看,我太懒了。

但要小心,MERGE不是primefaces的,这可能会导致以下效果(谢谢,Marius):

SESS1:

 create table t1 (pk int primary key, i int); create table t11 (pk int primary key, i int); insert into t1 values(1, 1); insert into t11 values(2, 21); insert into t11 values(3, 31); commit; 

SESS2: insert into t1 values(2, 2);

SESS1:

 MERGE INTO t1 d USING t11 s ON (d.pk = s.pk) WHEN NOT MATCHED THEN INSERT (d.pk, di) VALUES (s.pk, si); 

SESS2: commit;

SESS1: ORA-00001

来晚了,但是…

有了oracle 11.2.0.1,有一个语义提示可以做到这一点: IGNORE_ROW_ON_DUPKEY_INDEX

例:

 insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(customer_orders,pk_customer_orders) */ into customer_orders (order_id, customer, product) values ( 1234, 9876, 'K598') ; 

更新 :虽然这个提示有效(如果你拼写正确),有更好的方法 ,不需要Oracle 11R2:

第一种方法 – 直接翻译以上的语义提示:

 begin insert into customer_orders (order_id, customer, product) values ( 1234, 9876, 'K698') ; commit; exception when DUP_VAL_ON_INDEX then ROLLBACK; end; 

第二个问题 – 比以上两个提示都要快得多,因为争议很多:

 begin select count (*) into l_is_matching_row from customer_orders where order_id = 1234 ; if (l_is_matching_row = 0) then insert into customer_orders (order_id, customer, product) values ( 1234, 9876, 'K698') ; commit; end if; exception when DUP_VAL_ON_INDEX then ROLLBACK; end; 

只有当要插入的项目不存在时才会插入。

工作相同:

 if not exists (...) insert ... 

在T-SQL中

 insert into destination (DESTINATIONABBREV) select 'xyz' from dual left outer join destination d on d.destinationabbrev = 'xyz' where d.destinationid is null; 

可能不漂亮,但它是方便的:)

如果你不想从其他表中合并,而是插入新的数据…我想出了这个。 有没有更好的方法来做到这一点?

 MERGE INTO TABLE1 a USING DUAL ON (a.C1_pk= 6) WHEN NOT MATCHED THEN INSERT(C1_pk, C2,C3,C4) VALUES (6, 1,0,1); 

我们可以结合DUAL和NOT EXISTS来存档您的需求:

 INSERT INTO schema.myFoo ( primary_key, value1, value2 ) SELECT 'bar', 'baz', 'bat' FROM DUAL WHERE NOT EXISTS ( SELECT 1 FROM schema.myFoo WHERE primary_key = 'bar' ); 

它的代码是在客户端上,那么你有很多旅行到服务器,以消除这一点。

将所有的数据插入到一个temportary表中,说T与myFoo具有相同的结构

然后

 insert myFoo select * from t where t.primary_key not in ( select primary_key from myFoo) 

这也应该在其他数据库上工作 – 我已经在Sybase上完成了

如果只有极less数的新数据被插入,就不是最好的,因为您已经通过networking复制了所有的数据。

 DECLARE tmp NUMBER(3,1); BEGIN SELECT COUNT(content_id) INTO tmp FROM contents WHERE (condition); if tmp != 0 then INSERT INTO contents VALUES (...); else INSERT INTO contents VALUES (...); end if; END; 

我使用了上面的代码。 这很长,但是,简单而且为我工作。 类似于Micheal的代码。

这是erikkallen发表的评论的答案:

你不需要临时表。 如果你只有几行,(select1从双UNION SELECT 2 FROM双)将做。 为什么你的例子会给ORA-0001? 不会合并获取索引键上的更新锁,并且不会继续,直到Sess1已提交或回滚? – erikkallen

那么,请自己尝试一下,告诉我你是否得到相同的错误:

SESS1:

 create table t1 (pk int primary key, i int); create table t11 (pk int primary key, i int); insert into t1 values(1, 1); insert into t11 values(2, 21); insert into t11 values(3, 31); commit; 

SESS2: insert into t1 values(2, 2);

SESS1:

 MERGE INTO t1 d USING t11 s ON (d.pk = s.pk) WHEN NOT MATCHED THEN INSERT (d.pk, di) VALUES (s.pk, si); 

SESS2: commit;

SESS1: ORA-00001

如果你的表与别人是“独立的”(我的意思是,它不会触发级联删除或不会设置任何外键关系为空),一个很好的技巧可能是首先删除行,然后再次插入。 它可以这样:

DELETE FROM MyTable WHERE prop1 ='aaa'; / /假设它会select至多一行!

INSERT INTO MyTable(prop1,…)VALUES('aaa',…);

如果你正在删除不存在的东西,什么都不会发生。

 INSERT INTO schema.myFoo(primary_key,value1,value2)
                          SELECT'bar1'AS primary_key,'baz1'AS value1,'bat1'AS value2 FROM DUAL WHERE(SELECT 1 AS value FROM schema.myFoo WHERE LOWER(primary_key)='bar1'AND ROWNUM = 1)is null;