【Access】「値がない」状態のまとめ

## はじめに
まずは、こちらのテーブルをご覧ください。
![テーブル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519886/6d1bfe57-c9e1-af78-bc94-3504bfc7025e.png)
住所カラムがぱっと見何も入っていないように見えますが、、、**入っている値が全て異なっている**んです。試しにこのようなSELECT文を実行してみると、
```
SELECT 氏名 FROM 顧客テーブル WHERE 住所 = "";
```

実行結果
![SQL実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3519886/7c579ed7-a9ef-1300-11bf-893bcb723da2.png)

あれ？2人分しか抽出できていない？？

見た目だけで区別がつかないし色々種類があって紛らわしいよ〜😭ということで、Accessのテーブルで「値がない」状態の違いやそれぞれの扱いについてまとめてみました！

:::note warn
注意
Accessの開発を始めてやっと1年経ったくらいの新人が書いております。間違い等あるかもしれませんので、その場合はご指摘ください🙇
:::

## 「値がない」状態のバリエーション
Accessのテーブルにおいて、「値がない」状態は主に3種類あります。

・NULL
・長さ0の文字列（＝空文字）
・スペース（半角・全角）

先ほどのテーブルは、上から順にこれらの値が格納されていました。それでは各パターンについて詳しく見ていきましょう。

### NULL
値がない状態のことです。NULLはVariant型の変数に格納されるリテラル値で、有効なデータが格納されていないことを表します。ADOやDAOでデータベースの操作をする場合、フィールドを操作するオブジェクトのValueプロパティがVariant型なので、値のない状態としてNullを扱うことができます。

### 長さ0の文字列
文字を一つも含まない文字列のことで、「""」で挿入できます。NULLと違い、長さ0の文字列は値を持っているという扱いになるようです。

### スペース
これが一番わかりやすいですね。半角または全角のスペースが入っているパターンです。半角か全角かで扱いが変わるため、注意が必要です。

## プロパティの設定
プロパティを設定することで、テーブルに入る値を制御することができます。Accessでは**値要求**と**空文字の許可**を組み合わせて設定します。公式のレファレンスはこちらです。

https://learn.microsoft.com/ja-jp/office/vba/access/concepts/miscellaneous/required-property-access

https://learn.microsoft.com/en-us/office/vba/access/concepts/miscellaneous/allowzerolength-property

ただ、このページの翻訳がうまく出来ておらず、とても読みにくい！！！空文字の許可に至っては、日本語版のページがない！！！仕方がないので、自分で翻訳してまとめてみました。

### 値要求
フィールドに値が必要かを設定するプロパティです。「はい」に設定されている場合、何かしらの値を入力する必要があります。NULLを入れていいか設定するという認識でよさそうです。（主キーを設定すると必ず「はい」になります）

### 空文字の許可
空文字（＝長さ0の文字列）を入れることができるかを設定するプロパティです。「はい」に設定されている場合、空文字を入力することができます。


### プロパティの組み合わせ表
各プロパティを設定した時に何が登録できるのかをまとめた表がこちらです。

|値要求|空文字の許可|①NULL|②""|③半角スペース|④全角スペース|
|:-:|:-:|:-:|:-:|:-:|:-:|
| いいえ | いいえ | NULL | × | NULL | 全角スぺース |
| いいえ | はい | NULL | "" | NULL | 全角スペース |
| はい | いいえ | × | × | × | 全角スペース |
| はい | はい | × | "" | "" | 全角スペース |

実際の操作内容は以下の通りです。
①何も入力せずにEnter押下
②長さ0の文字列（""）を入力しEnter押下
③半角スペースを入力しEnter押下
④全角スペースを入力しEnter押下

×は許可されていないためエラーとなることを示しています。
値要求「はい」、空文字の許可「いいえ」とすることで、全角スペース以外の「値がない」状態を排除することができます。この設定にしておくと紛らわしい状態は回避できそうです！
ちなみに、初期値は、値要求「いいえ」、空文字の許可「はい」となっています。一番制限が緩い設定がデフォルトだったのか、、、

また、この結果を見て気になったのですが、Accessデータベースの直接操作では半角スペースを入れることができないんですね？SQLではどうなるのだろうとUPDATE文で半角スペースを挿入してみたところ、値要求「はい」、空文字の許可「いいえ」以外は半角スペースを入れることができました。なぜSQLなら半角スペースを入れることができるかはさっぱりわからないので、ご存じの方がいらっしゃったらご教授願います。

## データの検索
SELECT文でデータを抽出する際、「値がない」ことを条件として用いる場面はまああると思います。その場合、検索条件として何を設定すると何がヒットするかをまとめたのがこちらです。縦がテーブルに入っている値、横が検索値です。
|テーブルの値/検索値|NULL|空文字|半角スペース|全角スペース|
|:-:|:-:|:-:|:-:|:-:|
| NULL | ◯ | × | × | × |
| 空文字 | × | ◯ | ◯ | × |
| 半角スペース | × | ◯ | ◯ | × |
| 全角スペース | × | × | × | ◯ |

検索においては空文字と半角スペースの違いはないようです。その他は検索した値のみがヒットしています。

## おまけ　半角スペースを含む検索
検索時の半角スペースの扱いが不思議だったので、前後に半角スペースを含む場合について追加調査してみました。表の「_」は半角スペースを、「A」は任意の値を表しています。
|テーブルの値|Aで検索|_Aで検索|A_で検索|_A_で検索|
|:-:|:-:|:-:|:-:|:-:|
| A | ◯ | × | ◯ | × |
| _A | × | ◯ | × | ◯ |
| A_ | ◯ | × | ◯ | × |
|_ A _| × | ◯ | × | ◯ |

後ろのスペースは検索条件から外されてしまっているのでしょうか、、、半角スペースは謎な部分が多いです。

## おわりに
今回調べてみて、半角スペースの扱いはかなり不思議なのだなあと思いました。半角スペースだけを挿入したい場合や前後にスペースを含んだままにしたい場合はあまりないと思うので、入力値のチェックはちゃんとしておいたほうが良さそうですね。

また、プロパティの設定によって入ってくる値がかなり変わることが分かり、テーブル設計の重要さを再認識しました。NULLも長さ0の文字列も入る設定のままだとコーディングの部分でも考慮しなければいけないことが増えるので避けたいですね。適切なテーブル設計の仕方についても今後学んでいきたいです。

## 参考サイト
* [NullとEmptyとNothingと空の文字列の違い｜Access VBA](https://www.moug.net/tech/acvba/0050010.html)
* [Nullについて - もう一度学ぶMS-Access](https://www.accessdbstudy.net/entry/20141015/p180000)
* [Access Null値の整理と判定方法、Null値によるエラーの抑止方法 IsNull VarType Nz](https://qiita.com/Q11Q/items/459171d80a42184a5f9e#null%E5%80%A4%E3%81%8C%E5%85%A5%E3%82%89%E3%81%AA%E3%81%84%E8%A8%AD%E5%AE%9A%E3%81%A7%E4%B8%80%E8%88%AC%E7%9A%84%E3%81%AB%E6%9F%94%E8%BB%9F%E3%81%AA%E3%81%AE%E3%81%AF%E5%80%A4%E8%A6%81%E6%B1%82%E3%81%AF%E3%81%84%E7%A9%BA%E6%96%87%E5%AD%97%E5%88%97%E3%81%AF%E3%81%84%E6%9F%94%E8%BB%9F%E3%81%A7%E3%82%BB%E3%82%AB%E3%83%B3%E3%83%89%E3%83%99%E3%82%B9%E3%83%88)
* [発掘：Access の Null 値と、長さ 0 の文字列の違いについて](https://qiita.com/Q11Q/items/80e1d8287fdc48388b18#%E5%80%A4%E8%A6%81%E6%B1%82%E3%81%A8%E7%A9%BA%E6%96%87%E5%AD%97%E5%88%97%E3%81%AE%E8%A8%B1%E5%8F%AF%E8%A8%AD%E5%AE%9A%E5%80%A4%E3%81%AE%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E3%81%8B%E3%82%89%E5%85%A5%E5%8A%9B%E3%81%95%E3%82%8C%E3%82%8B%E5%80%A4%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)