17

目前我正在使用 mysql 5.7 开发和 5.6 生产。每次我在开发中使用 group by 运行查询时,我都会收到一些错误,例如“错误代码:1055。SELECT 列表的表达式 #1 不在 GROUP BY 中”

这是查询。

SELECT c.id, c.name, i.* 
 FROM countries c, images i 
WHERE i.country_id = c.id
GROUP BY c.id; Fixed for 5.7; 

SELECT c.id, c.name,
       ANY_VALUE(i.url) url, 
       ANY_VALUE(i.lat) lat, 
       ANY_VALUE(i.lng) lng 
  FROM countries c, images i
 WHERE i.country_id = c.id
 GROUP BY c.id;

为了解决这个问题,我使用了 5.7 ANY_VALUE 中的 mysql 函数,但主要问题是它在 mysql 5.6 中不可用

因此,如果我修复用于开发的 sql 语句,我将在生产中遇到错误。

您知道 mysql 5.6 中 ANY_VALUE 函数的任何解决方案或 polifill 吗?

4

3 回答 3

19

代替ANY_VALUE,您可以使用MINMAX聚合函数。

或者,您可能会考虑不设置ONLY_FULL_GROUP_BYSQL 模式,这是默认为 MySql 5.7 设置的,它负责您在使用 MySql 5.6 时遇到的差异。然后,您可以延迟查询的更新,直到您将所有环境迁移到 MySql 5.7。

两者中哪一个是更好的选择,值得商榷,但从长远来看,调整您的查询会更好,以便它们遵守ONLY_FULL_GROUP_BY规则。使用MINMAX肯定可以用于这样做。

于 2016-05-07T14:20:15.940 回答
19

您滥用了臭名昭著的非标准 MySQL 扩展 GROUP BY。标准 SQL 将始终拒绝您的查询,因为您提到的列不是聚合的,也没有在GROUP BY. 在您的开发系统中,您正在尝试使用ANY_VALUE().

在生产中,您可以关闭ONLY_FULL_GROUP_BY MySQL 模式。 尝试这样

  SET @mode := @@SESSION.sql_mode;
  SET SESSION sql_mode = '';
  /* your query here */
  SET SESSION sql_mode = @mode;

这将允许 MySQL 接受您的查询。

但是看,您的查询并不正确。当您可以说服它运行时,它会从images表中返回一个随机选择的行。这种不确定性通常会给用户和您的技术支持人员造成混淆。

为什么不让查询更好,所以它选择一个特定的图像。如果您的images表格有一个自动增量id列,您可以这样做来选择“第一个”图像。

SELECT c.id, c.name, i.*
  FROM countries c
  LEFT JOIN (
       SELECT MIN(id) id, country_id
         FROM images
        GROUP BY country_id
       ) first ON c.id = first.country_id
  LEFT JOIN images i ON first.id = i.id

这将在每个国家/地区返回一行,并显示可预测的图像。

于 2016-05-07T14:26:28.247 回答
4

几十年来,您可以编写在标准 SQL 中无效但在 mysql 中完全有效的查询

在标准 SQL 中,包含 GROUP BY 子句的查询不能引用选择列表中未在 GROUP BY 子句中命名的非聚合列。例如,此查询在标准 SQL 中是非法的,因为选择列表中的非聚合名称列未出现在 GROUP BY 中:

SELECT o.custid, c.name, MAX(o.payment) FROM orders AS o, customers AS c WHERE o.custid = c.custid GROUP BY o.custid; 为了使查询合法,名称列必须从选择列表中省略或在 GROUP BY 子句中命名。

MySQL 扩展了 GROUP BY 的标准 SQL 使用,以便选择列表可以引用未在 GROUP BY 子句中命名的非聚合列。

这来自GROUP BY上的 Mysql 5.6 手册页。如果您查看5.7.6的同一页面,您会发现情况发生了变化。并且发生了翻天覆地的变化!!

该页面还为您提供了解决方案。禁用ONLY_FULL_GROUP_BY这将使您的旧 5.6 查询可以在 5.7.6 上工作(从您的查询中删除 ANY_VALUE,因为它在 5.7.6 中不可用,而是使用 ONLY_FULL_GROUP_BY)。

于 2016-05-07T14:24:21.397 回答