我有以下MySQL表和查询:http://sqlfiddle.com/#!9/13a3c84/2
如您所见,它正在以MySQL 5.6
运行。
我要执行以下查询:SELECT * FROM (SELECT * FROM test ORDER BY year DESC) x GROUP BY title;
这将使以下内容:
MySQL 5.6
的输出是:
3 Test Name 2017
与MySQL 5.7.28
相同,给出以下输出:
1 Test Name 2015
我想,MySQL 5.6
和MySQL 5.7.28
之间有所变化,但是呢?
MySQL 5.7是第一个默认拒绝此类查询的人。您必须为该查询设置sql模式才能运行。
[按某项分组时,select中的所有内容都应在组中或使用聚合函数。
您的查询不明确,因此可以更改。如果要选择最低年份,请使用select title, min(year)
标题很好,因为它属于分组依据。而且年份很好,因为它在聚合函数中
您现在获得不同的结果,因为您的查询一开始并不完全正确。
GROUP BY
子句允许将来自不同源行的值合并到单个结果集行中。有两种方法可以实现它:
SUM()
,COUNT()
或AVG()
。您的查询过去一直是不正确的,因为它采用了第三种方法:选择给定列具有不同值的行,并按照没有确定性的规则任意选择其中一个值。
[大多数其他DBMS只会中止查询并引发错误。但是,MySQL传统上一直很宽容,并且很容易产生错误的结果。
仅输出标题相同的年份最高的行的正确方法是什么?
您可以使用下面的查询来获得所需的结果。
查询:
select
t1.*
from
test as t1
left join
test as t2 ON t1.title = t2.title and t1.year < t2.year
where
t2.id is null;
输出:
id |标题|年-:| :-------- | ---:3 |测试名称| 2017年4 |测试2016年
小提琴:fiddle here
并且在MySQL 8+中(使用默认设置),您会得到一个错误,因为SELECT
中的列不在GROUP BY
中。顺便说一句,这是正确的行为。您的查询格式不正确。
如果要为每个title
选择最新的数据行,那么您应该考虑的是“过滤器”而不是“聚合”。
这意味着您需要where
子句(或类似内容)。对于您的问题,我建议使用相关子查询:
select t.*
from test t
where t.year = (select max(t2.year)
from test t2
where t2.title = t.title
);
在test(title, year)
上有索引,这也应该比您的版本快。
我手头没有这两个版本,以查看您所说的内容是否可复制。如果是这样,则原因可能与子查询结果的实现有关。在MySQL 5.7的不同发行版中,优化程序都得到了改进。
为了使您的版本能够正常工作(我在引号中加上了引号,因为由于SELECT
中包含未聚合的列,因此语法无效的SQL),MySQL必须实现子查询。但是,在某些时候,优化器可能认为这是不必要的-基本上忽略了子查询中的ORDER BY
。这将解释结果的差异。
无论如何,正确编写查询,这不是问题。