2011年3月20日日曜日

Oracle文字化け

SQLを実行するさいに、文字化けをするので、色々調べてみました。

参考:
http://www.atmarkit.co.jp/fdb/rensai/ora_admin/05/oraadmin0501.html


文字化けが発生したとき、対処が困難になる場合がほとんどです。まず、Oracleの内部処理によるものなのか、別のソフトウェア製品の処理が介在したことによるものなのか、といった問題の切り分けが重要になります。そのため、Oracle内部の文字データと文字コードの処理を理解する必要があります。

日本では、歴史的な経緯から複数の文字コードが存在します。例えば、ShiftJIS・EUC・Unicodeといったものがあります。このため文字データをやりとりする場合、文字コードの変換が必要になってきます。ここでいう文字コードの変換とは次に紹介するビット列の変換に相当します。
       
        あらかじめ定められた変換表をに基づき変換
        ・ShiftJIS で「あ」に対応するビット列 = 0x82A0
        ・Unicodeで「あ」に対応するビット列 = 0xE38182


Oracleの文字コードの設定
Oracleでは、対象となるシステムに様々なOSが介在するため、システムごとに文字コードを指定・変換する必要があります。

Oracleでは、次のようなパラメータが存在します。
        ・データベースキャラクタセット
                データベースに文字データを保存するさいの文字コードを示す
                データベースに格納される文字データをある特定の文字コードで一元的に保管する仕組み
                データベースの作成時に指定する
        ・NLS_LANG
                クライアント環境に適した文字コードを指定する
                

■データベースキャラクタセット
データベースには、作成時に1つのデータベースキャラクタセットを指定します。

次のSQLを実行し確認することができます。
SQL> SELECT * FROM V$NLS_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET';

■NLS_LANG
NLS_LANGは環境変数として設定することができます。設定する値自体は、クライアント環境がサポートしているキャラクタセットを指定する必要があります。たとえば、Window環境では、一般的に日本語EUC文字コードには対応していないので、JA16EUCを指定すると文字化けが発生する場合があります。


Oracleは自動的に文字コード変換を行う
NLS_LANGとデータベースキャラクタセットが異なっていても、Oracleは自動的に文字コード変換を行います。

■クライアントからOracle Databaseに対して文字データを送信する
以下の手順が行われます。
  1. Oracleクライアントから入力された文字データをいったんUnicodeに変換する
  2. Unicodeからデータベースキャラクタセットに対応した文字コードに変換する
  3. Oracle Databaseに文字データを送信する
ただし、データベースキャラクタセットとNLS_LANGのキャラクタセットが同じ場合、Oracleは例外的に文字コードの変換を行いません。


Oracleの文字化けの原因と対処
■クライアント側で入力された文字が、データベース側のキャラクタセットで対応していない
クライアントのNLS_LANGとOracleのデータベースキャラクタセットが異なる場合に起きます。

NLS_LANGでは対応できる文字でも、データベースキャラクタセットでは対応できない一部の文字においては、文字コード変換が正常に実行されません。例えば、JA16EUCのデータベースキャラクタセットにShiftJisの「①」を格納する場合に起きます。

文字コードの変換が正常にできないとき、Oracleにより強制的に「?」文字に変換されます。このような状態になった場合、データベースでは元の文字の情報は失われています。つまり、復元はできません。

解決方法としては以下に示す通りです。
・システムの対応範囲外とする
・すべてのキャラクタセットを限定する
・すべてのキャラクタセットを統一する
・Unicodeとしてデータを格納する


■データ表示において文字化けする
OracleはNLS_LANGに指定したキャラクタセットに対応した文字コードをアプリケーションが適切に処理出来ると仮定しています。つまり、OSやアプリケーションが適切に処理できているかは考慮せず、決められた文字コードを出力しています。

このため、OS/アプリケーションが実際に処理できない文字コードをNLS_LANGのキャラクタセットに指定すると、文字化けが発生する原因になります。

解決策としては以下の方法があります。
・NLS_LANGのキャラクタセットをOS/アプリケーションが対応している文字コードに設定する
・OS/アプリケーションに文字コード設定が存在する場合は、それらをNLS_LANGのキャラクタセットに統一する


実際に、設定してみよう
僕の環境は、
OSはLinuxで、クライアントのアプリケーション
・ターミナル(文字コード:UTF8)
Oracle データベース
・Oracle11gR1 (データベースキャラクタセット:JA16EUC)

データベースキャラクタセットは以下のSQLで確認することができます。
SQL> select * from nls_database_parameters where parameter='NLS_CHARACTERSET';


何も設定しなければ、ものすごく文字化けするので、環境変数でNLS_LANGを設定しよう。
$ vi ~/.bash_profile

export NLS_LANG=Japanese_Japan.AL32UTF8
を追加する

$ source ~/.bash_profile

以上の設定で、文字化けの問題は解決しました。

0 件のコメント:

コメントを投稿