插入如果不存在oracle

时间:2009-11-09 18:27:58

标签: sql oracle oracle-sqldeveloper

我需要能够运行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中执行此操作,可以获得奖励积分。

10 个答案:

答案 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;