[Oracle] VARCHAR2とNVARCHAR2を文字列結合して置換すると文字化けを起こす | Archive Redo Blog

Archive Redo Blog

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

データベース上のデータを加工してCSVファイルに出力するストアドプロシージャを作成・テストしていたら、REPLACE関数を使って文字列置換を行っている箇所で文字化けが発生しました。


どうもNVARCHAR2型のデータを置換すると文字化けを起こすようなのですが、文字化けするところとしないところがあります。


置換する前に'||'を使って文字列結合したりしているのも関係するかもしれません。

ということで、以下のような簡単なテストスクリプトを作成して調査してみました。


DECLARE
	wk_varchar VARCHAR2(1000) DEFAULT '"VARCHAR文字列"';
	wk_nvarchar NVARCHAR2(1000) DEFAULT '"NVARCHAR文字列"';
BEGIN

	DBMS_OUTPUT.PUT_LINE( '============================================================');
	DBMS_OUTPUT.PUT_LINE( '1.VARCHAR2+NVARCHAR2');
	DBMS_OUTPUT.PUT_LINE( '------------------------------------------------------------');
	DBMS_OUTPUT.PUT_LINE( '【文字列結合のみ】' );
	DBMS_OUTPUT.PUT_LINE( wk_varchar || wk_varchar );
	DBMS_OUTPUT.PUT_LINE( '【文字列結合+置換】' );
	DBMS_OUTPUT.PUT_LINE( REPLACE( wk_varchar || wk_varchar, '"', '""' ) );
	DBMS_OUTPUT.PUT_LINE( '============================================================');

	DBMS_OUTPUT.PUT_LINE( '============================================================');
	DBMS_OUTPUT.PUT_LINE( '2.NVARCHAR2+NVARCHAR2');
	DBMS_OUTPUT.PUT_LINE( '------------------------------------------------------------');
	DBMS_OUTPUT.PUT_LINE( '【文字列結合のみ】' );
	DBMS_OUTPUT.PUT_LINE( wk_nvarchar || wk_nvarchar );
	DBMS_OUTPUT.PUT_LINE( '【文字列結合+置換】' );
	DBMS_OUTPUT.PUT_LINE( REPLACE( wk_nvarchar || wk_nvarchar, '"', '""' ) );
	DBMS_OUTPUT.PUT_LINE( '============================================================');

	DBMS_OUTPUT.PUT_LINE( '============================================================');
	DBMS_OUTPUT.PUT_LINE( '3.NVARCHAR2+VARCHAR2');
	DBMS_OUTPUT.PUT_LINE( '------------------------------------------------------------');
	DBMS_OUTPUT.PUT_LINE( '【文字列結合のみ】' );
	DBMS_OUTPUT.PUT_LINE( wk_nvarchar || wk_varchar );
	DBMS_OUTPUT.PUT_LINE( '【文字列結合+置換】' );
	DBMS_OUTPUT.PUT_LINE( REPLACE( wk_nvarchar || wk_varchar, '"', '""' ) );
	DBMS_OUTPUT.PUT_LINE( '============================================================');

	DBMS_OUTPUT.PUT_LINE( '============================================================');
	DBMS_OUTPUT.PUT_LINE( '4.VARCHAR2+NVARCHAR2');
	DBMS_OUTPUT.PUT_LINE( '------------------------------------------------------------');
	DBMS_OUTPUT.PUT_LINE( '【文字列結合のみ】' );
	DBMS_OUTPUT.PUT_LINE( wk_varchar || wk_nvarchar );
	DBMS_OUTPUT.PUT_LINE( '【文字列結合+置換】' );
	DBMS_OUTPUT.PUT_LINE( REPLACE( wk_varchar || wk_nvarchar, '"', '""' ) );
	DBMS_OUTPUT.PUT_LINE( '============================================================');

END;
/

VARCHAR2型とNVARCHAR2型の文字列変数を用意し、

 1.VARCHAR2型 + VARCHAR2型
 2.NVARCHAR2型 + NVARCHAR2型
 3.NVARCHAR2型 + VARCHAR2型
 4.VARCHAR2型 + NVARCHAR2型

の4パターンの文字列結合を行った場合と、各パターンの文字列結合後に置換を行った場合で文字化けが発生するかどうかを調べるというものですが、実行してみると、以下のような結果となりました。

※テストしたデータベースのデータベース・キャラクタセットはJASJISTILDE、各国語・キャラクタセットはAL16UTF16

============================================================
1.VARCHAR2+NVARCHAR2
------------------------------------------------------------
【文字列結合のみ】
"VARCHAR文字列""VARCHAR文字列"
【文字列結合+置換】
""VARCHAR文字列""""VARCHAR文字列""
============================================================
============================================================
2.NVARCHAR2+NVARCHAR2
------------------------------------------------------------
【文字列結合のみ】
"NVARCHAR文字列""NVARCHAR文字列"
【文字列結合+置換】
""NVARCHAR文字列""""NVARCHAR文字列""
============================================================
============================================================
3.NVARCHAR2+VARCHAR2
------------------------------------------------------------
【文字列結合のみ】
"NVARCHAR文字列""VARCHAR文字列"
【文字列結合+置換】
""NVARCHAR文字列""""VARCHAR文字列""
============================================================
============================================================
4.VARCHAR2+NVARCHAR2
------------------------------------------------------------
【文字列結合のみ】
"VARCHAR文字列""NVARCHAR文字列"
【文字列結合+置換】

"
"
V
A
R
C
H
A
ReⅧWR
"
"
"
"
N
V
A
R
C
H
A
ReⅧWR
"
"
============================================================


VARCHAR2型+NVARCHAR2型を置換するパターンのみが文字化けを起こすようです。


REPLACE関数の仕様ではVARCHAR2型もNVARCHAR2型も受け付けるようなのですが...


この現象、Oracleは”仕様”と言うのでしょうか、”バグ”というのでしょうか?

まぁ、ともかくこういう現象が発生するということは、VARCHAR2型とNVARCHAR2型をくっつけて置換することは避けた方が良さそうです。


どうしてもそうしたいときは、以下のようにTO_CHAR関数を使って明示的にNVARCHAR2型の文字列をVARCHAR2型に変換してからくっつけて回避すればいいでしょう。

REPLACE( wk_varchar || TO_CHAR( wk_nvarchar ), '"', '""' )