Db2とOracle 空文字の扱いの違いによる影響例
この投稿は、
・Db2のOracle互換機能を使ってみた😃<4> ~空文字(長さ0の文字)の扱い(2)~
の続きになります。
当回はDb2からOracle互換Db2(またはOracle) への移行の場合についての注意点について、ある事例をベースにご紹介します。
NULL可能列でも要注意
Oracleでは空文字はNULLに扱いになるため、Db2からOracleに移行する場合にまず問題になるのは更新対象列がNOT NULLの場合です。
Db2ではNOT NULLの列でも空文字で更新や挿入ができますが、Oracleではエラーになってしまうということですので、これは容易に想像がつくと思います。
ではNULL可能な列は気にしなくてよいのでしょうか。
実はNULL可能な列であるからこその問題が発生することもあります。
今回はそれについてご紹介します。
■ Db2からOracle互換Db2(またはOracle)への移行での事例
Db2 V9.5からV10.5への単純移行を行ったお客様で発生した事象
Db2のバージョンアップですので、こちらのお客様ではアプリケーションはそのまま変更せず使用したのですが、V9.5では動いてたプログラムがV10.5では期待通り動かない(期待しているデータが引っ掛からない)という事象が発生してしまいました。
問題のアプリケーションでは、表に新規の行をINSERTする際にNULL可能なVARCHAR列の初期値として空文字を入れ、別の処理で 対象列= '' というように空文字を条件にして初期値が入っているレコードを選択し処理を行うようになっていました。 しかしこの空文字を条件にした検索で、存在するはずの初期レコードが1件も検索されず、処理を継続することができなくなってしまったというのです。
そこで初期レコードの実際のデータを確認してみた所、一見分かり難いのですが新規行の初期値がNULLになっていました。
事象の理由
当初、なぜNULLが入ってしまったのかすぐには分からなかったのですが、データベースの構成パラメータを確認したところ、なぜか “VARCHAR2データ・タイプの互換性”の項目がONになっていることが判明しました。
V10.5のデータベースは新規に作成し、データはV9.5のデータベースから移行する方法を取ったのですが、この時にDB2_COMPATIBILITY_VECTOR=ORAを設定した状態でV10.5のデータベースを作成してしまい、意図せずOracle互換のDb2になってしまっていたようです。
そのため初期値としてINSERTした空文字がNULLとして挿入され、対象列= '' という条件に合致しなくなってしまったというのが今回の事象の原因でした。
これは、別の投稿
・Db2のOracle互換機能を使ってみた😃<3> ~空文字(長さ0の文字)の扱い(1)~
でご紹介した**「検索条件では空文字はNULLの代用にはならない!」というOracleの仕様に起因する事象と言えます。
つまりOracleでは空文字で挿入/更新した列を検索条件にしたい場合は 対象列=' ' ではなくIS NULLで指定する必要がある**のです。
Oracle互換機能の中には、変更できないものがある
Db2のOracle互換機能の中でも、以下の3つに関連する仕様はデータベース作成時に決定され、その後変更はできません。
・可変長列の末尾ブランク、および空文字(長さ0の文字)の扱い
・数値型(NUMBER,DECIMAL)
・日付型(DATE)
そのため、これらの仕様を変更するには、データベースを再作成するしかなく、この事例のお客様も問題解決のためにはデータベースの再作成を余儀なくされました。
変更不可のOracle互換機能の確認
上記の3つの仕様がOracle互換になっているか否かは、データベース構成パラメータで確認できますので、データベース作成後は必ず確認するようにしてください。
【図1】の色を変えた3項目の設定がON(個別に設定は可能)になっている場合は、該当するそれぞれの機能がOracle互換になっていることを示します。
Native Db2仕様の場合はすべてOFFになっています。
【図1】Oracle互換仕様の確認(データベース構成パラメータ)
事象から学べること
今回ご紹介した例は意図せずOracle互換にしてしまったというものですが、事象としてはDb2からOracleやOracle互換のDb2に移行する際には同様に該当しますし、対象の列がVARCHAR列でもCHAR列でも発生します。
そのためDb2から移行する場合は、挿入/更新データとしてだけでなく、検索条件としても空文字を指定している処理はないか、移行計画の初期の段階で調査をすることが重要になります。
空文字挿入/更新を探す方法案
膨大なアプリケーション・コードの中で空文字を指定しているものを探し出すという事は容易ではありませんが、こればかりは空文字('')をキーワードにソース・コードをスキャンするしかないかもしれません。
ただ、すべてのアプリケーションを調査するのは困難なので、せめて空文字挿入/更新の対象の表が判ればという事であれば、トリガーの利用も可能ではあります。
トリガーでは検索条件での空文字使用は検知できませんが、空文字挿入/更新の有無を移行前のDb2に対してチェックすることはできます。
この具体的な方法については、以下の投稿を参考にしてください。
・Db2のOracle互換機能を使ってみた😃<6>
TRIM関数結果の空文字
実はもう1点、明示的に空文字を指定していなくても、空文字と同等になるケースがあるのですが、皆様はお気づきでしょうか。
それはTRIM関数(RTRIM/LTRIMも含む)の結果としての空文字です。
例えばブランクしか入っていないCHAR列やVARCHAR列に対してTRIM関数をかけると、その結果は長さが0のデータ、つまり空文字と同じになります。よって、そのTRIM関数の結果で別の列を更新するとか、検索条件にするというような処理があると、空文字挿入/更新や検索と同じ問題が発生し得ますので、TRIM関数の使用の有無も調査が必要です。
関連投稿
・Db2のOracle互換機能を使ってみた😃<1> ~データベースの作成~
・Db2のOracle互換機能を使ってみた😃<2> ~可変長列の末尾ブランクの違い~
・Db2のOracle互換機能を使ってみた😃<3> ~空文字(長さ0の文字)の扱い(1)~
・Db2のOracle互換機能を使ってみた😃<4> ~空文字(長さ0の文字)の扱い(2)~
・Db2のOracle互換機能を使ってみた😃<6> ~空文字(長さ0の文字)の扱い(4)~
・Db2のOracle互換機能を使ってみた😃<7> ~NUMBERタイプの互換性(1)~
・Db2のOracle互換機能を使ってみた😃<8> ~NUMBERタイプの互換性(2)~
・Db2のOracle互換機能を使ってみた😃<9> ~NUMBERタイプの互換性(3)~
・Db2のOracle互換機能を使ってみた😃<10> ~NUMBERタイプの互換性(4)~
-----
お断り:
当投稿は、Database migration to DB2-IBM Japan Community Wikiに掲載のブログを、Qiita用に書き直したものです。
本資料掲載事項は、ある特定の環境・使用状況においての正確性は確認されていますが、すべての環境において同様の結果が得られる保証はありません。
これらの技術を自身の環境に適用する際には、自己の責任において十分な検証と確認を実施いただくことをお奨めいたします。