##末尾ブランクの違いだけじゃない
Db2ではOracle互換機能を備えたデータベース(Oracle互換Db2)を作成することができ、この可変長列の末尾ブランクの扱いをOracle仕様にするには、Db2のOracle互換機能の中の、“VARCHAR2 データ・タイプ互換フィーチャー”をON(DB2_COMPATIBILITY_VECTOR=20またはORA)にします。
これについては、別投稿でご紹介しました。(関連投稿を参照してください。)
実は、この”VARCHAR2 データ・タイプ互換フィーチャー”をONにすることにより、もう1つ、可変長列だけでなく固定長列にも関連するある仕様がOracle仕様になります。
それは空文字の扱いです。
ということで、当投稿ではその空文字の扱いついてご紹介します。
###■Oracleでは空文字はNULLになる!
空文字とは連続したシングルコーテーション(‘’)で表される「文字が存在しないリテラル」のことです。
Db2では空文字は“長さが0の文字”として扱いますが、Oracleでは“空白値(NULL)と同値”とみなすという大きな違いがあります。
####具体例を見てみる
OracleとOracle互換機能を使っていないDb2(ここではNative Db2と称することにします)で、固定長か可変長か、さらにNULL値が可能か不可かの4つのパターンの定義のCHAR列をTAB1表に定義し、空文字(‘’)で更新してみます。
TAB1には最初にすべての列に‘A’(バイナリー値はx’41’)をINSERTしておき、C_COLから順に1列ごと空文字(‘’)でUPDATEします。
【図1】(Native Db2の場合)と【図2】(Oracleの場合)が、それぞれの結果です。
各UPDATEの後に更新結果をSELECTしていますが、NULLなのかブランクなのかがわかり易いように、Native Db2もOracleもSELECTリストの最初の項目はNVL関数をかけ、列値がNULL以外であれば列値自体を、NULLであれば null という文字を表示するようにしています。また2番目のSELECTリストの項目はデータの内容を判別し易いようにHEX関数またはRAWTOHEX関数をかけ、バイナリーコードを表示させています。
【図1】 Native Db2 空文字更新の結果
【図1】のDb2の結果では、NULL可能かどうかに関わらず空文字で更新ができています。
固定長のC_COLとCNN_COLはCHARタイプの充填文字である半角ブランクで埋められ、可変長列のVC_COLとVCNN_COLはデータがなにもない**“長さが0の文字”**という状態となり、いずれもNULLとは異なる結果となっていることが確認できます。
では、同じことをOracleで行ったらどうなるでしょうか。
【図2】 Oracle空文字更新の結果
【図2】の結果より、Oracleでは対象列が固定長であるか可変長であるかに関係なく、空文字はNULLとして扱われるため、NULL可能であれば対象列はNULLに更新され、NOT NULLの列の場合はORA-01407のエラーで更新できないということが分かります。
###■検索条件では空文字はNULLの代用にはならない!
では次に、この空文字で更新した列の値を条件にして検索したい場合はどうするのか、という例を見てみましょう。
####TAB1のC_COLとVC_COLに対して空文字を指定して検索してみる
Db2では空文字で更新した列に対し、空文字を条件にして検索を行った場合、充填ブランクの有無にかかわらず固定長でも可変長でもどちらも検索条件に合致して検索できるということがわかります。
【図3】 Native Db2 空文字検索の結果
ではOracleではどうなるでしょうか。
【図4】 Oracle空文字検索の結果
この結果からわかるように、Oracleでは条件で指定する場合は空文字はNULLの代用にはならないということです。
つまり、空文字更新でNULLになった列であってもその列を条件に検索する場合は、空文字ではなく「対象列 IS NULL」と、NULLであることを明示的に指定する必要があります。
以上、空文字を使った時のNative Db2とOracleの扱いの違いを実際の例を見ながらご紹介しました。
ここではOracleを例に検証しましたが、最初に触れたように、“VARCHAR2 データ・タイプ互換フィーチャー”がONになっている Oracle互換のDb2の場合は、Oracleの仕様と全く同様の結果になります。
では、この空文字の扱いの違いによってどんな影響が出る可能性があるのか、これについては別の投稿でご紹介したいと思います。
##関連投稿
[・Db2のOracle互換機能を使ってみた😃<1> ~データベースの作成~][1]
[1]:https://qiita.com/Seven_Marine/items/1a9009a29e78fc80a2f0
[・Db2のOracle互換機能を使ってみた😃<2> ~可変長列の末尾ブランクの違い~][2]
[2]:https://qiita.com/Seven_Marine/items/f7a31fc71a728282e043
[・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用に書き直したものです。
本資料掲載事項は、ある特定の環境・使用状況においての正確性は確認されていますが、すべての環境において同様の結果が得られる保証はありません。
これらの技術を自身の環境に適用する際には、自己の責任において十分な検証と確認を実施いただくことをお奨めいたします。