凄く過激なタイトルを付けてしまいました。
これはあるSQL文を見て、それを短く書き換えたときの感情です。
SELECT SUM(CASE WHEN condition > 100 THEN 0 ELSE 1 END) as positive FROM some_table
1行で書いてしまいましたが、もともとはCASE文が数層入れ子になっていて、複雑な条件式を最後にSUMで括っていた、というのが複数項目にも及んでいた感じのSQLでした。そして、CASE式で評価される結果は必ず0か1。つまるところ、CASE文をたくさん組み合わせて条件を作り、条件に合うものを数えるということをやっていたわけです。
最初に思ったのは「WHERE句で条件絞ってcountすればいいじゃん」ってことです
SELECT COUNT(condition) as positive FROM some_table WHERE condition > 100
そうできればよかったんですが…条件に合う件数を数える項目がほかにもたくさんあり、それぞれで
毎回SQLを発行するのもこれまた頭が悪い。
SQLの返答をphp側でforeach回してオレオレカウントする…というのも考えたのですが、
カウント部分で何をやっているかを把握しようとするとCASE文のピラミッドとどっこいどっこいだなとも。
「テーブル全体を検索しつつ、複数条件それぞれにおいて条件に合うものをcountするには…」と調べていて、
このタイトルの「Say yes or die!」にたどり着いたわけです。
MySQLの論理式にはTrue、FalseのほかにNullを叩き込むことができると言う話があって…
- True AND Null = Null
- False AND Null = False
- True OR Null = True
- False OR Null = Null
つまるところ、Nullの有無にかかわらずTrue/False断言できる式は断言してもらえるという結果になるわけです。
そして、count()はNullでないものを数える。
というわけで生まれるイディオムが count([何か条件式] OR Null) というわけです。
条件式がTrueならレコードはTrueと評価され、カウントの対象になる、
条件式がFalseまたはNullなら、レコードはFalseと評価され、カウントされない。
このイディオムを使って最初のSQLを書き直すと…
SELECT count((condition > 100) OR NULL)as positive FROM some_table
‘OR NULL’という書き方の意味さえ知っていれば、これが何かを「合計」しているわけではなく「数えている」ことが一目でわかりますし、何より、WHERE句を変えながら何度もSQL発行しなくて済みます。別のカウントをしたいときは条件を変えた検索フィールドを追加するだけですから。
「Say yes or die!」もとい「Be true or null!」使えると思います!