考虑以下两个查询:
SELECT *, MAX(age) AS maxAge FROM someTable ORDER BY age ASC;
SELECT *, 'dummyC' AS dummyC FROM someTable ORDER BY age ASC;
前一个查询返回表的所有行和所有列,以及一个额外的虚拟列。后面的查询仅返回一行,即具有最低主键的行。为什么会这样,我该如何解决?在一些旧但稳定的 Debian 服务器上在 MySQL 5.1 中进行了测试。
考虑以下两个查询:
SELECT *, MAX(age) AS maxAge FROM someTable ORDER BY age ASC;
SELECT *, 'dummyC' AS dummyC FROM someTable ORDER BY age ASC;
前一个查询返回表的所有行和所有列,以及一个额外的虚拟列。后面的查询仅返回一行,即具有最低主键的行。为什么会这样,我该如何解决?在一些旧但稳定的 Debian 服务器上在 MySQL 5.1 中进行了测试。
这是一个MySQL 扩展。
MySQL 扩展了 GROUP BY 的使用,以便选择列表可以引用未在 GROUP BY 子句中命名的非聚合列。这意味着前面的查询在 MySQL 中是合法的。您可以使用此功能通过避免不必要的列排序和分组来获得更好的性能。但是,这主要在每个未在 GROUP BY 中命名的非聚合列中的所有值对于每个组都相同时很有用。服务器可以自由地从每个组中选择任何值,因此除非它们相同,否则选择的值是不确定的。此外,从每个组中选择值不会受到添加 ORDER BY 子句的影响。在选择了值之后对结果集进行排序,并且 ORDER BY 不会影响服务器选择的值。
你得到的价值是不确定的。您通常会得到插入到表中的第一行,但这不能保证。
如果您想要包含最高年龄的行中的相应值,那么最好使用ORDER BY
和的组合LIMIT 1
:
SELECT *
FROM someTable
ORDER BY age DESC
LIMIT 1;
第一个查询有一个聚合函数 ( MAX
),但没有GROUP BY
,这意味着它聚合(收集和组合值)整个结果集并将其作为一行返回。大多数 SQL 方言不允许非聚合列出现在这样的查询中,但 MySQL 特别允许。但是,这些非聚合列填充了 MySQL 遇到的第一行的值,这可能是任何行。如果您从未从有问题的表中删除过,MySQL 通常会首先找到 ID 最低的行,因为它以与存储在磁盘上的顺序相同的顺序扫描表(至少在需要全表扫描时)。如果您要在表上运行一堆DELETE
后续INSERT
语句,您至少会在某些查询中获得其他行。简而言之,不要指望得到任何特定的行。
第二个查询缺少聚合函数,因此它不执行任何隐式分组 - 您只需获得完整的结果集。
在第一个查询中,* 是隐藏列
引用 MySQL 文档:
MySQL 扩展了 GROUP BY 的使用,以便选择列表可以引用未在 GROUP BY 子句中命名的非聚合列。这意味着前面的查询在 MySQL 中是合法的。您可以使用此功能通过避免不必要的列排序和分组来获得更好的性能。但是,这主要在每个未在 GROUP BY 中命名的非聚合列中的所有值对于每个组都相同时很有用