SQLステートメントにおけるNULL値の扱い方
日常的にデータベースを利用する中で、NULL値を気にすることはないでしょうか。
実は、NULL値はデータベースにおいて非常に特殊で興味深い存在なので、見ていきましょう。
データベースに問い合わせる際、ある列(例えばユーザー登録年USER_AGE)がNULLかどうかを知りたい場合、SQLの問い合わせ文はどのように書くのでしょうか。
次のようになります。
SELECT * FROM TABLE WHERE USER_AGE = NULL
それともあれか?
SELECT * FROM TABLE WHERE USER_AGE IS NULL
もちろん、正しい書き方は2番目のもの(WHERE USER_AGE IS NULL)でしょう。
しかし、なぜこのような書き方をするのでしょうか?データベースのデータを比較するときに、"IS"というキーワードは使いませんよね?
例えば、あるカラムの値が1に等しいかどうかを知りたい場合、WHERE文は次のようになります。
WHERE USER_AGE = 1
では、なぜNULL値に対してISキーワードを使用するのでしょうか。なぜNULLをこのように扱わなければならないのでしょうか?
なぜなら、SQLでは、NULLは"unknown"を意味するからです。つまり、NULL値はquot;unknown"な値を表しています。
NULL=不明です。
ほとんどのデータベースでは、NULlと空の文字列は異なります。
例えば、Oracleは空の文字列をサポートしておらず、自動的にNULL値に変換してしまいます。
他のほとんどのデータベースでは、NULL 値と文字列は異なる方法で扱われます。
- ヌル("")文字列は、"値なし"を意味しますが、値は知られています。
- NULLは"unknown value"を意味し、値が不明であることを示します。
他の多くのデータベースが異なる扱いをするのに対し、Oracleはどちらの値もNULLを使って表現するという点で特別です。
しかし、NULLが未知の値を表すということさえ覚えておけば、SQLのクエリ文は簡単に書けるようになります。
例えば、このようなクエリ文があった場合。
SELECT * FROM SOME_TABLE WHERE 1 = 1
この問い合わせは、式 "1 = 1" が真でなければならないため、全ての行を返します(SOME_TABLEが空のテーブルではないと仮定しています)。
このように書くと
SELECT * FROM SOME_TABLE WHERE 1 = 0
式 "1 = 0" は偽で、このクエリ文はいかなるデータも返しません。
しかし、このように書くと
SELECT * FROM SOME_TABLE WHERE 1 = NULL
この時点で、データベースは2つの値(1とNULL)が等しいかどうか分からないので、"NULL" または "unknown" と仮定し、いずれのデータも返しません。
3項論理
SQLクエリ文のWHEREは、一般的に3つの結果を持ちます。
- 真になることがあります(この時点でデータが返されます)。
- はfalseにすることができます(この時点ではデータは返されません)。
- は、NULL または unknown にすることもできます (この時点ではデータは返されません)。
それなら、false や NULL を気にする必要はないじゃないか、どちらもデータを返さないじゃないか、と思うかもしれません。
次に、NOT( )メソッドを見て、問題があるところを紹介します。
このようなクエリ文があったとします。
SELECT * FROM SOME_TABLE WHERE NOT(1 = 1)
データベースは、まず1=1を計算しますが、これは明らかに真です。
次に、データベースはNOT()条件を適用するので、WHEREは偽を返します。
ですから、上のクエリはデータを返しません。
しかし、この文に変更すると
SELECT * FROM SOME_TABLE WHERE NOT(1 = 0)
データベースはまず1=0を計算するので、これは偽でなければならない。
次に、データベースは反対の結果を与えるNOT()条件をtrueに適用します。
つまり、この文はデータを返すのです。
しかし、この文をもう一度、次のように変えてみたらどうでしょうか。
SELECT * FROM SOME_TABLE WHERE NOT(1 = NULL)
データベースはまず1 = NULLを計算しますが、NULLの値がわからないので、1がNULLと等しいかどうかはわかりません。
つまり、この計算ではtrueもfalseも返さず、NULLが返されるのです。
次に、NOT() は、前の計算で返された結果の解析を続けています。
NOT() が NULL に遭遇すると、別の NULL を生成します。未知数の反対は別の未知数です。
つまり、どちらのクエリでも
SELECT * FROM SOME_TABLE WHERE NOT(1 = NULL)
SELECT * FROM SOME_TABLE WHERE 1 = NULL
どちらも正反対なのに、データを返しません。
NULLとNOT IN
もし、こんなクエリ文があったら。
SELECT * FROM TABLE WHERE 1 IN (1, 2, 3, 4, NULL)
明らかに、WHEREは真を返し、この文は括弧付きのリストに1が存在するので、データを返すことになります。
しかし、このように書くと
SELECT * FROM SOME_TABLE WHERE 1 NOT IN (1, 2, 3, 4, NULL)
明らかに、WHEREはfalseを返し、このクエリは1が括弧付きのリストに入っているためデータを返しません。
しかし、この文をこう変えてみるとどうでしょう。
SELECT * FROM SOME_TABLE WHERE 5 NOT IN (1, 2, 3, 4, NULL)
このWHEREはtrueを返さないので、データを返しません。5という数字は、NULL値があるので、括弧付きのリストに存在するかどうかわかりません(データベースはNULL値が何であるかを知りません)。
このWHEREはNULLを返すので、クエリ全体では何のデータも返されません。
SQL文でNULL値を扱う方法について、ご理解いただけたと思います。
以上、SQL文におけるNULL値の扱い方について詳しく説明しました。SQLのNULL値についてもっと詳しく知りたい方は、スクリプトハウスの他の関連記事もご覧ください
関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Spark SQL 2.4.8 データフレームを操作するための2つの方法
-
SQL SERVERのストアドプロシージャを使用した履歴データの移行について
-
SQL Server2017では、IPをサーバー名としてサーバーに接続します。
-
SQL Server一括挿入データ事例詳細
-
SQL ServerのSELECT INTOとINSERT INTOのSELECTのケースを説明する
-
mybatis動的SQLの共通シナリオのまとめ
-
SQL Server のフィルタードインデックスによるクエリ文の改善に関するパフォーマンス分析
-
SQLでのmod()関数の余りの使用法
-
そのPHP環境の普遍的なパスワードのSQLインジェクションの脆弱性と防御手段
-
データベース毎日練習問題、毎日少しづつ進歩(1)