SQLのSELECT結果からCOUNT関数を使い、複数のデータ集計をしたい局面がありました。
/* aのカラムには、「0」と「3」の値が入っている */ mysql> SELECT * FROM sample; +---+ | a | +---+ | 0 | | 3 | +---+ 2 rows in set (0.00 sec)
そこで次のSQLを実行したのですが、想定外の値が返ってきました。
/* COUNT(a > 1)の結果は、「2」になります */ /* COUNT(a > 3)の結果も、「2」になります */ mysql> SELECT COUNT(a > 1), COUNT(a > 3) FROM sample; +--------------+--------------+ | COUNT(a > 1) | COUNT(a > 3) | +--------------+--------------+ | 2 | 2 | +--------------+--------------+ 1 row in set (0.00 sec)
見ての通り、本来なら「a > 1」のレコード数は1のはずですが、2が返却されてしまいます。 理由が分からずハマっていたのですが、原因はどうやらCOUNT関数の特性にあるようです。
COUNT関数は、NULL以外の行数を求める
COUNT関数は引数に指定したカラムのNULLを除いた行数を取得するために使用します。
引用: https://www.dbonline.jp/mysql/function/index6.html
つまりどういうことかと申しますと、「a > 1」は真(TRUE)または偽(FALSE)を返却するため、NULLにならないのです。
偽(FALSE)のときにNULLにする
COUNT関数で正しく集計するためには、NULLを活用する必要があります。
mysql> SELECT COUNT(a > 1 OR NULL), COUNT(a > 3 OR NULL) FROM sample; +----------------------+----------------------+ | COUNT(a > 1 OR NULL) | COUNT(a > 3 OR NULL) | +----------------------+----------------------+ | 1 | 0 | +----------------------+----------------------+ 1 row in set (0.00 sec)
「OR NULL」を条件に加えることで、条件がFALSEのときにNULLと判定されるようになります。 その結果、想定した集計結果が返却されるようになりました。
さいごに
SQL関数は、意外と奥が深い分野であることを再認識しました。
必ずリファレンスを確認してから、SQL関数は使い始めるようにしたいです。