【初級編⑭】SQL Server におけるNULLの取り扱い

データベースでレコードを取り扱う上で避けては通れない「NULL」とは一体なんなのか、どのような特徴や制約があるのかについて解説したいと思います。

NULLとは

NULLは、ヌルやナルと読み、値が何も存在しない状態を表しています。値が存在しない状態とは、文字列の空文字(”)や数値の0などとは明確に区別されます。どちらかと言うと、NULLは特殊な値として扱われます。

基本的には、レコードを作成する時に値を何も指定しなかった列はNULL(何も指定していないから値が存在しない状態)となります。空文字や数値の0は、それぞれ明示的に値をセットしていることになります。

例えば以下のようなクエリ結果を見てみると、社員番号が00008の給料はNULLですが、社員番号が00007の部署コードは空文字であり、NULLではありません。

NULLと空文字

このNULL値を検索したい場合は、WHERE句の書き方を工夫しなければなりません。

SELECT *
FROM Table_Syain
WHERE 給料 = NULL

------------------------------------------------------------------------
社員番号  名前                   年齢          性別   生年月日       給料          部署コード
----- -------------------- ----------- ---- ---------- ----------- -----

(0 行処理されました)

このように、NULLを普通に検索してもヒットしません。前述した通りNULLは特殊な値になりますので、NULLであるレコードを検索するにはWHERE句に「項目名 IS NULL」と書かなければなりません。逆にNULLではないレコードを検索するには「項目名 IS NOT NULL」と書きます。

SELECT *
FROM Table_Syain
WHERE 給料 IS NULL

------------------------------------------------------------------------
社員番号  名前                   年齢          性別   生年月日       給料          部署コード
----- -------------------- ----------- ---- ---------- ----------- -----
00008 増田 八助                30          男    1982-10-05 NULL        B001

(1 行処理されました)
SELECT *
FROM Table_Syain
WHERE 給料 IS NOT NULL

------------------------------------------------------------------------
社員番号  名前                   年齢          性別   生年月日       給料          部署コード
----- -------------------- ----------- ---- ---------- ----------- -----
00001 田中 一郎                20          男    1993-01-01 205000      A001
00002 山田 二郎                41          男    1972-01-02 420000      A001
00003 鈴木 三つ子               28          女    1985-01-03 250000      A004
00004 高橋 四郎                35          男    1978-01-04 360000      A005
00005 松村 五郎                26          男    1987-01-05 230000      A004
00006 前田 六実                20          女    1993-01-06 180000      A002
00007 七道 剛                 28          男    1985-02-04 270000

(7 行処理されました)

それぞれ、WHERE句の指定を変えることで正しくレコードが取得できていることが分かります。

また、IN句にNULLを指定することはできません。

NULLはIN句に書けない

ちょっと例が悪いですが、給料がNULLのレコードが取得できていません。この例でNULL値も取得したい場合は、OR でIS NULL を繋げてあげると、NULLのレコードも取得できます。

IS NULLをORで繋げる

NULLの使い道

NULLの使い道は、前述したとおり「値が存在しない状態を表す」ことにあります。文字列の場合、空文字はれっきとした値が存在しますし、数値の場合も0は明確に値が存在します。そこで例えば、外部のシステムが出力したCSVなんかをデータベースに取り込む際、値がセットされていない項目はNULLにすることで、処理の結果を分岐したい場合など、でしょうか。

日付の値は、取り扱うプログラムや環境によって初期値となる値が変わります(1900年1月1日とか)ので、文字列の空文字や数値の0のような表現がしづらいです。そこで、NULLを使うことで日付の値として何も存在しない(値がセットされていない)状況が簡単に作り出せるのです。

他には、テーブルの外部結合を行った結果、結合されるレコードが存在しない場合もNULLになります。

外部結合でNULL

NULLを許容するかどうか

レコードの値としてNULL値を許容するかどうかを指定することができます。指定するには、テーブル定義から項目に対して指定します。現在の設定状況は、Management Studioの「テーブル」→「列」を開くことで分かります。

NULLを許容する項目

NULL許容設定1

個人的には、極力文字列型や数値型はNULLを許容しない方が好きです。日付型だけは初期値の扱いが面倒なのでNULL許容してもいいと思います。

NULLが許容されると、一つ一つ後述するISNULL関数を使わなければならなくなったりと、NULLを考慮しないといけなくなるので面倒です。






NULLの演算

NULL値に対して、* や / 等の各種演算を行った場合、計算できないので結果はNULLになります。

NULL値の演算結果はNULL

また、集計関数を使用した時はNULLのレコードは無視されます。以下のような給料の平均値を求めるSQLを実行した場合を見てみると、社員は合計8人いるのに7で割られていることが分かります。

集計関数ではNULLは無視される

他にも、SUM MAX MIN でも同様にNULLのレコードは無視されます。COUNTの場合は少し特殊で、COUNT(*)はNULLも含めるがCOUNT(給料)はNULLを無視します。

COUNTの場合

ISNULL関数

NULL値をNULLのまま取り扱うのは、多少面倒です。上述のとおり、NULL値との演算は全てNULLになってしまいますが、例えば集計等を行った場合、値が無ければ0として取り扱いたいことが多いと思います。

そんな時は「ISNULL()」関数を使い、もし値がNULLだった場合に別の値に置き換えることができます。

ISNULL(変換対象の項目, 変換後の値)

ISNULL関数

さきほどのAVGでも、このISNULL()関数は有効です。ISNULL()した結果をAVGすれば、NULLではない値を集計していることになるのでカウントしてくれます。

ISNULLした上でAVG

NULL許容していて、このISNULL()をし忘れるとバグります。。。NULL許容していなかったら絶対にNULLは存在しない状態にデータベースレベルで実現できるので(開発者が何もしなくても)、余計な考慮をしなくて済むというお話です。

以上が、データベースにおけるNULLの取り扱いの説明です。

この記事と関連性の高い記事