PREPARATION
受験対策

オススメ!OSS-DB情報

第8回 NULLって何?

データベースの勉強を始めたとき、多くの人が戸惑うのが NULL です。
そもそも何と読むのでしょう?
ヌル、と言う人もいれば、ナル、と言う人もいます。
どちらが正解とは言えませんが、「ヌル」も「ナル」も「NULLである」と理解してください。

データベースには、数値型、文字列型、日付型、論理値型など様々なデータ型がありますが、どんな種類のデータも NULL という値を取ることができます。
例えば整数であれば、..., -3, -2, -1, 0, 1, 2, 3, 4... という値を取りますが、データベースでは、これら以外に NULL という値を取ることができ、これは、そのデータに「値が入っていない」「値がない」「値が不明である」といった状態を指すことになります。
「値がない」ことと「値がゼロである」ことはまったく異なることに注意してください。ゼロに対しては四則演算などを実行することができますが、値がないデータに対して演算をすることはできません。例えば、3 + 0 は 3、3 * 0 は 0、というように計算できますが、3 + NULL や 3 * NULL は計算できませんので、結果は NULL になります。このことは psql でデータベースに接続して、
select 3 + 0;
select 3 + null;
などを実行すれば確認できます。

文字列についても同じです。例えば、文字列の長さを調べる length という関数があります。length('') は 0 ですが、length(null) は NULL になります。これも、psql でデータベースに接続し、
select length(''), length(null);
などとすれば確認できます。特に、|| 演算子を使った文字列の結合には注意が必要です。
select 'abc' || null;
の結果は NULL になります。

演算の結果が NULL になるのは納得できるでしょうが、WHERE 句の条件については戸惑う人が多いでしょう。
例えば、次の SQL 文で簡単なテーブルを作ってみます。
create table testnull(id integer);
insert into testnull values (1), (2), (3), (4), (null);
ここで、
select * from testnull;
とすれば、5行のデータが返されますが、
select * from testnull where id <= 2;
select * from testnull where id > 2;
はいずれも2行のデータを返し、NULL の行は返されません。この結果自体は自然に思えるでしょうが、「id <= 2」と「id > 2」の条件のいずれにも引っかからないデータがある、ということは注意すべきです。
では、次の SELECT 文はどうでしょうか。
select count(*) from testnull;
select count(*) from testnull where id = 2;
select count(*) from testnull where id <> 2;
最初の SELECT 文はテーブル testnull の行数を返すので 5 が返ります。次の SELECT 文は id が 2 のデータの行数を返すので 1 です。最後の SELECT 文は id が 2 ではないデータの行数ですが、結果は 3 です。これは、id が NULL の行については「id = 2」も「id <> 2」もどちらも真にはならない、という論理学的な常識とは異なる仕様によって起こる結果です。逆に言うと、値の比較をするケースで、データに NULL が含まれる場合は、十分に注意しないと、期待と異なる結果になることがあります。

値が NULL かどうかを調べるには、IS NULL、あるいは IS NOT NULL を使います。上と同じテーブルを使った例ですが、
select count(*) from testnull where id is null;
select count(*) from testnull where id is not null;
を試してみてください。
なお、
select count(*) from testnull where id = null;
select count(*) from testnull where id <> null;
はエラーにはなりませんが、結果はいずれも 0 になります。NULL かどうかの確認に、= や <> を使うことができないことにも注意しましょう。

NULL の扱いについて注意しなければならないことに、集計関数があります。
主な集計関数には、count, sum, avg, max, min などがあり、それぞれ、データ件数、合計値、平均値、最大値、最小値、を計算します。上のテーブルを使って実験してみましょう。
select count(*), count(id), sum(id), avg(id), max(id), min(id) from testnull;
合計値(sum)、最大値(max)、最小値(min)が、NULL データの影響を受けず、それぞれ 10, 4, 1 になることは想像に難くないでしょう。
データ件数を返す count 関数は、引数として * を渡すと行数が返りますが、列名を渡すと NULL でないデータの件数が返ります。従って、count(*) は 5、 count(id) は 4 になります。
平均値を返す avg 関数は、NULL を除いたデータの平均、別の言い方をすれば、 sum(id) / count(id) が返ります。この例では、合計が10、データ件数が4なので、2.5が返ります。

NULL を含む演算の結果を NULL にしたくない、ということもあります。
例えば、次の SQL 文で定義したテーブル
create table testsum(a integer, b integer);
insert into testsum values (10, 20), (20, null), (null, 30), (30, 0);
において、各行の a + b の値を求めたいとしましょう。
select a + b from testsum;
とすると、2行目と3行目はいずれも NULL になってしまいます。しかし、NULL を 0 であるとみなして足し算したい、ということはよくあります。
coalesce 関数を使うことでそれが実現できます。上記の例では、
select coalesce(a,0) + coalesce(b,0) from testsum;
とします。
coalesce 関数は2つ以上の引数を取ります。
coalesce(value1, value2) では、
value1 が NULL でなければ value1 の値が、value1 が NULL であれば value2 の値が返されます。
集計関数に適用することもできて、例えば
select avg(a), avg(coalesce(a,0)) from testsum;
とすると、avg(a) は 20、avg(coalesce(a,0)) は 15 になることがわかります。

結果を NULL にしたくないのは、文字列演算の場合にも当てはまり、例えば、
create table persons(first_name varchar(20), last_name varchar(20), initial varchar(5));
insert into persons values ('Michael', 'Fox', 'J');
insert into persons values ('Ichiro', 'Suzuki', null);
のように定義したテーブルから、フルネームを取り出したいとき、
select first_name || ' ' || initial || ' ' || last_name from persons;
とすると、initial が NULL のデータについて、結合文字列もNULLになってしまいます。
select first_name || ' ' || coalesce(initial,'') || ' ' || last_name from persons;
とすれば解決します。

以上の NULL に関する事柄のほとんどは、PostgreSQL に限らず、多くの RDBMS で共通ですが、重要な例外が1つあります。
Oracleでは、NULL を含む文字列結合において NULL を返しません。つまり
select 'abc' || null from dual;
の結果は abc になります。Oracle で開発された SQL のプログラムを PostgreSQL など他の RDBMS で使う場合、文字列結合において、期待と異なる動作にならないよう、プログラム修正が必要になります。これについては「文字列リテラル」の項も参照してください。

解説:松田神一

応募者全員プレゼント!
オープンソース データベース標準教科書 -PostgreSQL-