Db2のOracle互換機能を使ってみた😃<2>　～可変長列の末尾ブランクの扱い～ 

###はじめに
IBMのDb2にはDb2でありながらOracleの仕様に合わせた使い方ができるOracle互換機能があります。
OracleからDb2に移行する場合、この機能を利用すると便利なことも多いですが、全くOracleと同じように使えるかというと、そうではない部分もあります。
そこで、Db2とOracleの違いに関してや、Oracle互換機能を使ってみて気づいたことなどを、つれづれに投稿していこうかなと思います。

###■Db2のOracle互換機能のデータ・ベースの作成
Oracle互換機能には様々な個別の機能がありますが、データ・ベースを作成する前に設定しておかないといけないものと、あとから設定できるものがあります。
個々の機能や、Oracle互換機能を備えたデータ・ベースの作成方法は、こちらの投稿に記載していますので参考にしてください。
[・Db2のOracle互換機能を使ってみた😃<1>　～データベースの作成～][1]

###■Db2とOracle データ・タイプに関する主な違い
OracleとDb2間でのデータベースの移行やデータ移動、またレプリケーションやフェデレーションによってデータ連携をしようとした際に、データに関して必ずと言って良いほど直面する代表的な仕様の違いと言えば、 
・可変長列の末尾ブランク、および空文字（長さ0の文字）の扱い
・数値型（NUMBER,INTEGER,DECIMALなど）
・日付、タイムスタンプ型（DATE,TIMESTAMPなど）
でしょうか。
 
Db2のOracle互換機能を使用する場合、上記の中にはその扱いについてデータベースの作成後は変更ができないものもあるので、データベースの設計時にそれぞれどうするのかを決定しておかなければなりません。
 
そこでまず最初に、この中の「可変長列の末尾ブランクの扱いの違い」について当投稿でご紹介します。

###■可変長列の末尾ブランクの扱いの違い
OracleとDb2の可変長列の末尾ブランクの扱いの違いは一言でいうと、**「文字比較において、Db2は末尾ブランクを無視するが、Oracleは無視しない」**ということになります。　
まず、具体例を見てみましょう。
【図1】はOracleとOracle互換機能を使っていないDb2（ここではNative Db2と称することにします）で、C1列に「あ」１文字だけのデータと「あ」＋半角ブランクを1文字入れたデータを入れたVCHAという表を作成し、その検索結果の違いを検証したものです。
データの内容が分かりやすいように、16進であわらした場合の結果を3列目として検索しています。
どちらもデータベースの文字コードはUnicode（UTF-8）なので、E38182が「あ」、20が半角ブランクのコードになります。
![Ora-DB2比較2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528658/d79ba91c-1ac2-f035-25d2-159fbc24ad91.png)
【図1】のOracleの方は「あ」の後続の半角ブランクの有無、またその個数まで厳密に合致していないと文字比較で同値とみなされませんが、Db2の場合は後続の半角ブランクの個数が0でも1以上でもみな同値となります。
このDb2の振る舞いは、SQL標準に沿った仕様だと聞いています。
 
このDb2の仕様は飽くまでも**文字比較において末尾ブランクの有無を無視する**ということで、Db2では末尾ブランクをつけたデータを可変長列には格納できないとか、LENGTH関数の結果で末尾ブランクの分がカウントされない、ということではありません。
またこの違いは可変長列に限った話で、固定長の場合にはOracleとDb2でこのような違いはありません。
 
この可変長列での仕様の違いですが、どちらが適切かはアプリケーション要件に依存するため何とも言えませんが、友人からこんな話を聞いたことがあります。
あるサイトでユーザー名の登録をして、その後そのユーザー名でログインしようとしたら、“そんなユーザーはいない”とログオンできなかったということです。
確かに自分の名前を登録したのになぜ？と記憶をたどると、最初はローマ字で名前と苗字をブランク1つあけて入力したけれど、その後名前だけでいいかと思い苗字部分を後ろからBackspaceで消して登録したとのことです。
ただそこで名前と苗字の間のブランクまで消したかどうか定かではなく、試しに名前の後ろにブランクをつけたら、めでたくログインできたということでした。
このサイトのデータベースがOracleであったかは分かりませんが、文字列の最後のブランクの有無は画面上判別しにくいため、ユーザーにとってはあってもなくてもいいという方がありがたいケースは多いかもしれません。
 
このようにOracleとDb2では可変長列の末尾ブランクの扱いが異なりますが、Db2を使うけれど、末尾ブランクの扱いについてはOracleと同じにしたいという場合は、Db2のOracle互換機能の中の、**“VARCHAR2 データ・タイプ互換フィーチャー”をON（DB2_COMPATIBILITY_VECTOR=20）にする**ことにより、同じ結果を得ることができるようになります。

###■“VARCHAR2互換フィーチャー”をONにしてみた
 
【図2】は、“VARCHAR2 データ・タイプ互換フィーチャー”をONにしたOracle互換のDb2で【図1】と同じ検証を行った結果です。
【図1】のOracleの結果と同じになっていますよね。
![Ora互換Db2_3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528658/42ed9e21-58db-b0b6-d29d-dd8b03425ed6.png)
データベースをOracleからDb2に移行する場合は、まずこの末尾ブランクの扱いの違いの影響を調査してください。
その結果、末尾ブランクの数は厳密にあっていなくても同値として良いというのであれば、Db2の仕様をそのまま採用するのがよいでしょう。
逆に今までのOracleと同じ振舞いをして欲しいという場合は、“VARCHAR2 データ・タイプ互換フィーチャー”の利用も検討してみてください。
 
なお、この末尾ブランクの件は、Db2とOracleをレプリケーションやフェデレーションによってデータ連携をしようとした場合にも注意が必要ですので、ご注意ください。　

###■最後に豆知識を１つ
今回この末尾ブランクのテストをしていた時に、Oracle互換のDB2なのに末尾ブランクの数を無視するDb2のような結果が出てあれ？と思った経験をしました。
それは【図2】の確認テストをWindowsのDB2コマンド・ウィンドウで行った時のことです。
UnixやLinuxでは、SQLステートメントでよく使うアスタリスクやシングルコーテーションの記号がある場合は、SQL文をダブルコーテーションで囲まないと正しく認識されません。
しかしWindowsの場合はその記号がコマンドプロンプト上で別の意味を持たなければ、ダブルコーテーションなしでも問題なく実行できるので、Windowsの場合はあえてダブルコーテーションをつけることはしていませんでした。
ところが【図2】の最後のケースで「あ」の後に半角ブランク8文字指定したにも関わらず、半角ブランクが1文字追加されているK1=1の行が検索できてしまったのです。（【図3】の最初のSELECTの例）
これは、WindowsのDB2コマンド・ウィンドウでは、ダブルコーテーションで囲まれていないSQL文中の**連続した半角ブランクは１つの半角ブランクにまとめられてデータベースに送信される**という事が理由だったようです。
よって半角ブランクの数が重要な検証を行う場合は、Windows環境でもSQL文をダブルコーテーションで囲むか、SQL文をファイルに記載して実行する、あるいはDb2コマンド行プロセッサを使うことをお勧めします。
 
**【図3】Windows環境からの連続ブランクの入ったSQL文の実行**
DB2コマンド・ウィンドウでのダブルコーテーション有無による結果の違い（Oracle互換Db2での検索）
![Db2CLP3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528658/884713c7-48ba-6f4d-f045-eb745f84a80d.png)


###関連投稿
[・Db2のOracle互換機能を使ってみた😃<1>　～データベースの作成～][1]
[1]:https://qiita.com/Seven_Marine/items/1a9009a29e78fc80a2f0
[・Db2のOracle互換機能を使ってみた😃<3>　～空文字(長さ0の文字)の扱い(1)～][3]
[3]:https://qiita.com/Seven_Marine/items/470d58226fe89f017b2a
[・Db2のOracle互換機能を使ってみた😃<4>　～空文字(長さ0の文字)の扱い(2)～][4]
[4]:https://qiita.com/Seven_Marine/items/612e1ca67054337f9758
[・Db2のOracle互換機能を使ってみた😃<5>　～空文字(長さ0の文字)の扱い(3)～][5]
[5]:https://qiita.com/Seven_Marine/items/28c73c824619baf48354
[・Db2のOracle互換機能を使ってみた😃<6>　～空文字(長さ0の文字)の扱い(4)～][6] 
[6]:https://qiita.com/Seven_Marine/items/5cc1afad26ea4eea4644
[・Db2のOracle互換機能を使ってみた😃<7>　～NUMBERタイプの互換性(1)～][7] 
[7]:https://qiita.com/Seven_Marine/items/74bf4af0e65de2222e33
[・Db2のOracle互換機能を使ってみた😃<8>　～NUMBERタイプの互換性(2)～][8]
[8]:https://qiita.com/Seven_Marine/items/a9b2c0e8a03695ef82c1
[・Db2のOracle互換機能を使ってみた😃<9>　～NUMBERタイプの互換性(3)～][9]
[9]:https://qiita.com/Seven_Marine/items/6a47ea5ea6418c6db6e2
[・Db2のOracle互換機能を使ってみた😃<10>　～NUMBERタイプの互換性(4)～][10] 
[10]:https://qiita.com/Seven_Marine/items/b260192afc9ec5c60899


-----
お断り：
当投稿は、Database migration to DB2-IBM Japan Community Wikiに掲載のブログを、Qiita用に書き直したものです。

本資料掲載事項は、ある特定の環境・使用状況においての正確性は確認されていますが、すべての環境において同様の結果が得られる保証はありません。
これらの技術を自身の環境に適用する際には、自己の責任において十分な検証と確認を実施いただくことをお奨めいたします。