分组查询

我们要讨论的最后一个查询功能是 GROUP BY 子句。通过该子句,可以对同一表中具有共同字段的行进行分组。例如,假设我们想通过一次查询就知道每个作者有多少本书。试试下面的方法:

mysql> SELECT
    -> author,
    -> COUNT(*) AS amount,
    -> GROUP_CONCAT(title SEPARATOR ', ') AS titles
    -> FROM book
    -> GROUP BY author
    -> ORDER BY amount DESC, author;

+-----------------+--------+-------------------+
| author          | amount | titles            |
+-----------------+--------+-------------------+
| George Orwell   | 2      | 1984, Animal Farm |
| Homer           | 2      | Odyssey, Iliad    |
| Bram Stoker     | 1      | Dracula           |
| Haruki Murakami | 1      | 1Q84              |
| J. M. Barrie    | 1      | Peter Pan         |
| Jodi Picoult    | 1      | 19 minutes        |
+-----------------+--------+-------------------+
5 rows in set (0.00 sec)

GROUP BY 子句总是在 WHERE 子句之后,它获取一个或多个字段(用逗号分隔),并将该字段具有相同值的所有记录视为一条记录。因此,按作者选择将分组所有包含相同作者的记录。这个功能看起来似乎不是很有用,但 MySQL 中有几个函数可以利用它。在这个例子中:

  • COUNT(*) 在使用 GROUP BY 的查询中使用,显示该字段分组的行数。在本例中,我们将用它来了解每位作者有多少本书。事实上,COUNT(*) 总是这样工作的;不过,对于不带 GROUP BY 的查询,MySQL 会将整组记录视为一组。

  • GROUP_CONCAT 与我们前面讨论过的 CONCAT 类似。唯一不同的是,这次函数将连接一个组中所有记录的字段。如果不指定 SEPARATOR,MySQL 将使用单个逗号。但是,在我们的例子中,我们需要一个逗号和一个空格来使其可读,所以我们在末尾添加了 SEPARATOR ', ' 。请注意,您可以在 CONCAT 中添加任意多的连接内容,分隔符只是将连接内容按行分隔开来。

尽管这与分组无关,但请注意我们添加的 ORDER 子句。我们按两个字段而不是一个字段排序。这意味着,MySQL 将按 amount 字段对所有记录排序;注意,这是一个别名,但在这里也可以使用。然后,MySQL 将按照标题字段对具有相同 amount 值的每组记录进行排序。

我们已经介绍了 SELECT 查询可以包含的所有重要子句,因此还有最后一件事需要记住:MySQL 希望查询的子句始终保持相同的顺序。如果你写了同样的查询但改变了顺序,你将会得到一个错误。顺序如下:

  1. SELECT

  2. FROM

  3. WHERE

  4. GROUP BY

  5. ORDER BY