我需要能够运行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中执行此操作,可以获得奖励积分。
答案 0 :(得分:36)
迟到了,但是......
使用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')
;
更新:虽然此提示有效(如果拼写正确),但better approaches不需要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;
第二个aproach-a lot 比上述两个提示更快时出现了很多争用:
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;
答案 1 :(得分:24)
该声明称为MERGE。看起来,我太懒了。
请注意,MERGE不是原子的,可能会产生以下影响(谢谢,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, d.i) VALUES (s.pk, s.i);
SESS2:commit;
SESS1:ORA-00001
答案 2 :(得分:17)
仅当要插入的项目尚未存在时才会插入。
与以下内容相同:
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;
可能不漂亮,但它很方便:)
答案 3 :(得分:10)
我们可以将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'
);
答案 4 :(得分:9)
如果您不想从其他表中合并,而是插入新数据......我想出了这个。有没有更好的方法来做到这一点?
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);
答案 5 :(得分:5)
该代码在客户端上,然后您有许多访问服务器,以消除它。
将所有数据插入到临时表中,例如T,其结构与myFoo相同
然后
insert myFoo
select *
from t
where t.primary_key not in ( select primary_key from myFoo)
这也适用于其他数据库 - 我在Sybase上做过这个
如果您通过线路复制了所有数据,那么插入的新数据非常少是不是最好的。
答案 6 :(得分:4)
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的代码。
答案 7 :(得分:0)
这是对erikkallen发表的评论的回答:
您不需要临时表。如果你 只有几行,(SELECT 1 FROM 双UNION SELECT 2 FROM dual)将 做。为什么你的例子会给出 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, d.i) VALUES (s.pk, s.i);
SESS2:commit;
SESS1:ORA-00001
答案 8 :(得分:0)
如果你的表与其他人“独立”(我的意思是,它不会触发级联删除或不会将任何外键关系设置为null),一个很好的技巧可能是首先删除该行然后再次插入它。它可以是这样的:
DELETE FROM MyTable WHERE prop1 ='aaa'; //假设它最多会选择一行!
INSERT INTO MyTable(prop1,...)VALUES('aaa',...);
如果您要删除不存在的内容,则不会发生任何事情。
答案 9 :(得分:0)
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;