3.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
是用来把记录按照宠物的主人分组, 否则,你将得到一条错误信息:
mysql> SELECT owner, COUNT(*) FROM pet;
ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...)
with no GROUP columns is illegal if there is no GROUP BY clause
COUNT()
和 GROUP BY
可以让你以各种各样的方式展示数据表中的数据,下面的例子显示了对pet表的各种统计操作:
按类别统计动物的数量:
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 | +---------+------+----------+
3.3.4.9. 使用多个表
pet
表只是保存了你所拥有的宠物的基本信息,或许你还需要保存其它的信息,诸如象它们生活中发生的一些事件,比如什么时候看兽医了,什么时候生小动物了等等。这个表应该是个什么样子呢?它需要:
-
需要包含宠物的名字,以便你能知道是发生在哪知宠物身上的事件。
-
一个时间,以便你能知道事件是什么时候发生的。
-
一个描述事件的字段。
-
一个事件类型字段,以便你能将事件进行分类。
出于这些考虑,event
表的CREATE TABLE
语句应该看起来象这样:
mysql>CREATE TABLE event (name VARCHAR(20), date DATE,
->type VARCHAR(15), remark VARCHAR(255));
和pet
表一样,可以创建一个以tab符分割的文本文件来载入初始化数据:
name | date | type | remark |
Fluffy | 1995-05-15 | litter | 4 kittens, 3 female, 1 male |
Buffy | 1993-06-23 | litter | 5 puppies, 2 female, 3 male |
Buffy | 1994-06-19 | litter | 3 puppies, 3 female |
Chirpy | 1999-03-21 | vet | needed beak straightened |
Slim | 1997-08-03 | vet | broken rib |
Bowser | 1991-10-12 | kennel | |
Fang | 1991-10-12 | kennel | |
Fang | 1998-08-28 | birthday | Gave him a new chew toy |
Claws | 1998-03-17 | birthday | Gave him a new flea collar |
Whistler | 1998-12-09 | birthday | First birthday |
象这样载入记录:
mysql> LOAD DATA LOCAL INFILE 'event.txt' INTO TABLE event;
以我们在pet
表上学到的查询基础,要在event
表上执行查询是很简单的,因为它们的规则是一样的。 但是,如果event
表自身的信息不足以回答你的问题,怎么办?
假设你想知道你的宠物是在多大年龄生小动物的,我们知道需要计算两个时间之间的差值,但是, 生小动物的时间在event
表种,但是要用来计算年龄的出生日期却在pet
表中,说明这个查询需要涉及到两个表:
mysql>SELECT pet.name,
->(YEAR(date)-YEAR(birth)) - (RIGHT(date,5)<RIGHT(birth,5)) AS age,
->remark
->FROM pet, event
->WHERE pet.name = event.name AND event.type = 'litter';
+--------+------+-----------------------------+ | name | age | remark | +--------+------+-----------------------------+ | Fluffy | 2 | 4 kittens, 3 female, 1 male | | Buffy | 4 | 5 puppies, 2 female, 3 male | | Buffy | 5 | 3 puppies, 3 female | +--------+------+-----------------------------+
下面是这个查询中需要注意的事情:
-
FROM
子句列出了两个表名,因为这个查询需要从两个表中提取数据。 -
当关联 (joining) 多个表中的信息时, 你需要指定一个表中的信息是怎样和另外一个表中的信息进行匹配的,在这个例子中很简单,因为它们都有name字段,
WHERE
子句使用name字段匹配两个表中的信息。 -
由于
name
列同时出现在两个表中, 所以你必须指定你引用的name列属于哪个表, 这是通过在列名前面指定表名来做到的。
你并不是必须在两个不同的表之间进行关联, 有些时候一个表也可以和它自己关联,如果你想在同一个表中把一条记录和另外一条记录进行比较,例如,要为两只动物配对,你可以让pet
表和自己关联来找出哪两只动物种类相同而性别不同:
mysql>SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
->FROM pet AS p1, pet AS p2
->WHERE p1.species = p2.species AND p1.sex = 'f' AND p2.sex = 'm';
+--------+------+--------+------+---------+ | name | sex | name | sex | species | +--------+------+--------+------+---------+ | Fluffy | f | Claws | m | cat | | Buffy | f | Fang | m | dog | | Buffy | f | Bowser | m | dog | +--------+------+--------+------+---------+
在这个查询中,我们为这个表的两次引用分别指定了别名,这样可以明确指出哪个列名属于哪个引用。

相濡以沫,不如相忘于江湖