首页 文章

插入如果不存在oracle

提问于
浏览
42

我需要能够运行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

    该声明称为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

  • 5

    迟到了,但......

    使用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')
         ;
    

    UPDATE :虽然这个提示有效(如果拼写正确),但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;
    

    第二个方法 - 比以上两个提示要快得多:

    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;
    
  • 4

    仅当要插入的项目尚未存在时才会插入 .

    作用相同:

    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;
    

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

  • 9

    我们可以将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'
    );
    
  • 17

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

    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);
    
  • 0

    它代码在客户端,然后你有许多访问服务器,以消除它 .

    将所有数据插入到临时表中,表示T与myFoo具有相同的结构

    然后

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

    这应该适用于其他数据库 - 我在Sybase上完成了这项工作

    如果您通过线路复制了所有数据,那么插入新数据的次数并不是最好的 .

  • 24
    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的代码 .

  • 36

    这是对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

  • 10

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

    DELETE FROM MyTable WHERE prop1 ='aaa'; //假设它最多会选择一行!

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

    如果您要删除不存在的内容,则不会发生任何事情 .

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

相关问题