2014/10/04

Nullと空文字の扱いにハマった(Oracle vs SQL Server)

Oracle歴が長いプログラマが、SQL Serverでの開発を行った時にハマったのが、Nullと空文字("")の扱いの違いだった。

結論から言うと、以下のようになっている。
  • Oracle: 空文字 ≒ Null
  • SQL Server:空文字 ≠ Null

OracleはNullと空文字が統一に使われているが、SQL ServerではNullと空文字では違う動作する。
OracleのプロジェクトからSQL Serverのプロジェクトに変わった時に、注意が必要だ。





Null と 空文字 の扱い方の違い



例えば、以下のようなテーブルがあったとする。
伝票No 担当者 商品コード 数量
D0001 テスト S0001 10
D0002 "    " S0002 20
D0003 "" S0003 30
D0004 (Null) S0004 40


このテーブルに対して、OracleとSQL Serverが操作しようとすると以下のようになる。


Oracle の場合


SELECT *
  FROM DENPYO
  WHERE 担当者 IS NULL
--> 伝票No 「D003」、「D004」 が取得できる

SELECT *
  FROM DENPYO
  WHERE TRIM(担当者) IS NULL
--> 伝票No 「D002」、「D003」、「D004」 が取得できる


ひとつ目のSQLは、[担当者]が空文字("")の「D0003」とNullの「D0004」のレコードが取得できる。
ふたつ目のTRIMをしたSQLでは、「D0002」の[担当者]が空文字("")とみなされるため、「D0002」、「D0003」、「D0004」が取得できる。



SQL Server の場合


SELECT *
  FROM DENPYO
  WHERE 担当者 IS NULL
--→ 伝票No D004 が取得できる

SELECT *
  FROM DENPYO
  WHERE LTRIM(RTRIM(担当者)) IS NULL
--→ 伝票No D004が取得できる

SELECT *
  FROM DENPYO
  WHERE LTRIM(RTRIM(担当者)) = ""
--→ 伝票No D002、D003が取得できる

SELECT *
  FROM DENPYO
  WHERE (LTRIM(RTRIM(担当者)) = ""
        OR 担当者 IS NULL)
--→ 伝票No D002、D003、D004が取得できる

見ての通り、SQL Serverでは空白、空文字、Nullを厳密に判定している。また、前後の空白を消すTRIM関数がないので、LTRIMとRTRIMで対応している。

「IS NULL」は、本当にNullのレコードだけしか取得しない。
空文字("")の場合は、「= ""」のようにしてあげないと取得できない。



「A IS NULL OR A = ""」という書き方を「A IS NULL」だけで済ますことができるから、個人的にはOracleの仕様のほうが楽だなぁ。


以上

written by @bc_rikko

0 件のコメント :

コメントを投稿