2012-03-05 17 views
0

forallを使用してMY_TABLEにレコードを挿入したいとします。しかし、のデータが挿入されたレコードの各テストの実行で変更し続けます!私はループカウンターと関係があると思いますが、わかりません。コードスニペットは次のとおりです。テーブルに正しくレコードを挿入し、pl/sqlでforallを挿入する方法

DECLARE 
    TYPE l_rec_type IS RECORD (
     datakey SOURCE_TABLE.datakey%TYPE, 
     sourcekey SOURCE_TABLE.sourcekey%TYPE, 
     DESCRIPTION SOURCE_TABLE.DESCRIPTION%TYPE, 
     dimension_name SOURCE_TABLE.dimension_name%TYPE , 
     data_type SOURCE_TABLE.data_type%TYPE 

    ); 


    TYPE l_table_type IS TABLE OF l_rec_typeINDEX BY PLS_INTEGER; 
    l_table l_table_type; 
    l_cntr NUMBER; 
BEGIN 
    FOR rec_dimname IN (SELECT dimension_name FROM dimension_table) LOOP 
    l_cntr1 := 1 
    FOR rec_source IN (SELECT * FROM source_table WHERE data_type IS NOT NULL) LOOP 
     l_table(l_ctr1).datakey := rec_source.datakey; 
     l_table(l_ctr1).sourcekey := rec_source.sourcekey; 
     l_table(l_ctr1).DESCRIPTION := rec_source.DESCRIPTION; 
     l_table(l_ctr1).dimension_name := rec_source.dimension_name; 
     l_table(l_ctr1).data_type := rec_source.data_type; 
     l_cntr1 := l_cntr1+1; 
    END LOOP 
    FORALL j IN l_table.FIRST..l_table.LAST 
     INSERT INTO my_table VALUES(l_table(j).datakey, 
            l_table(j).sourcekey, 
            l_table(j).DESCRIPTION, 
            l_table(j).dimension_name, 
            l_table(j).data_type, 
            1, 
            SYSDATE, 
            login_id        
           ); 

    END LOOP; 
END; 

私は間違っていますか? forループを使用した通常の挿入では5000レコードが挿入されます。私が直面している別の問題は、forallを使ってWHEN DUP_VAL_ON_INDEXと他の例外を処理する方法です。野生のためのループは簡単です。しかし、私は高速挿入のためにFORALLを使用しなければなりません。助けてください!

答えて

1

コードを見ると、ループ内のpl/tableに保存されているデータは削除されず、クエリにはorder byが含まれていないことがわかります。したがって、最初の反復でより多くのデータがある場合は、2番目の反復でデータが重複します。

だからあなたl_cntr1 VAR(l_cntr1 := 1)を初期化した後、あなたのPL /テーブルをクリアする必要があります。

l_table.delete; 

お役に立てば幸いです。

+0

おかげで...私はそれは私の問題を解決を願って。これをしようとします。.. – Arcs

+0

はい 'l_table.delete'は...魔法のように助け – Arcs

+0

グレートに感謝を働きました!喜んで助けてください:) –

0

dimension_tableにループするだけで、同じことを複数回繰り返しているように見えます。つまり、次のように簡略化して高速化できます。下にはforallバージョンがあります。

いずれのバージョンでもexception when dup_val_on_indexを使用することはできません。行ごとに行う必要があります。あなたが投稿したことだけで判断私はあなたが実際にあなたが1つのクエリでやろうとしていることを達成し、この問題を完全に(重複値を扱うことを含めて)保存できると思います。

declare 

    cursor c_src is 
    select datakey, sourcekey, description, dimension_name 
     , data_type, 1, sysdate, login_id -- previously missing 
     from source_table 
    where data_type is not null; 

    type t__src is table of c_src%rowtype index by binary_integer; 
    t_src t__src; 

    i integer; 

begin 

    select count(*) 
    into i 
    from dimension_table; 

    for j in 1 .. i loop 

     open c_src; 
     loop 

     fetch c_src bulk collect into t_src; 

     forall k in t_src.first .. t_src.last 
      insert into my_table (datakey, sourcekey, description 
           , dimension_name, someother_column 
           , some_date_column, login_id 
      values t_src; 

     end loop; 
     close c_src; 

    end loop; 
    commit; 

end; 
/
+0

Hii ..私はあなたに同意します。しかし、私は私のテーブルに挿入する前に行く特定の検証ロジックのために2つのループを持つ必要があります。コードスニペットは、コードデザインの概要です。カーソルからデータを直接選択していないので、BULK COLLECTは使用できません。私はテーブル型の要素を初期化する必要があります。私はちょうど例外を保存することについて読んでいます。私はそれを組み込むことができるかもしれません。私はそれに事前のコーディング経験がありません。実際には、全体のデザインは、通常のforループ内のMY_TABLEへのInsertとして作成されました。例外の間に例外が発生したときはいつでも、それが処理され、ループカウンタがインクリメントされます。 – Arcs

+0

しかし、今や、テーブルへの通常の挿入は、8〜9時間という膨大な時間を要しています。だから私はインサートのためにFORALLを取り入れようとしています。 – Arcs

+0

@Arcs、あなたが投稿したすべてがあなたの実際の質問とは何の関係もないと言ったばかりです!現時点であなたが行っていることで '一括収集 'を使うことができます。あなたはカーソルから直接選択しています。あなたのタイプの値を更新しているなら、 'bulk collect'を使うことができます!あなたの実際の問題は何ですか? – Ben

1

はここで、固定コードです:

declare 

    i integer; 

begin 

    select count(*) 
    into i 
    from dimension_table; 

    for j in 1 .. i loop 

     insert into my_table (datakey, sourcekey, description 
          , dimension_name, someother_column 
          , some_date_column, login_id 
     select datakey, sourcekey, description, dimension_name 
      , data_type, 1, sysdate, login_id -- previously missing 
      from source_table 
     where data_type is not null; 

    end loop; 
    commit; 

end; 
/

は場合は、しかし、あなたは本当にあなたがこのような何かを行うことができますforallを使用します。プラスSAVE EXCEPTIONS本当に私の日を保存!ここで私はこのソリューションを実装しました。貴重な時間と提案をいただき、ありがとうございます。

DECLARE 
     TYPE l_rec_type IS RECORD (
      datakey SOURCE_TABLE.datakey%TYPE, 
      sourcekey SOURCE_TABLE.sourcekey%TYPE, 
      DESCRIPTION SOURCE_TABLE.DESCRIPTION%TYPE, 
      dimension_name SOURCE_TABLE.dimension_name%TYPE , 
      data_type SOURCE_TABLE.data_type%TYPE 

     ); 


     TYPE l_table_type IS TABLE OF l_rec_typeINDEX BY PLS_INTEGER; 
     l_table l_table_type; 
     l_cntr NUMBER; 
     ex_dml_errors EXCEPTION; 
     PRAGMA EXCEPTION_INIT(ex_dml_errors, -24381); 
     login_id NUMBER := -1; 
     errm VARCHAR2(512); 
     err_indx NUMBER 
    BEGIN 
     FOR rec_dimname IN (SELECT dimension_name FROM dimension_table) LOOP 
     l_cntr1 := 1; 
     l_table.DELETE; -- Added 
     FOR rec_source IN (SELECT * FROM source_table WHERE data_type IS NOT NULL) LOOP 
      l_table(l_ctr1).datakey := rec_source.datakey; 
      l_table(l_ctr1).sourcekey := rec_source.sourcekey; 
      l_table(l_ctr1).DESCRIPTION := rec_source.DESCRIPTION; 
      l_table(l_ctr1).dimension_name := rec_source.dimension_name; 
      l_table(l_ctr1).data_type := rec_source.data_type; 
      l_cntr1 := l_cntr1+1; 
     END LOOP 
     FORALL j IN l_table.FIRST..l_table.LAST SAVE EXCEPTIONS 
      INSERT INTO my_table VALUES(l_table(j).datakey, 
             l_table(j).sourcekey, 
             l_table(j).DESCRIPTION, 
             l_table(j).dimension_name, 
             l_table(j).data_type, 
             1, 
             SYSDATE, 
             login_id        
            ); 

      END LOOP; 
     END LOOP; 
     EXCEPTION 
     WHEN ex_dml_errors THEN 
      l_error_count := SQL%BULK_EXCEPTIONS.count; 
      DBMS_OUTPUT.put_line('Number of failures: ' || l_error_count); 
      errm := SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE); 
      err_indx := SQL%BULK_EXCEPTIONS(i).error_index 
      FOR i IN 1 .. l_error_count LOOP 
      DBMS_OUTPUT.put_line('Error: ' || i || 
       ' Array Index: ' || SQL%BULK_EXCEPTIONS(i).error_index || 
       ' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE)); 
       IF errm LIKE '%unique%constraint%violated' THEN -- Insert into my_multiple_entries_tbl on duplicate value on index DATAKEY 
       INSERT INTO my_multiple_entries_tbl(my_multiple_entries_tbl_seq.NEXTVAL, 
                l_table(err_indx).datakey, 
                l_table(err_indx).sourcekey, 
                l_table(err_indx).data_type, 
                SYSDATE, 
                login_id ); 

      ELSE -- Insert into my_other_errors_tbl on other errors 
       INSERT INTO my_other_errors_tbl ( my_other_errors_tbl_seq.NEXTVAL, 
                l_table(err_indx).datakey, 
                l_table(err_indx).sourcekey, 
                l_table(err_indx).data_type, 
                SYSDATE, 
                login_id ); 
      END IF; 
    END; 
+0

あなたは正しい答えを出しますが、誰も理解できないようです。 – Cyryl1972

関連する問題