●NULL値 NULLはゼロでも空白でもない特殊な値 |
NULL値は,特殊な値である。この値は,「データが存在しない」という意味を持つ。すべてのデータ型に対して利用できるが,特殊な値であるため,その扱いには注意が必要である。
NULL値の特性を説明する前に,NULL値の表示方法を説明しておこう。NULL値は「データが存在しない」という意味なので,人が目で見て確認することが難しい。そこでOracleの対話型ツール「SQL*Plus」では,NULL値を任意の文字で表示させる機能を提供している。SQL*PlusにおいてNULL値を「?」で表示させるには
SET NULL ?
というコマンドを打ち込む。本記事では,NULL値を「?」と表記する。
NULLは「= NULL」で判定できない
NULL値は,数値型や文字型などのあらゆるカラムに格納できる値である。カラム内に存在する値であるため,カラム値の集計計算や文字列の比較などにおいてNULL値が対象になることがある。NULL値を含む計算やNULL値の比較判定は,特殊な挙動を示す。
SELECT*文におけるNULL値の特性をまとめると,5つのポイントがある。1つ目のポイントは,NULL値は「ゼロ」や「空白文字」とは別物であることだ(図4(1)[拡大表示])。NULLは「データが存在しない」という意味であるため,「ゼロ」という数値や,「空白」という文字とは別物である。図4(1)のようにNULLとゼロ,NULLと空白文字を比較しても,その判定は“等しくない”となる。
2つ目のポイントは,NULL値かどうかを判定するために,「= NULL」としても判定されないことである(同(2))。「=」は値を比較するものであり,NULLはデータが存在しないという意味であるため,比較対象がNULLの場合この判定は「偽(False)」になる。「= NULL」とした場合,常に「偽」と判定される。NULLかどうかの判定には,「IS NULL」を使う。図4(2)のSELECT文は,
SELECT *
FROM TEST
WHERE C1 IS NULL ;
と記述すれば,NULLかどうかが判定できる。NULLでないかどうかを判定するには,「IS NOT NULL」とする。
NULL値をほかの値に置き換えて使う
3つ目のポイントは,NULL値を含むカラムをキーにソートした場合,NULL値は並びの最後になることである(図4(3))。NULL値は,数値や文字と比較することができないため,ソート対象から外され,ソート結果の最後に並べられる。
4つ目のポイントは,NULL値の四則演算の結果はNULLになることだ(同(4))。NULLに対する足し算,引き算,掛け算,割り算の結果はすべてNULLになる。5つ目のポイントは,SQL関数の引数にNULLを指定すると関数の戻り値はNULLになることである(同(5))。例えば文字列長さを返すLENGTH関数*の引数がNULL値であった場合,その戻り値は0ではなく,NULLになる。
このようにNULLは特殊な値であるため,比較対象や計算対象になった時の挙動をしっかり頭に入れておくことが大事である。実際のアプリケーション開発ではNULL値を意識してデータベース設計を行い,NULL値の扱い方を決めておく。NULLをほかの値に置き換えて扱うことが多く,その場合NVL関数*を使う。例えば図4(4)のSELECT文を,
SELECT NVL(C2,0) + 100
FROM TEST ;
と記述すれば,NULL値は0として計算される。NVL関数は,NULL値以外の値は変更しない。
外部結合するとNULL値が挿入される
そのほかNULL値について注意すべきは,テーブルを外部結合した場合である。外部結合するとNULL値が自動的に挿入される。
外部結合という結合は,結合対象のキー・カラムにおいて共通しない値も結合対象にする方法である。通常の単純結合では,結合対象のキー・カラムにおいて共通する値だけを結合対象とする。例えば,販売した商品の個数を格納した「販売テーブル」と,全商品種類の商品情報を格納した「商品テーブル」がある場合を考える。常に全種類の商品が販売されるわけではないため,販売テーブルの商品は,全商品種類の一部しかないケースが多い(図5[拡大表示])。そのようなテーブル構成において商品種類ごとの販売数を計算する場合,通常の単純結合では販売した商品一覧しか出力されず,販売数が0の商品は出力されない。
販売数が0の商品を含めて全商品一覧を出力したい場合,外部結合を行えばよい。Oracleで外部結合をさせるには,WHERE句の2つのカラムのうち,データの種類数が少ないカラムに「(+)」と記述する。図5の場合は,販売テーブルの商品コード・カラムに「(+)」を記述する。
図5下の場合,商品名が「えええ」と「おおお」の商品は販売されなかったため,これらに該当する販売テーブルのレコードが存在しない。データが存在しないことになり,そのような場合NULL値が挿入される。
この例の場合,外部結合した結果の数量を基に販売数量の合計を求めると,NULL値が計算対象外になる。販売数量の合計はNULL値があってもなくても結果は変わらないが,平均値とレコード数の算出の場合はNULL値の有無で結果が変わる。NVL関数を使ってNULLを0に置き換えることを忘れないようにしなければならない。
●複合インデックス 利用は検索条件のカラムに左右される |
複合インデックスとは,複数カラムのデータを含むインデックスのことである。複合インデックスは,単一カラムのインデックスよりも高速な検索を行うことができる。しかし,単一インデックスに比べればインデックスの利用制限は厳しく,条件に合わなければ使われない。
インデックス内のカラムの順番が重要
複合インデックスは,複数のカラムを検索条件にすることが多い場合によく使う。例えば「販売日」と「商品コード」の2つのカラムを条件に検索することが多い場合,この2つのカラムの複合インデックスは,どちらか一方の単一インデックスよりも高速な検索が行える可能性が高い。基本的に1つのSELECT文を処理するのに使うインデックスは1つであり,1つのカラム値で絞り込めるレコード数よりも2つ以上のカラム値で絞り込めるレコード数の方が少なくなるからだ。
ただ,複合インデックス内のカラムの順番が「販売日」,「商品コード」の順の場合,検索条件に「販売日」がなければ,この複合インデックスは使われない(図6(1)[拡大表示])。その理由は,複合インデックスの内部構造を見れば分かる。複合インデックスの内部は,第1ソート・キーが「販売日」で,第2ソート・キーが「商品コード」になっている。インデックス内のデータの並びが「販売日」順になっているため,「商品コード」だけが検索条件にある場合,複合インデックスは利用されず,全件検索が行われる。
複合インデックスが使われるようにするには,まず複合インデックス内の先頭カラムが検索条件にあることが必要である(図6(2))。図6の例は2つのカラムによる複合インデックスであるが,3つ以上のカラムにおいても同様のルールが適用される。つまり,検索条件のカラムが,複合インデックス内のカラムの並び順でなければ,複合インデックスは使われない*4。例えば複合インデックスが「A」「B」「C」というカラムの順で作成した場合,「A」と「B」が検索条件であればインデックスは使われる。一方,「A」と「C」が検索条件でもインデックスは使われることがあるが,複合インデックスの「A」の情報しか利用しない。
次回は日付型,グループ関数,副問合せなどの注意点を解説する予定である。
玉川 敏一 シーズ・ラボ ITソリューション部 セクションマネージャー |