MySQL GROUP BY行为

时间:2009-10-29 19:14:14

标签: sql mysql group-by

给出下表“foo

ID | First Name | Last Name
----------------------------
67   John        Smith
----------------------------
67   Bill        Jacobs

以下查询返回的内容为first_namelast_name,为什么?

SELECT * FROM foo WHERE ID = 67 GROUP BY ID

6 个答案:

答案 0 :(得分:27)

MySQL任意选择一行。实际上,常用的MySQL存储引擎会返回组中 first 行中与物理存储相关的值。

create table foo (id serial primary key, category varchar(10));

insert into foo (category) values 
  ('foo'), ('foo'), ('foo'), ('bar'), ('bar'), ('bar');

select * from foo group by category;

+----+----------+
| id | category |
+----+----------+
|  4 | bar      |
|  1 | foo      |
+----+----------+

其他人都认为MySQL允许您运行此查询,即使它具有任意且可能具有误导性的结果。 SQL标准和大多数其他RDBMS供应商不允许这种模糊的GROUP BY查询。这称为单值规则:select-list中的所有列必须明确地成为GROUP BY标准的一部分,或者在聚合函数内部,例如, COUNT()MAX()

MySQL支持SQL模式ONLY_FULL_GROUP_BY,如果您尝试运行违反SQL标准语义的查询,则会使MySQL返回错误。

AFAIK,SQLite是唯一允许分组查询中含糊不清的列的其他RDBMS。 SQLite从组中的 last 行返回值:

select * from foo group by category;

6|bar
3|foo

我们可以想象查询不会模糊,但仍然违反SQL标准语义。

SELECT foo.*, parent_of_foo.* 
FROM foo JOIN parent_of_foo 
  ON (foo.parent_id = parent_of_foo.parent_id) 
GROUP BY foo_id;

没有合理的方法可以产生模棱两可的结果。如果我们GROUP BY foo的主键,foo中的每一行都有自己的组。因此foo中的任何列只能在组中有一个值。如果组由foo的主键定义,即使加入foo中外键引用的另一个表,每个组只能有一个值。

MySQL和SQLite相信您可以设计逻辑上明确的查询。形式上,select-list中的每一列必须是GROUP BY条件中列的功能依赖。如果你不遵守这个,那就是你的错。 : - )

标准SQL更严格,并且不允许某些可以明确的查询 - 可能是因为它对于RDBMS来说通常过于复杂。

答案 1 :(得分:4)

MySQLs group by与标准的SQL行为不一致,MySQL可以很容易地获得其他列但同时你永远无法确定你会得到哪一个。

更新: 参考此页面: http://dev.mysql.com/doc/refman/5.0/en/group-by-handling.html

  

使用此功能时,所有行都在   每个组应具有相同的值   对于从中省略的列   GROUP BY部分。服务器是免费的   从组中返回任何值,所以   结果是不确定的,除非   所有的价值都是一样的。

答案 2 :(得分:3)

这是未定义的,这将导致你获得。

我一直想知道为什么甚至允许这种行为。真的,我希望这样的代码只会产生一个错误(最好是一个可辨认的错误,没有那个通常的MySQL“你的语句有问题,但我不知道在哪里”。)

答案 3 :(得分:0)

很可能会选择第二行(最后一行)的名字和姓氏。

您可以添加ORDER BY子句,以提供有关如何对分组行进行排序的提示。

答案 4 :(得分:0)

在标准SQL中,此SQL应该失败,服务器处理器错误类似于

“firstname和lastname不能包含在select子句中,除非它们也在Group By中,或者是聚合函数的一部分。”

MySql是否实际为此返回数据?

答案 5 :(得分:0)

  

MySQLs group by与标准SQL行为不一致,   MySQL可以让你轻松获得其他列,但同时也是如此   永远不能确定你会得到哪一个。

真。实际上它更多地与postgres中的SELECT DISTINCT ON模式相对应,除了这允许你指定在distinctization(?)之前的行的顺序,因此你将获得哪一行(即最新,最旧,无论如何)。

注意“符合sql”模式下的MySQL将拒绝带有未指定列的GROUP BY,如示例所示。