[Oracle] NVARCHAR2の列とリテラル値の比較でORA-01401エラーが発生する。 | Archive Redo Blog

Archive Redo Blog

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

WHERE 句で NVARCHAR2(または NCHAR)で定義された列と''で囲んだ 1000 文字を超えるリテラル値を比較した SQL を実行すると、

SELECT COUNT(*) FROM TEST
WHERE NVARCHAR2_COLUMN = 
'12345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901';

以下のエラーが発生します。

ORA-01401: 列に挿入した値が大きすぎます。


INSERT 文で代入する際にも同じエラーが発生します。

INSERT INTO TEST (NVARCHAR2_COLUMN) VALUES (
'12345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901'
);

ところが、列が VARCHAR2、CHAR の場合はエラーは発生しません。
(データベース・キャラクタ・セットは JA16SJIS、各国語キャラクタ・セットは AL16UTF16 です。)

リテラル値が 1000 文字以下でもエラーは発生しません。

リテラル値を以下のように明示的に変換した場合もエラーは発生しません。

SELECT COUNT(*) FROM TEST
WHERE NVARCHAR2_COLUMN = 
N'12345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901';

SELECT COUNT(*) FROM TEST
WHERE NVARCHAR2_COLUMN = 
TO_NCHAR(
'12345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012345678901234567890123456789012345678901');


これは一体どういうことなのでしょう?

''で囲まれたリテラル値というのは CHAR に相当します。

つまり、上記の例では CHAR と NVARCHAR2 を比較しているということになります。

このように異なるデータ型の値を比較する場合、どちらかの値に対して暗黙的に型変換が行われますが、どちらがどちらに変換されるか(変換の方向)は比較する型の組み合わせごとにあらかじめ決められています。

上記の例の場合は、リテラル値(CHAR)が NVARCHAR2 に暗黙的に変換されるわけですが、この暗黙的な型変換時に上記のエラーが発生しているのではないかと推測されます。

1001 文字以上でエラーとなることから、おそらく CHAR(または NCHAR) の最大サイズ 2000 バイトが影響しているのではないでしょうか。

1001 文字は JA16SJIS では 1001 バイト、AL16UTF16 では 2002 バイトになります。

つまり、CHAR(あるいは NCHAR)の器の中で型変換を行おうとして、結果 2000 バイトを超えてしまうために「列に挿入した値が大きすぎます。」と言われてしまうのかと...

リテラル値を使用する場合、比較・代入対象が NCHAR、NVARCHAR2 であっても暗黙の型変換に甘えてついつい''で囲んで記述してしまいがちですが、上記のエラーに引っかかる可能性がある場合は、リテラルの頭に"N" を付けて各国語キャラクタ・セットであることを明示的に宣言するか、TO_NCHAR 関数を使用して明示的に型変換を行うよう注意しなければなりません。