【ORACLE】NULL大全集


### 【背景】

オラクルマスターSilver SQLを受験してやっぱりNULLの扱いって微妙だなーって思ったのでそんなに物量ありませんが、まとめました！
ORACLEの現場にいる方だったら割とピンとくる気がしますがNULLの扱いが面倒ですよね、、（別にオラクルじゃなくてもそうか、、）
後から見て振り返りやすい様にまとめたので良かったらチラ見程度で参考にしていってください。


---
### 目次
１.NULLとは
２.NULLの判定・扱い
３.NULLを考慮する・しない処理（関数）
４.実際の開発現場でのNULL事象
５.体験記

---

### １.NULLとは


======================

『NULLは空文字の扱い』

======================

NULLは通常のデータと違い違った扱いをする為、開発案件や見積り調査等で
NULLを扱う際は十分な注意が必要になります。

---

### ２.NULLの判定・扱い

そのテーブルのその項目がNULLであるかどうかを判定する際は以下のように判定します。

```PLSQL:NULL関連ファンクション例　NVL
--テーブル：test
name       nenrei
---------- -------- 
test1       61
test2       24
test3       

--testテーブルの「nenrei」カラムがNULLのレコードを取得する
SELECT name, nenrei FROM test where nenrei IS NULL;
--結果： 
name       nenrei
---------- -------- 
test3       

--testテーブルの「nenrei」カラムがNULLではないレコードを取得する
SELECT name, nenrei FROM test where nenrei IS NOT NULL;
--結果： 
name       nenrei
---------- -------- 
test1       61
test2       24
```

下記の様には判定できません。

× 『= NULL』
× 『= ''』

```PLSQL:NULL関連ファンクション例　NVL
--テーブル：test
name       nenrei
---------- -------- 
test1       61
test2       24
test3       

--testテーブルの「nenrei」カラムがNULLのレコードを「= NULL」判定で取得する
SELECT name, nenrei FROM test where nenrei = NULL;
--結果： レコードが選択されませんでした。

--testテーブルの「nenrei」カラムがNULLのレコードを「= ''」判定で取得する
SELECT name, nenrei FROM test where nenrei = '';
--結果： レコードが選択されませんでした。

```

#### ・NULLの算術式や文字列の連結
NULLを計算や文字列の結合に使用する際は以下のような動作をします。
計算処理での出力結果が空文字（NULL）になってしまったりと注意が必要になります。
⇨NULLを考慮した処理を実装する必要があることもある

```PLSQL:NULL関連ファンクション例　NVL

--NULLと数値を計算する
SELECT NULL + 10 FROM dual;
--結果：     ※空文字(NULL)

--NULLとNULLを文字列結合する
SELECT NULL || NULL FROM dual;
--結果：     ※空文字(NULL)

--NULLと文字列を文字列結合する
SELECT NULL || 'test' FROM dual;
--結果：test

```


#### ・ORDER BY句でのNULLの動作
【注意点】NULLは一番大きい値として扱われる


```PLSQL:NULL関連ファンクション例　NVL
--テーブル：test
name       nenrei
---------- -------- 
test1       61
test2       24
test3       

--testテーブルの「nenrei」カラムにて昇順でレコードを取得する
SELECT name, nenrei FROM test ORDER BY nenrei ASC;
--並べ換え結果：
name       nenrei
---------- -------- 
test2       24
test1       61
test3       

--testテーブルの「nenrei」カラムにて降順でレコードを取得する
SELECT name, nenrei FROM test ORDER BY nenrei DESC;
--並べ換え結果：
name       nenrei
---------- -------- 
test3       
test1       61
test2       24

```
**備考：**
DESC（降順）にてNULLデータを最後に持ってきたい場合は「NULLS LAST」を使用する様にしましょう。
※「NULLS FIRST」もあります。「NULLS FIRST」「NULLS LAST」についての説明は割愛いたします。

 
---

### ３.NULLを考慮する・しない処理（関数）

--カウントする処理や集計する処理は注意が必要

|関数|処理内容 
|---|---|
|COUNT(*) |NULLも含めた件数を取得する| 
|DITINCT（列名） |NULLを排除した上で重複業を排除した結果を出力|


#### ・集計ファンクション

下記、集計ファンクションにて〇〇（列名）とするとNULLを排除した動作になる。
例：SUM(列名), AVG(列名), MAX(列名), MIN(列名), COUNT(列名)

|ファンクション|説明 
|---|---|
|SUM |合計を求める| 
|AVG |平均値を求める|
|MAX |最大値を求める|
|MIN |最小値を求める|
|COUNT |行数をカウントする|


```PLSQL:NULLを考慮する・しない処理（関数）
--テーブル：test
name       nenrei
---------- -------- 
test1       61
test2       24
test3       
test4       30
test5       30

--testテーブルの「nenrei」カラムを「*」でレコードを取得する
SELECT COUNT(*) FROM test;
--結果：5

--testテーブルの「nenrei」カラムをCOUNTでレコードを取得する
SELECT COUNT(nenrei) FROM test;
--結果：4

--testテーブルの「nenrei」カラムをDISTINCTにてレコードを取得する
SELECT DISTINCT(nenrei) FROM test;
--結果：
nenrei
-------- 
61
24
30
--※NULLを排除した動作

--testテーブルの「nenrei」カラムにて昇順でレコードを取得する
SELECT COUNT(DISTINCT(nenrei)) FROM test;
--結果：3　※一つ上の結果をカウントした結果

--testテーブルの「nenrei」カラムを集計ファンクション「AVG」でレコードを取得する
SELECT AVG(nenrei) FROM test;
--結果：36.25 ※(61+24+30+30)/4

--testテーブルの「nenrei」カラムを集計ファンクション「AVG」でレコードを取得する
--NULLを考慮した処理を実施
SELECT AVG(NVL(nenrei,0)) FROM test;
--結果：29 ※(61+24+0+30+30)/5

```


#### ・NULL関連ファンクション

テーブルの制約にて NOT NULL制約を用いていないカラムについてなど
上記でも解説した通り集計する際などにNULLデータがカウント（件数取得）されていない為、正しく集計されない場合があります。
PL/SQLの現場などにいらした方ならピンとくると思いますがNVLやNVL2で変換している処理がたくさんあるかと思います。


|ファンクション|説明 
|---|---|
|NVL |NULLを指定した値に置き換える| 
|NVL2 |NULLかどうかに応じて異なる値を戻す|
|NULLIF |値が等しい場合にNULLを戻す|
|COALESCE |複数の値のうち、最初に見つかった非NULL値を戻す|

```PLSQL:NULL関連ファンクション例　NVL
--test3の「nenrei」カラムがNULL
SELECT name, nenrei FROM test;

name       nenrei
---------- -------- 
test1       61
test2       24
test3       

----------------------------------------------------------------------
--NVLを使用した場合
SELECT name, NVL(nenrei,0) FROM test;

name       nenrei
---------- -------- 
test1       61
test2       24
test3       0
```


```PLSQL:NULL関連ファンクション例　NVL2
--NVL2：第１引数がNULLではない場合は、第２引数を取得。
--     第１引数がNULLの場合は、第3引数を取得
--test3の「nenrei」カラムがNULL
SELECT name, nenrei FROM test;

name       nenrei
---------- -------- 
test1       61
test2       24
test3       

----------------------------------------------------------------------
--NVL2を使用した場合
SELECT name, NVL2(nenrei, nenrei, XX) FROM test;

name       nenrei
---------- -------- 
test1       61
test2       24
test3       XX -- ⇨test3に元々「44」と入っている場合は「44」と出力される。
```


---

### ５.体験記

**実際の開発案件での体験**

実際の開発案件にてテーブルのカラム追加を行なった際に仕様からNULLに対して許容するか否かをお客様へ確認を行った経験がありました。
カラム追加をしたテーブル関してはフロントのオンライン画面でも見えるところだった為、もしNULLが流れてきた場合はオンライン画面上どう見せたいか、また、NULLがデータとして流れてくることによってシステムエラー等で落ちないかどうかを考慮したりデグレード試験をどの程度実施する必要があるかなどを考える必要が出てきていました。

NULLをテーブルレベルから許容するか否かを設計フェーズより前にて判断するのは当時の私にとってはかなり大変な思考でしたが今回のようなこうした知識があればもう少し判断に余裕を持たせられたのかなって思っています！

【前提】
カラム追加するテーブルにはNOT NULL制約は付けておらず、また、デフォルトの設定もしていなかった為、NULLのデータが流れてくる仕様

---

一読頂いてありがとうございます❗️❗️