昨年末、仕事というか、会社の方針に対してフラストレーションを溜め込んでいる時期があった。どういう経緯で何がどう不服だったのかというのは、書いてもただ長くなって、そもそもつまらん話なので割愛する。まぁ、自分の意見は社長に対して直訴する機会があったのでもういいのだ。それで状況が変わったかというのはまた別の話だが、会社には会社の都合があるし、俺も俺で所詮は社畜なので、要求に応えるしか生きる術がない。
そんなこんなで色々あって、今は再びOracleのSQLシルバー資格を取得するために勉強を始めている。現時点では別にSAPの業務を離れたわけではないが、今後どう転んでもいいような対応を求められている。
まぁOracle資格とは言え、SQLについての試験なんで、SAPとか他のRDBMSで使うそれとさほど大差はないし、学習書を半分ほど読んだ感じでは、シルバーという割にぬるい印象はある。しかし、長いこと保守しかしてなくて開発から遠ざかっていたので、あまり見る機会の少ない関数とかをすっかり忘れている。とりわけ、引数の順序とか。
たとえば
NVL2(in, out1, out2)
NVL2は、引数inの値がNULLか否かに応じて戻り値をout1かout2に変える関数。というのは覚えている。入社時のOracle研修でしか使ったことないけど。問題は、どっちがNULLの時の戻り値だっけ…?ということ。
正解は、out2でした。
それから、今まで意識してなかったが、NVL2に関して気をつけなきゃいけないのは、out1とout2のデータ型は一緒でないといけないということ。厳密に言うと、out1とout2のデータ型が異なった場合、out2の方のデータ型がout1のデータ型に自動で暗黙的変換される。自動変換してくれるならいいじゃん、という話ではない。
たとえば、変数mojiが文字(CHAR型)、変数sujiが数値(NUMBER型)としたときに、
NVL2(in, moji, suji)
これはinの値がNULL以外ならmojiの値、NULLならsujiの値を返すファンクションとして、一応機能する(はず)。基本的に数値はそのまま文字型に変換できるので、暗黙変換でエラーにならないから。in IS NULLのとき、変数sujiの値が1234なら、文字列’1234’がこの関数の戻り値になる。
一方で、
NVL2(in, suji, moji)
こっちの関数はエラーになる可能性が高い。変数mojiの値が’こま’だと、in IS NULLの時に暗黙変換でエラーになる。mojiの値がたまたま’1234’とかなら機能するだろうけど、当然、暗黙変換に成否が依存してる時点でよろしいわけがない。
なので、この関数を実現したいなら
NVL2(in, TO_CHAR(suji), moji)
と、データ型変換を噛まして型を揃えるのが正しい。
もっといえば、1つ目の関数も
NVL2(in, moji, TO_CHAR(suji))
と明示的変換にしておいた方が健全だとは思う。
同じNULLを扱う系の関数でも、NULLIFとか、COALESCEとかは引数の暗黙変換はなくて、引数が同じ型でないとエラーになる。こんな感じでそれぞれ挙動が違ったりすると、やっぱり暗黙変換の利用は可能な限り避けて明示的にしておくのが、見返す人にとっては親切だよね。
そんな感じで、久々に基礎に立ち返り中。