このすみろぐ

とあるWebエンジニアが、技術や趣味について書くブログです。

SQLのCOUNT関数内で、判定条件を使って集計するときは「OR NULL」を追加しよう

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関数は使い始めるようにしたいです。