更新一:
有一些参考者反馈文中“COUNT写法”的可用性问题,这里就在文首提前聊一个概念性问题。众所周知,关系型数据库思想和SQL规范都源自IBM。然后基于(并非完全遵守)关系型数据库的理论思想和SQL标准,很多商业版或社区开源版的关系型数据库软件产品出现了。其中商业版比较知名的有IBM的DB2、Oracle的Oracle以及Microsoft的SQL Server;开源免费版比较流行的有MySQL(现在也属于Oracle公司)/MariaDB(MySQL被Oracle化后的新分支)、PostgreSQL、SQLite。虽然这些RDBMS产品都是关系型,并且支持SQL,但是每种产品的实现都是不同的,对SQL标准的支持也是不一样的。即便是同一个数据库产品,当进行过一些比较大的版本更新后,其设计和实现也可能会焕然一新。所以,也就是要有——数据库与数据库之间以及数据库版本与版本之间差异性——的概念。下文内容整理自第三版《高性能MySQL》,主要基于MySQL5.5而写,而个人举的游客数据示例查询,印象中是在MySQL5.6和5.7版本都测试过的。所以如果使用其他数据库产品、甚至是示例用MySQL但是其他比较旧的或者久远的将来很新的版本,当查询出现不适用的情况时,要将其看作是一件再正常不过的事情。
SQL查询中经常会碰到需要在一条语句中统计某字段中不同记录值的数量,即频数统计。在看《高性能MySQL》(https://book.douban.com/subject/23008813/)这本“葵花宝典”时看到里面总结了两种方法,我在这里再整理记录一下:一种是“SUM”法;另一种是“COUNT”法。
如示例表“visitor_province_day”数据所示,记录游客在每个省驻留的天数。现在想知道若干省份(如“陕西省”和“浙江省”)被游客游览的次数,就可以直接计数它们的记录数来进行统计。
mysql> select * from visitor_province_day;
+---------+-----------+-----+
| visitor | province | day |
+---------+-----------+-----+
| 1 | 陕西省 | 5 |
| 1 | 河北省 | 2 |
| 1 | 浙江省 | 9 |
| 11 | 浙江省 | 7 |
| 11 | 江苏省 | 3 |
| 11 | 湖南省 | 1 |
| 11 | 福建省 | 4 |
| 11 | 陕西省 | 1 |
| 11 | 浙江省 | 5 |
| 11 | 广东省 | 9 |
| 11 | 陕西省 | 11 |
+---------+-----------+-----+
“SUM”写法。
SELECT SUM(IF(vpd.province = '陕西省', 1, 0)) AS cnt_sx, SUM(IF(vpd.province = '浙江省', 1, 0)) AS cnt_zj
FROM visitor_province_day AS vpd;
+--------+--------+
| cnt_sx | cnt_zj |
+--------+--------+
| 3 | 3 |
+--------+--------+
“COUNT”写法。
SELECT COUNT(vpd.province = '陕西省' OR NULL) AS cnt_sx, COUNT(vpd.province = '浙江省' OR NULL) AS cnt_zj
FROM visitor_province_day AS vpd;
+--------+--------+
| cnt_sx | cnt_zj |
+--------+--------+
| 3 | 3 |
+--------+--------+
由结果可以看出样本中两个省份的频次是一样的,都是3次。如果要进行多个匹配,把“=”改成“IN”列表的形式就可以了,如IN('陕西省', '浙江省')。更甚,也可以把等号替换成“LIKE”或者“REGEXP”模糊匹配噢!