4

SQLLDR を介して Oracle にデータをロードしています。ソースファイルは「パイプ区切り」です。

FIELDS TERMINATED BY '|'

ただし、一部のレコードでは、セパレータとしてではなく、データにパイプ文字が含まれています。そのため、データパイプ文字をフィールド ターミネータとして認識するため、レコードの正しいロードが中断されます。

この問題を解決するための方向性を教えてもらえますか?

データファイルは約9GBなので、手動で編集するのは大変です。

例えば、

ロードされた行:

ABC|1234567|STR 9 R 25|98734959,32|28.12.2011

拒否された行:

DE4|2346543|WE| 454|956584,84|28.11.2011

エラー:

Rejected - Error on table HSX, column DATE_N.
ORA-01847: day of month must be between 1 and last day of month

DATE_N 列が最後の列です。

4

3 に答える 3

5

セパレータを使用することはできず、次のようなことを行うことができます。

field FILLER,
col1 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\1')",
col2 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\2')",
col3 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\3')",
col4 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\4')",
col5 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\5')",
col6 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\6')"

この正規表現は、垂直バーで区切られた6つのキャプチャグループ(括弧内)を取ります(それ以外の場合は正規表現でORを意味するため、エスケープする必要がありました)。3番目を除くすべてのグループに縦棒([^|]*)を含めることはできず、3番目のグループには何でも含めることができ(.*)、正規表現は行の最初から最後まで(^および$)にまたがる必要があります。

このようにして、3番目のグループがすべての余分なセパレーターを食べることを確信しています。これは、区切り文字を含む可能性のあるフィールドが1つしかないためにのみ機能します。プルーフチェックが必要な場合は、たとえば、4番目のグループが数字で始まるように指定できます(\d4番目の括弧で囲まれたブロックの先頭に含めます)。

二重引用符で囲まれた式の中にあるため、すべての円記号を2倍にしましたが、そうすべきかどうかはよくわかりません。

于 2012-01-20T15:53:56.660 に答える
2

OK、ファイルを解析して区切り文字を置き換えることをお勧めします。Unix/Linux のコマンド ラインでは、次のことを行う必要があります。

cat current_file | awk -F'|' '{printf( "%s,%s,", $1, $2); for(k=3;k<NF-2;k++) printf("%s|", $k); printf("%s,%s,%s", $(NF-2),$(NF-1),$NF);print "";}' > new_file

このコマンドは、現在のファイルを変更しません。5 つのフィールドを持つカンマ区切りの新しいファイルを作成します。入力ファイルを「|」で分割します そして、最初、2 番目、すべてをアンテラスト、アンテラスト、および最後のチャンクに取ります。

「、」区切り文字を使用して new_file を sqlldr することができます。

更新: コマンドは、(および parse.awk という名前の) ようなスクリプトに入れることができます。

#!/usr/bin/awk
# parse.awk
BEGIN {FS="|"}
{
printf("%s,%s,", $1, $2);

for(k=3;k<NF-2;k++)
        printf("%s|", $k);

printf("%s,%s,%s\n", $(NF-2),$(NF-1),$NF);
}

次の方法で実行できます。

cat current_file | awk  -f parse.awk > new_file
于 2012-01-20T15:36:49.463 に答える
2

SQL*Loader でファイルを処理することは実際には不可能であるように思われます。これは、区切り文字を含めることができ、引用符で囲まれておらず、可変長である 3 番目のフィールドが原因です。代わりに、提供されたデータが正確な例である場合は、サンプルの回避策を提供できます。まず、ファイル内の任意の 1 行の最大長と同じ長さの VARCHAR2 の 1 列を持つテーブルを作成します。次に、ファイル全体をこのテーブルにロードします。そこから、次のようなクエリを使用して各列を抽出できます。

with CTE as
       (select 'ABC|1234567|STR 9 R 25|98734959,32|28.12.2011' as CTETXT
          from dual
        union all
        select 'DE4|2346543|WE| 454|956584,84|28.11.2011' from dual)
select substr(CTETXT, 1, instr(CTETXT, '|') - 1) as COL1
      ,substr(CTETXT
             ,instr(CTETXT, '|', 1, 1) + 1
             ,instr(CTETXT, '|', 1, 2) - instr(CTETXT, '|', 1, 1) - 1)
         as COL2
      ,substr(CTETXT
             ,instr(CTETXT, '|', 1, 2) + 1
             ,instr(CTETXT, '|', -1, 1) - instr(CTETXT, '|', 1, 2) - 1)
         as COL3
      ,substr(CTETXT, instr(CTETXT, '|', -1, 1) + 1) as COL4
  from CTE

これは完全ではありませんが (SQL*Loader には適応できるかもしれませんが)、より多くの列がある場合、または 3 番目のフィールドが私が考えているものと異なる場合は、少し作業が必要になります。でも、スタートです。

于 2012-01-20T15:14:51.573 に答える