插入如果不存在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;