DB2 for i の SQL の文字列関数で DBCS 文字は正しく扱えない!? (V5R4)

SQL の文字列関数に RIGHT とか LEFT とかいった関数がありますが、今回はそれが「日本語」にたいしてどう使えばいいかの紹介をしたいと思います。
また、あわせて SUBSTR 関数でも同じ使い方ができることも紹介しようと思っています。


引数に 1 を指定すると

まず、「あいうえお」という 5文字の「日本語」にたいして RIGHT 関数を使ってみてみましょう。

↓のように RIGHT の引数に 1 を指定してみるとどうなるかを見てみます。

SELECT str,                          
       RIGHT(str, 1)                 
 FROM (SELECT 'あいうえお' AS str  
         FROM sysibm/sysdummy1) AS T

結果は↓のようになります。2つめカラムが、RIGHT 関数での出力結果なのですが、何も見えませんね。つまり、「文字」は出てきません。

何が起きているんでしょうか?

16進数でどうなっているか、HEX 関数を使って中身を見てみましょう。

SELECT str,                          
       RIGHT(str, 1),                
       HEX(RIGHT(str, 1))            
 FROM (SELECT 'あいうえお' AS str  
         FROM sysibm/sysdummy1) AS T

↑が出力結果です。HEX で出力させると、何も出てきていないわけではないことがわかります。

取り出されているのは '0F' です。「シフト・イン」文字ですね。

EBCDIC で DBCS をあつかうために、いわばモードを変えるための文字になります。表現するのにダブルバイトが必要な文字の場合は、その最初と最後は 0E と 0F でかこんで識別するようにします。その 0E/0F を「シフト・アウト」「シフト・イン」文字といいます。

「日本語」を正しくあつかうにはいったん UTF-8 に変換して

いろいろやってみるとわかると思いますが、引数を加減してみても、正しく文字は表示されません。
切り出した文字の前に自動的に「シフト・アウト」文字が入るわけではないんですね。

… DB2 for i ではこうした「日本語」は正しくあつかえないのでしょうか?!

確かにこれは EBCDIC 特有の問題ですが、要するに文字コードの問題です。
クライアントとサーバーで文字コードが違うことで起きる可能性のある問題なので、PC や UNIX だったら起こらない、というわけではありませんよね。ある意味、普遍的な問題です。

IBM i の場合、CCSID の仕組みがきちんと働いているので、たとえばオン・デマンド的にユニコードとしてあつかうということが可能です。

SELECT str,                                                      
       RIGHT(str, 3)                                            
FROM (SELECT CAST('あいうえお' AS CHAR(15) CCSID 1208) AS str 
         FROM sysibm/sysdummy1) AS T                             

SQL では CAST という関数をもちいてデータ型を変換することが可能です。CCSID を指定して CHARACTER タイプに CAST すると、動的に、そのコードに一時的に変換して扱うことが可能なんですね。

では、CCSID を UTF-8 (1208) に指定して、RIGHT 関数を実行してみましょう。

↓が、その実行結果です。文字が表示されているのがわかりますね。

DB2/400 と Unicode」でもふれましたが、UTF-8 は(少なくとも V5R4 では) 3桁でカウントするようです。

HEX で見てみると、UTF-8 になっていることが確認できます。

SELECT str,                                                      
       RIGHT(str, 3),                                            
       HEX(RIGHT(str, 3))                                        
 FROM (SELECT CAST('あいうえお' AS CHAR(15) CCSID 1208) AS str 
         FROM sysibm/sysdummy1) AS T                             

比較ももちろんできるようになっています。

切り出した文字が、WHERE 句で指定したリテラルと同じかどうかを判定する SQL を実行させてみましょう。

きちんと、自動的なデータ変換が行われて、意図した結果が返っていることがわかりますね。

SUBSTR 関数でも同様

SUBSTR 関数でも同じ手が使えます。

↓の例は、今までの例をそのままコピーしたので最初に「シフト・アウト」文字、最後に「シフト・イン」文字分の空白が入ってしまっています。
つまり、1バイト分余計なブランクが入ってしまっているので、文字の開始位置は 2 になっています。逆に言えば、それも含めてきちんとカウントしてくれる、ということがわかります。

1文字はやっぱり 3桁( = 3バイト)になります。

文字を途中から切り出したい場合は、(↓の例では 1バイトを最初に足した上で) 3バイトきざみで指定します。


まとめ

V5R4 では RIGHT/LEFT や SUBSTR などの関数で日本語(DBCS/MBCS)をあつかう場合は、いったん UTF-8 に CAST したうえであつかうことが有効である、ということですね。

”文字化け”というのは、オープン系のデータベースでも実はけっこう頭の痛い問題なのですが、IBM i の場合はこうした仕組みには一日の長があります。
DB2/400 と Unicode」でもふれましたが、カラム単位で文字コードの指定もできますし、UTF-8 だって UTF-16 だって使えます。
今回の記事のように動的に変更して比較などに使用することもできます。

たまに「IBM i は文字コードの処理が」と「EBCDIC なのでいろんな不都合が」などという人がいますが、逆にいちばん柔軟に対応できるようになっているんですよ。
オープン系の方が実はけっこう複雑だったりすることを知らない人が知ったかぶりをしてそんなことを言ったりするので、ぜひお気をつけくださいませ。

[Top Pageに戻る]

Ads by TOK2