[Oracle] SQL*Loaderで文字長セマンティクスがらみのエラーが発生 | Archive Redo Blog

Archive Redo Blog

DBエンジニアのあれこれ備忘録

Oracle には文字列の長さをバイト数で数える(バイトセマンティクス)か文字数で数えるか(文字長セマンティクス)を切り替える機能があります。

この区別をはっきりつけておかないと、文字列の長さに関わるエラーに悩まされるわけですが、それは SQL*Loader でもやはり同じです。


以下のような文字長セマンティクスの列を含んだテーブルに対し、

CREATE TABLE TEST
(
  A  NUMBER(3,0),
  B  VARCHAR2(10)
  C  VARCHAR2(10 CHAR)
  D  NVARCHAR2(10)
)

以下のような制御ファイルと

TEST.ctl
LOAD DATA
  CHARACTERSET JA16SJIS
  INFILE 'TEST.CSV'
  BADFILE 'TEST.BAD'
  DISCARDFILE 'TEST.DSC'
  REPLACE
INTO TABLE TEST
  FIELDS TERMINATED BY ","
(
  A,
  B CHAR(10),
  C CHAR(10),
  D CHAR(10)
)

以下のようなデータを用意して

TEST.csv
1,1234567890,1234567890,1234567890
2,文字長は10ですよ。,1234568790,1234568790
3,1234568790,文字長は10ですよ。,1234568790
4,1234568790,1234568790,文字長は10ですよ。

SQL*Loader でデータをロードしようとすると、

sqlldr USERID=SCOTT/TIGER@ORCL CONTROL=TEST.ctl DATA=TEST.csv LOG=TEST.log


レコード2: 拒否されました。- 表TEST,列Bでエラーが発生しました。
データ・ファイルのフィールドが最大長を超えています
レコード3: 拒否されました。- 表TEST,列Cでエラーが発生しました。
データ・ファイルのフィールドが最大長を超えています
レコード4: 拒否されました。- 表TEST,列Dでエラーが発生しました。
データ・ファイルのフィールドが最大長を超えています

というエラーが発生します。


レコード2 がエラーになるのは、最大 10 バイトの列 (B) にマルチバイト文字を含む 10 文字をセットしようとしているため理解できますが、レコード3、レコード4については最大 10 文字の列 (C、D) に 10 文字をセットしようとしているためエラーにならないように思えます。

にもかかわらずエラーになるのは、データファイルにもバイト長セマンティクスと文字長セマンティクスの区別があり、データファイルが UTF-16 以外のキャラクタ・セットの場合はバイト長セマンティクスがデフォルトとなっているためらしいです。

つまり、上記の制御ファイルのように JA16SJIS キャラクタ・セットのデータファイルを使用した場合、フィールド・リストで指定したバイト長を超えるデータが含まれていると弾かれてしまうということです。


データファイルにおいても文字長セマンティクスを使用するには制御ファイルの CHARACTERSET パラメータの下に LENGTH SEMANTICS CHAR というパラメータを書いてやる必要があります。

TEST.ctl
LOAD DATA
  CHARACTERSET JA16SJIS
  LENGTH SEMANTICS CHAR
  INFILE 'TEST.CSV'
  BADFILE 'TEST.BAD'
  DISCARDFILE 'TEST.DSC'
  REPLACE
INTO TABLE TEST
  FIELDS TERMINATED BY ","
(
  A,
  B CHAR(10),
  C CHAR(10),
  D CHAR(10)
)

このように制御ファイルを書き換えて実行すると、レコード2のみがエラーとなり、納得のいく結果が得られます。

レコード2: 拒否されました。- 表TEST,列Bでエラーが発生しました。
ORA-01401: 列に挿入した値が大きすぎます。


また、このときレコード2 に対するエラーメッセージが先ほどとは異なりますが、これはデータファイルと制御ファイルとの関係においてエラーとなったか、データファイルとテーブルとの関係においてエラーになったかの違いです。


なお、上記の制御ファイルではフィールド・リストにデータ型と長さを指定していますが、実際の現場で SQL*Loader を使う場合、データ型や長さについては暗黙の了解の下に使われることが少なくありません。


つまり、制御ファイルのフィールド・リストには単に列名を羅列するだけで、データ型や長さを指定しないことのほうが多いと思われます。

このようにフィールド・リストにデータ型と長さを指定しない場合は CHAR(255) とみなされます。
そのため、255バイトを超えるデータをロードしようとしない限りは上記の問題に気づくことはありません。

実際、私が上記の問題に気づいたのは 256 文字の列に256文字のデータをロードしようとしたためで、そのようなことをしない限りは平和に過ごせるのです^^;