0

それが可能かどうかはわかりませんが、一時テーブルから通常のテーブルに大量のレコードをコピーしたいと考えています。問題は、一部のレコードがチェック制約に違反する可能性があることです。そのため、可能なすべてのものを挿入し、無効なレコードのエラー ログを別の場所に生成したいと考えています。

私が実行した場合:

INSERT INTO normal_table
  SELECT ... FROM temp_table

いずれかのレコードが制約に違反している場合、何も挿入されません。ループを作って手動で1つずつ挿入することもできましたが、パフォーマンスが低下すると思います。

Ps: 可能であれば、Oracle 9 で動作するソリューションが欲しいです。

4

2 に答える 2

3

log errorsOracle 10gR2から、次の句を使用できます。

EXECUTE DBMS_ERRLOG.CREATE_ERROR_LOG('NORMAL_TABLE');
INSERT INTO normal_table
   SELECT ... FROM temp_table
   LOG ERRORS REJECT LIMIT UNLIMITED;

最も単純な形で。次に、発生したエラーを確認できます。

SELECT ora_err_mesg$
FROM err$_normal_table;

ここCREATE_ERROR_LOGでの手順の詳細。


このアプローチは9iから機能すると思いますが、テストに使用できるインスタンスがないため、これは実際には11gR2
アップデートで実行されます。9iでテストおよび調整(PLS-00436を回避するため):

declare
    type t_temp_table is table of temp_table%rowtype;
    l_temp_table t_temp_table;
    l_err_code err_table.err_code%type;
    l_err_msg err_table.err_msg%type;
    l_id err_table.id%type;

    cursor c is select * from temp_table;

    error_array exception;
    pragma exception_init(error_array, -24381);
begin
    open c;
    loop
        fetch c bulk collect into l_temp_table limit 100;
        exit when l_temp_table.count = 0;

        begin
            forall i in 1..l_temp_table.count save exceptions
                insert into normal_table
                values l_temp_table(i);
        exception
            when error_array then
                for j in 1..sql%bulk_exceptions.count loop
                    l_id := l_temp_table(sql%bulk_exceptions(j).error_index).id;
                    l_err_code := sql%bulk_exceptions(j).error_code;
                    l_err_msg := sqlerrm(-1 * sql%bulk_exceptions(j).error_code);
                    insert into err_table(id, err_code, err_msg)
                    values (l_id, l_err_code, l_err_msg);
                end loop;
        end;
    end loop;
end;
/

idデモの目的で行った、単なるではなく、すべての実際の列を使用します。

create table normal_table(id number primary key);
create table temp_table(id number);
create table err_table(id number, err_code number, err_msg varchar2(2000));

insert into temp_table values(42);
insert into temp_table values(42);

次に、上記の匿名ブロックを実行します...

select * from normal_table;

        ID
----------
        42

column err_msg format a50
select * from err_table;

        ID   ERR_CODE ERR_MSG                                          
---------- ---------- --------------------------------------------------
        42          1 ORA-00001: unique constraint (.) violated          

これは、いくつかのレベルでは満足のいくものではありません-コーディングが多く、例外がたくさんある場合は遅くなり(それらの個々の挿入のため)、違反した制約(または他のエラーの詳細)が表示されず、表示されませんロールバックしてもエラーを保持します。ただし、それが問題である場合は、自律型トランザクションを呼び出してログに記録することもできますが、ここでは疑問です。

句について心配したくないほど少量のデータがある場合はlimit、少し単純化できます。

declare
    type t_temp_table is table of temp_table%rowtype;
    l_temp_table t_temp_table;
    l_err_code err_table.err_code%type;
    l_err_msg err_table.err_msg%type;
    l_id err_table.id%type;

    error_array exception;
    pragma exception_init(error_array, -24381);
begin
    select * bulk collect into l_temp_table from temp_table;

    forall i in 1..l_temp_table.count save exceptions
        insert into normal_table
        values l_temp_table(i);
exception
    when error_array then
        for j in 1..sql%bulk_exceptions.count loop
            l_id := l_temp_table(sql%bulk_exceptions(j).error_index).id;
            l_err_code := sql%bulk_exceptions(j).error_code;
            l_err_msg := sqlerrm(-1 * sql%bulk_exceptions(j).error_code);
            insert into err_table(id, err_code, err_msg)
            values (l_id, l_err_code, l_err_msg);
        end loop;
end;
/

9iのドキュメントはもうオンラインではないようですが、これは新機能のドキュメントであり、多くの人がそれについて書いています-以前にもここで質問されました。

于 2013-02-15T11:41:36.367 に答える
0

チェック制約のみに特に関心がある場合は、データ ディクショナリからターゲット チェック制約の定義を読み取り、動的 SQL を使用してソース テーブルからデータを抽出するクエリに述語として適用する方法を 1 つ考えてみてください。

与えられた:

 create table t1 (
   col1 number check (col1 between 3 and 10))

あなたはできる:

select  constraint_name,
        search_condition
from    user_constraints
where   constraint_type = 'C' and
        table_name = 'T1'

結果は次のとおりです。

"SYS_C00226681"、"col1 は 3 から 10 の間"

彼らが言うように、そこからは「コーディングの簡単な問題」であり、この方法はほぼすべてのバージョンの Oracle で機能します。最も効率的な方法は、チェック制約述部を適用する CASE ステートメントの結果に基づいて、複数テーブルの挿入を使用して、目的のターゲット テーブルまたはエラー ログ テーブルに行を送信することです。

于 2013-02-15T14:43:17.767 に答える