apache
2011年09月27日
MySQLにおけるnullの取り扱い
MySQLでデータを取り出す際にちょっとはまったので覚え書き。
前提:
担当者名を入れるフィールド「charge」があり、担当者名が入っているかnullかのどちらかです。
またアクセス者名を入れる変数$userがあり、これは必ずアクセス者名が入っています。
ここで、「自分が担当者でない」データを検索するとき
〜 and charge != '$user' and 〜
としたところ、chargeがnullのデータは一切ヒットしなくなりました。
Google先生によると出てきた解は、MySQLの比較は比較物がnullの時は必ず「偽」を返す、というものでした。(これも嘘というか私の解釈違いな訳ですが)
そこで次のように変更してみます。
〜 and not(charge = '$user') and 〜
偽のnotなのでこれでうまくいくと思いましたが、結果は先ほどと全く同じ。どうもnullの扱いがよくわかりません。
さらに調べていくと…、ありました。「nullセーフ」というんだそうです。
MySQLの比較演算子「=」はnullセーフではないとのこと。「=」に相当するnullセーフな比較演算子は「<=>」なんだそうです。
つまり私の期待した答えを得られる式は
〜 and not(charge <=> '$user') and 〜
ということです。
正確な仕様は、
- MySQLの真偽は「真=1」「偽=0」と考えるとわかりやすい。
- 通常の(nullセーフでない)比較演算子は、比較対象がnullの時必ず「null」を返す。(nullは「0」(つまり偽)ではない。)
- nullセーフな比較演算子「<=>」で期待する結果が得られる。
ということの様です。(参考資料:MySQL 6.3.1.2. 比較演算子)
まとめてみると
chargeの中身 | 期待値 | charge != '$user' not(charge = '$user') | not(charge <=> '$user') |
アクセス者名 | 偽 | 偽 | 偽 |
他のユーザ名 | 真 | 真 | 真 |
null | 真 | 偽 | 真 |
こんな感じでしょうか。
ここでいう「nullセーフな比較」という概念そのものを知らなかった(全ての比較演算子がnullセーフだと思っていた)ため、ここを疑うまでに結構かかりました。
思い込みって怖いですね。
静かで安くてコストパフォーマンス最高。
Linuxサーバに最適。