5.3.4.8 统计行数

数据库通常用于回答这个问题,“某种类型的数据在表中出现的频率是多少? 例如,您可能想知道您有多少只宠物,或者每个主人有多少只宠物,或者您可能想对您的动物进行各种人口普查操作。

计算您拥有的动物总数与“pet 表中有多少行? 相同,因为每只宠物有一条记录。 COUNT(*) 统计行数,因此计算您的动物数量的查询如下所示

mysql> SELECT COUNT(*) FROM pet;
+----------+
| COUNT(*) |
+----------+
|        9 |
+----------+

之前,您检索了拥有宠物的人的姓名。 如果您想找出每个主人有多少只宠物,可以使用 COUNT()

mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
+--------+----------+
| owner  | COUNT(*) |
+--------+----------+
| Benny  |        2 |
| Diane  |        2 |
| Gwen   |        3 |
| Harold |        2 |
+--------+----------+

前面的查询使用 GROUP BY 对每个 owner 的所有记录进行分组。 将 COUNT()GROUP BY 结合使用对于在各种分组下表征您的数据非常有用。 以下示例展示了执行动物普查操作的不同方法。

每个物种的动物数量

mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| bird    |        2 |
| cat     |        2 |
| dog     |        3 |
| hamster |        1 |
| snake   |        1 |
+---------+----------+

每种性别的动物数量

mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+------+----------+
| sex  | COUNT(*) |
+------+----------+
| NULL |        1 |
| f    |        4 |
| m    |        4 |
+------+----------+

(在此输出中,NULL 表示性别未知。)

每种物种和性别组合的动物数量

mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | NULL |        1 |
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

使用 COUNT() 时,无需检索整个表。 例如,之前的查询(仅对狗和猫执行)如下所示

mysql> SELECT species, sex, COUNT(*) FROM pet
       WHERE species = 'dog' OR species = 'cat'
       GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
+---------+------+----------+

或者,如果您只想了解性别已知的动物的每种性别的动物数量

mysql> SELECT species, sex, COUNT(*) FROM pet
       WHERE sex IS NOT NULL
       GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

如果除了 COUNT() 值之外还指定了要选择的列,则应存在一个命名相同列的 GROUP BY 子句。 否则,将发生以下情况

  • 如果启用了 ONLY_FULL_GROUP_BY SQL 模式,则会发生错误

    mysql> SET sql_mode = 'ONLY_FULL_GROUP_BY';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT owner, COUNT(*) FROM pet;
    ERROR 1140 (42000): In aggregated query without GROUP BY, expression
    #1 of SELECT list contains nonaggregated column 'menagerie.pet.owner';
    this is incompatible with sql_mode=only_full_group_by
  • 如果未启用 ONLY_FULL_GROUP_BY,则服务器会将所有行视为一个组来处理查询,但为每个命名列选择的值是不确定的。 服务器可以自由地从任何行中选择值

    mysql> SET sql_mode = '';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT owner, COUNT(*) FROM pet;
    +--------+----------+
    | owner  | COUNT(*) |
    +--------+----------+
    | Harold |        8 |
    +--------+----------+
    1 row in set (0.00 sec)

另请参阅 第 14.19.3 节,“MySQL 对 GROUP BY 的处理”。 有关 COUNT(expr) 行为和相关优化的信息,请参阅 第 14.19.1 节,“聚合函数说明”