46

多数の行を挿入する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でこれを行う方法を教えていただければボーナスポイント。

4

10 に答える 10

37

パーティーに遅れて来るが...

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

更新:このヒントは機能しますが(正しく綴れば)、Oracle11R2を必要としないより良いアプローチがあります。

最初のアプローチ-上記のセマンティックヒントの直接翻訳:

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

2番目のアプローチ-多くの競合がある場合、上記の両方のヒントよりもはるかに高速です。

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;
于 2011-02-25T08:30:38.333 に答える
28

このステートメントは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

于 2009-11-09T19:22:47.317 に答える
18

これは、挿入されるアイテムがまだ存在しない場合にのみ挿入されます。

次と同じように機能します。

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;

きれいではないかもしれませんが、便利です:)

于 2011-03-18T03:29:50.980 に答える
17

とを組み合わせてDUALNOT 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'
);
于 2016-02-24T10:04:52.670 に答える
15

他のテーブルからマージするのではなく、新しいデータを挿入する場合...私はこれを思いつきました。これを行うためのより良い方法はおそらくありますか?

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);
于 2013-04-23T07:08:00.933 に答える
5

そのコードがクライアント上にある場合、それを排除するためにサーバーに何度もアクセスする必要があります。

myFooと同じ構造のTなどの一時テーブルにすべてのデータを挿入します

それで

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

これは他のデータベースでも機能するはずです-私はSybaseでこれを行いました

すべてのデータをネットワーク経由でコピーしたため、新しいデータをほとんど挿入しない場合は最適ではありません。

于 2009-11-09T18:48:40.357 に答える
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のコードに似ています。

于 2012-06-13T13:27:16.133 に答える
1

テーブルが他のテーブルから「独立」している場合(つまり、カスケード削除をトリガーしないか、外部キー関係をnullに設定しない場合)、最初に行を削除してから再度挿入するのが良いトリックです。これは次のようになります。

MyTableから削除WHEREprop1='aaa'; //最大で1行を選択すると仮定します!

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

存在しないものを削除する場合、何も起こりません。

于 2013-10-28T14:28:22.567 に答える
0

これは、erikkallenによって投稿されたコメントへの回答です。

一時テーブルは必要ありません。行数が少ない場合は、(SELECT 1 FROM dual 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

于 2009-11-09T22:15:13.327 に答える
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)はnullです。

于 2015-11-25T15:42:49.843 に答える