Nullについて

 Accessを使う以上は避けて通れないNullについてです。
 「値がない」というごく当たり前のことに過ぎないのですが、Accessでは取り扱いが複雑なものとなりますので常にその存在を意識する必要があります。Access(正確に言うとデータベースと呼ばれるソフト)を扱う場合の宿命といえますが、仕方がありませんので早めに慣れるようにしましょう。

Nullとは

f:id:accs2014:20170923213158p:plain:right:w400

 テーブルを作成して入力を進めていく中で、さまざまな値が記録されていきますが、そのうち何も入力されない部分が生じることがあります。この画像の例では2行目の「右視力」列の値と3行目の「体重」列の値がありません。
 このように値が存在しない状態のことをNull(ヌル)と呼びます。妙な名前ですがその正体は単純で、ただ値がないというだけのことです。
 このような状態が発生する原因として次のようなものが考えられます。

・値は存在するはずなのだが、把握できない
・値がそもそも存在し得ない(例:個人事業主の発行株数)
・単なる入力漏れ;-o-)


f:id:accs2014:20170923213155p:plain:right:w400

 さて、テーブルには「値要求」というプロパティがあり、これを「はい」にすると、そのフィールドには必ず何かの値を入力しなければなりません。「値要求」を「はい」にすることは、つまりNullという状態が発生することを許さないということです。
 画像の例では「氏名」列の「値要求」プロパティを「はい」としています。これによって氏名がNullとなることを防いでいます。


f:id:accs2014:20170923213152p:plain:right:w400

 ところで、フィルターを使ったときに、値がない状態は「(空白)」と表されます。しかしAccessでの一般的な呼び方はやはりNullです。フィルターの例はむしろ特別で、クエリなどでこのような状態を指定する場合には「Is Null」と表さなければなりません。「= Null」ではなく「Is Null」です。後の節で説明しますが、このことはぜひ覚えておいてください。


スペースとの違い

 Nullに似たものとしてスペース(半角スペース、全角スペース)があります。スペースもNullも、どちらも何もないように見えます。
 しかしスペースは文字記号の一種ですので、大きさがあり普通の文字のように選択してコピーペーストすることもできます。他の文字の間に挟まれていればその存在を視覚的にも把握できます。一方Nullは文字や記号ではありません。

空文字列(長さ0の文字列)との違い

f:id:accs2014:20170923213149p:plain:right:w400

 さらにNullに似たものとして空文字列(長さ0の文字列)というものがあります。
 これはデータ型がテキスト型のフィールドで「""」(ダブルクォーテーションを2つ)と記入することで入力できます。
 画像は4行目の「氏名」列に空文字列を入力中の状態です。なお、上記で示したように「氏名」列の「値要求」プロパティは「はい」としています。


f:id:accs2014:20170923213146p:plain:right:w400

 4行目入力後の状態です。「氏名」の値は空文字列で、「左視力」以降の列はNullとなっています。見た目はどちらも「何もない」ように見えるためとてもまぎらわしいです。
 空文字列は「文字列なのに文字数が0」という奇怪な存在でありNullに似ていますが、Nullと違って「値」として扱われますので「値要求」が「はい」であってもエラーにはなりません(空文字列をも許容しない場合は「空文字列の許可」プロパティを「いいえ」にします)。


Nullの性質

f:id:accs2014:20170923213246p:plain:right:w400

 比較のためにまずExcelの例を見てみます。Excelでは値のない状態のセルを空白セルと呼びます。
 画像のようにD3セルが空白セルであるときに「=C3+D3」という計算をすると、空白セルであるD3の値は0であるかのような結果となります。


f:id:accs2014:20170923213242p:plain:right:w400

 ただしCOUNT関数(数値の個数を数える)を用いると、空白セルは数値としてカウントされません。AVEGARE関数などでも空白セルは計算の対象から除外されます。


f:id:accs2014:20170923221827p:plain:right:w400

 では空白セルは数値ではないのかという話になりますが、IF関数を使ってD3セルが0なのか否かを判定すると0そのものであるとの結果が返ります。
 このように集計の内容によって0のようであったりなかったりします。慣れればさほど気になりませんが、Excelの空白セルの扱いも結構独特ですので注意が必要です。

f:id:accs2014:20170923213233p:plain:right:w400

 一方でAccessのNullもExcel以上に独特です。上記のテーブル(最初の画像)に「視力の和」という集計列を設けて、式を「[左視力]+[右視力]」と設定します。


f:id:accs2014:20170923213230p:plain:right:w400

 データシートビューです。
 2行目の「右視力」列がNullとなっていますが、この行の「視力の和」列には何も表示されていません。Excelの例のように0.7という結果になりそうな気もしますがそうはならず、結果がNullになってしまうのです。

f:id:accs2014:20170923213338p:plain:right:w400

 次の例です。「身長体重比」という集計列を設け、式を「[身長]/[体重]」とします。


f:id:accs2014:20170923213329p:plain:right:w400

 3行目の「体重」列がNullとなっており、その結果「身長体重比」の値もNullとなっています。ゼロで割り算したときのようにエラーが出そうな気がしますが、そうはならず結果はNullになります。Accessにおいて1/NullはNullであり、さらに言えばNull/1もNullに、Null/NullもNullになります。
 これらの例のように、AccessではNullを含む四則演算の結果はすべてNullになります。複雑な長い計算式でも1つNullが含まれるだけでNullになります。この点がExcelとの大きな違いです。


f:id:accs2014:20170923213324p:plain:right:w300

 ただし、集計行を用いた場合には結果はNullにならず、Nullであるレコードが集計対象から除外されて集計されます。
 また、後でクエリについて説明しますが、クエリにおいても縦に集計したときは結果はNullにならず、Nullであるレコードが集計対象から除外されるだけです。この辺りはExcelの例に似ています。


f:id:accs2014:20170923232427p:plain:right:w400

 次にIIf関数を使ってNullが0とみなされるかを試してみますが…


f:id:accs2014:20170923232422p:plain:right:w400

 Excelとは違い、0ではないという結果になります。


f:id:accs2014:20170923233726p:plain:right:w400

 だんだんよくわからなくなってきますが、さらに独特かつ問題なのは抽出の対象としてNullを扱う場合です。
 ちょっと予習になりますが、この画像ではクエリによりテーブルのデータを抽出しようとしています。
 具体的には「『右視力』列の値が0であるか、または『右視力』列の値が0でない」という条件でレコードを抽出しようとしています。
 普通に考えますと「右視力」列の値が何であれ、0であるか0でないかのどちらかに間違いありませんので、この条件ではすべてのレコードが抽出されると思われます。しかし…

f:id:accs2014:20170923233723p:plain:right:w400

 なんと「右視力」列がNullであるレコード(テーブルの2行目)は抽出されません。
 何かの値と比較することでNullを抽出することはできず、条件に「Is Null」と明記しなければならないのです。これを忘れて「数値型の列は0であるか0でないかのどちらかに二分できる」とか「文字型の列は『ABC』であるか『ABC』でないかのどちらかに二分できる」と考えてしまうと、Nullであるレコードが集計から漏れてしまうという事態が起こるのです。

Nullをどう扱うか

 Excelでは空白セルの存在はさほど問題にされません。そもそもシートを作成した段階ですべてのセルが空白セルですし、空白セルのせいで計算結果が空白になることはなく、抽出にもさほど支障はありません。
 しかしAccessの場合、Nullの取り扱いは厄介で、常に意識していないと集計漏れなどのトラブルに直結します。必然的に、できる限りNullはない方がよい、ということになります。
 対策としてはテーブルのつくりを工夫する(後で説明する正規化の実施)によって発生を抑えるほか、値要求プロパティを駆使して何が何でもNullを阻止する、ということが考えられます。しかし「値がわからない」といった場合がどうしても出てきますので、そのようなデータは不適切なものとしてレコードごと記録対象から除くのか、あるいは仮の値を入力するのかといった取り決めが必要になってきます。ただし仮に0とか99999とかを入力するようにした場合、その取り扱い自体を忘れて抽出・集計してしまうなど別の問題を生むことがあります。
 結局のところNullを完全に排除するのは困難ですので、重要な抽出・集計に関わる列についてはNullを許さず値が不明な場合などの取り扱いについてはしっかり取り決めをし、それ以外の列はあまり固く考えずNullを許容するという結論になろうかと思います。

 また、Nullにより四則演算等に支障が出る件については、Nz関数によりNullをゼロに変換するといった対策が考えられます。