[.NET][JavaScript][SQL] null と空文字の等価／不等価判定を言語別に並べて比較してみた

言語によって null や空文字の扱いは異なることがあります。
以下に例を示します。
（赤字は注意が必要な箇所です）

## 言語ごとの判定結果（C#／VB.NET／JavaScript／SQL）

|  | C# | VB.NET | JavaScript（厳密/非厳密） | SQL（ANSI/ISO 準拠） |
|:--|:--|:--|:--|:--|
| **Equals** | Equals(null, null) <br />**true** | Equals(Nothing, Nothing)<br />**True** | ― | ― |
| **Is** | ― | (Nothing Is Nothing)<br />**True** | Object.is(null, null)<br />**true** | (NULL IS NULL)<br />**TRUE** |
| **Is Not** | ― | (Nothing IsNot Nothing)<br />**False** | ― | (NULL IS NOT NULL)<br />**FALSE** |
| **null との等号比較** | (null == null)<br />**true** | (Nothing = Nothing)<br />**True** | (null === null)<br />**true**<br />(null == null)<br />**true** | (NULL = NULL)<br />**<font color="Red">UNKNOWN</font>**<br />NOT (NULL = NULL)<br />**<font color="Red">UNKNOWN</font>**<br />※NOT しても UNKNOWN（以下同様） |
| **null との不等号比較** | (null != null)<br />**false** | (Nothing <> Nothing)<br />**False** | (null !== null)<br />**false**<br />(null != null)<br />**false** | (NULL <> NULL)<br />**<font color="Red">UNKNOWN</font>** |
| **空文字との等号比較** | (null == "")<br />**false** | (Nothing = "")<br />**<font color="Red">True</font>** | (null === "")<br />**false**<br />(null == "")<br />**false** | (NULL = '')<br />**<font color="Red">UNKNOWN</font>** |
| **空文字との不等号比較** | (null != "")<br />**true** | (Nothing <> "")<br />**<font color="Red">False</font>** | (null !== "")<br />**true**<br />(null != "")<br />**true** | (NULL <> '')<br />**<font color="Red">UNKNOWN</font>** |
| **有効文字との等号比較** | (null == "a")<br />**false** | (nullString = "a")<br />**False** | (null === "a")<br />**false**<br />(null == "a")<br />**false** | (NULL = 'a')<br />**<font color="Red">UNKNOWN</font>** |
| **有効文字との不等号比較** | (null != "a")<br />**true** | (Nothing <> "a")<br />**True** | (null !== "a")<br />**true**<br />null != "a")<br />**true** | (NULL <> 'a')<br />**<font color="Red">UNKNOWN</font>** |
| **未定義値との等号比較** | ― | ― | (null === undefined)<br />**false**<br />(null == undefined)<br />**<font color="Red">true</font>** | ― |
| **未定義値との不等号比較** | ― | ― | (null !== undefined)<br />**true**<br />(null != undefined)<br />**<font color="Red">false</font>** | ― |

ポイントは3つです。

- VB.NET では、String 型の等価／不等価演算子は Nothing と空文字を等しいと判断します。
- JavaScript では、非厳密演算子は null と undefined を等しいと判断します。
- ANSI/ISO 準拠のSQLでは、比較演算子による NULL との比較結果は UNKNOWN となります。（SQL Server で [ANSI_NULLS](https://docs.microsoft.com/ja-jp/sql/t-sql/statements/set-ansi-nulls-transact-sql) オプションをOFFにすると違う結果になりますが、今後のバージョンでサポートされなくなることがアナウンスされています）

## LINQ to Entities における null の扱い
LINQ to Entities の値比較における null の扱いには別途注意が必要です。
Entity Framework 6 で [UseDatabaseNullSemantics プロパティ](https://docs.microsoft.com/ja-jp/dotnet/api/system.data.entity.infrastructure.dbcontextconfiguration.usedatabasenullsemantics) が導入され、既定（false）で (operand1 == operand2) が次のような複雑なSQL式に変換されるようになりました。
※operand1, operand2 がどちらも NULL となりうるケース、たとえば operand1 が NULL 許可列、operand2 が String 型変数の場合を想定します。

```sql
(((operand1 = operand2) AND (NOT (operand1 IS NULL OR operand2 IS NULL))) OR ((operand1 IS NULL) AND (operand2 IS NULL)))
```

どちらかが NULL の場合、ANSI 準拠の等価演算子 '=' では常に UNKNOWN が返されてしまうため、NULL を絡めた比較も正しく行われるような考慮がされています。
設定を true に変えれば (operand1 = operand2) という素直な式が生成されますが、NULL を正しく比較できないことを認識したうえで設定しないと「不可解な」挙動に頭を抱えることになりかねませんので注意しましょう。