在MySql中执行查询时与only_full_group_by相关的错误

我已经升级了我的系统,并安装了MySql 5.7.9与我的工作的Web应用程序的PHP。 我有一个dynamic创build的查询,并在较旧版本的MySql中运行时,它工作正常。 由于升级到5.7我得到这个错误:

SELECT列表的expression式#1不在GROUP BY子句中,并且包含非聚集列'support_desk.mod_users_groups.group_id',它在function上不依赖于GROUP BY子句中的列; 这与sql_mode = only_full_group_by不兼容

请注意关于服务器SQL模式主题的Mysql 5.7手册页。

这是给我麻烦的查询:

SELECT mod_users_groups.group_id AS 'value', group_name AS 'text' FROM mod_users_groups LEFT JOIN mod_users_data ON mod_users_groups.group_id = mod_users_data.group_id WHERE mod_users_groups.active = 1 AND mod_users_groups.department_id = 1 AND mod_users_groups.manage_work_orders = 1 AND group_name != 'root' AND group_name != 'superuser' GROUP BY group_name HAVING COUNT(`user_id`) > 0 ORDER BY group_name 

我在这个问题上做了一些search,但我不明白only_full_group_by足以找出我需要做什么来修复查询。 我可以closuresonly_full_group_by选项only_full_group_by ,还是还有其他的我需要做的?

让我知道如果你需要更多的信息。

我只是将group_id添加到GROUP BY

SELECT一个不属于GROUP BY组成部分的列时,组内的该列可能会有多个值,但结果中只有一个空间可用于单个值。 所以, 通常需要告诉数据库如何将这些多个值合并为一个值。 通常,这是用像COUNT()SUM()MAX()等集合函数完成的…我通常说,因为大多数其他stream行的数据库系统坚持这一点。 但是,在5.7之前的MySQL中,默认行为更加宽容,因为它不会抱怨,然后随意select任何值 ! 它还有一个ANY_VALUE()函数,如果你真的需要和以前一样的行为,可以作为这个问题的另一个解决scheme。 这种灵活性是有代价的,因为它是非确定性的,所以我不会推荐它,除非你有一个很好的理由需要它。 MySQL现在开启了默认情况下的only_full_group_by设置,所以最好习惯它,并使查询符合它。

那么为什么我上面的简单答案? 我做了一些假设:

1) group_id是唯一的。 看起来合理,毕竟这是一个“身份证”。

2) group_name也是唯一的。 这可能不是这样一个合理的假设。 如果情况并非如此,并且您有一些重复的group_names ,然后按照我的build议将group_id添加到GROUP BY ,则可能会发现现在获得的结果比以前更多,因为具有相同名称的组现在将具有单独的行结果。 对我来说,这会比隐藏这些重复组更好,因为数据库已经悄悄地select了一个值!

当涉及多个表时,使用表名或别名限定所有列也是一个好习惯。

 SELECT g.group_id AS 'value', g.group_name AS 'text' FROM mod_users_groups g LEFT JOIN mod_users_data d ON g.group_id = d.group_id WHERE g.active = 1 AND g.department_id = 1 AND g.manage_work_orders = 1 AND g.group_name != 'root' AND g.group_name != 'superuser' GROUP BY g.group_name, g.group_id HAVING COUNT(d.user_id) > 0 ORDER BY g.group_name 

您可以尝试通过执行以下操作来禁用only_full_group_by设置:

 mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'; mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'; 

您可以按照其他答案中的说明closures警告消息,或者您可以了解发生的情况并解决问题。

从MySQL 5.7.5开始,默认的SQL模式包括ONLY_FULL_GROUP_BY ,这意味着当您对行进行分组,然后从这些组中select某些内容时,您需要明确说明应从哪个行进行select。 Mysql需要知道您要查找的组中的哪一行,这给了您两个选项

Mysql需要知道您要查找的组中的哪一行,这给了您两个选项

  • 您还可以group by rect.color, rect.value将您想要的列添加到组语句group by rect.color, rect.value在某些情况下可以是您想要的,否则将使用您可能不想要的相同颜色返回重复的结果
  • 你也可以使用mysql的聚合函数来指示你在AVG() MIN() MAX() 完整列表
  • 最后你可以使用ANY_VALUE()如果你确定组内的所有结果是相同的。 DOC

如果您不想在当前查询中进行任何更改,请按照以下步骤操作 –

  1. stream浪ssh到你的盒子里
  2. 键入: sudo vim /etc/mysql/my.cnf
  3. 滚动至文件底部并键入A进入插入模式
  4. 复制和粘贴

     [mysqld] sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 
  5. inputesc退出input模式

  6. 键入:wq保存并closuresvim。
  7. 键入sudo service mysql restart重启MySQL。

我使用Laravel 5.3,MySQL 5.7.12,在laravel宅基地(0.5.0,我相信)

即使在明确设置编辑/etc/mysql/my.cnf以反映:

 [mysqld] sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 

我仍然收到错误。

我必须将config/database.phptrue更改为false

  'mysql' => [ 'strict' => false, //behave like 5.6 //'strict' => true //behave like 5.7 ], 

进一步阅读:

https://laracasts.com/discuss/channels/servers/set-set-sql-mode-on-homestead https://mattstauffer.co/blog/strict-mode-and-other-mysql-customizations-in-laravel -5-2

使用ANY_VALUE()来引用非ANY_VALUE()列。

从MySQL 5.7文档 :

您可以通过使用ANY_VALUE()来引用非ANY_VALUE()列来实现相同的效果,而不禁用ONLY_FULL_GROUP_BY

由于select列表中的非ONLY_FULL_GROUP_BY地址列未在GROUP BY子句中命名,因此此查询可能无效, ONLY_FULL_GROUP_BY启用ONLY_FULL_GROUP_BY

 SELECT name, address, MAX(age) FROM t GROUP BY name; 

如果您知道,对于给定的数据集,每个名称值实际上唯一确定地址值,地址在function上实际上取决于名称。 要告诉MySQL接受查询,可以使用ANY_VALUE()函数:

 SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name; 

我会尽力向你解释这个错误是关于什么的。
从MySQL 5.7.5开始,选项ONLY_FULL_GROUP_BY是默认启用的。
因此,根据标准的SQL92及更早的版本:

不允许查询select列表,HAVING条件或ORDER BY列表引用既未在GROUP BY子句中命名也未在function上依赖于GROUP BY列(由其唯一确定)的非聚合列

( 更多文档 )

所以,例如:

 SELECT * FROM `users` GROUP BY `name`; 

执行上面的查询后,您将收到错误消息。

#1055 – SELECT列表的expression式#1不在GROUP BY子句中,并且包含非聚集列“testsite.user.id”,它在function上不依赖于GROUP BY子句中的列; 这与sql_mode = only_full_group_by不兼容

为什么?
因为MySQL不完全明白,从分组logging中检索什么特定值,这就是重点。

IE让我们说你有这个logging在你的users表中:
哟

你会执行上面的无效查询showen。
你会得到上面显示的错误,因为有3个logging名为John ,这是很好的,但是,他们都有不同的email字段值。
所以,MySQL根本不明白哪个返回结果分组logging。

你可以通过改变你的查询来解决这个问题:

 SELECT `name` FROM `users` GROUP BY `name` 

此外,你可能想要添加更多的字段到SELECT部分​​,但你不能这样做,如果他们不汇总,但有拐杖,你可以使用(但非常reccomended):

 SELECT ANY_VALUE(`id`), ANY_VALUE(`email`), `name` FROM `users` GROUP BY `name` 

在这里输入图像描述

现在,您可能会问,为什么不推荐使用ANY_VALUE
因为MySQL并不完全知道分组logging的检索价值,所以通过使用这个函数,你可以提取它们中的任何一个(在这种情况下,第一个logging的名字= John的电子邮件被提取)。
确切地说,我不能想出为什么你会想这种行为存在的任何想法。

请,如果你不了解我,阅读更多关于如何分组在MySQL中的作品,这是非常简单的。

最后,这是一个更简单,但有效的查询。
如果要根据可用年龄查询总计用户数,则可能需要记下此查询

 SELECT `age`, COUNT(`age`) FROM `users` GROUP BY `age`; 

根据MySQL规则,这是完全有效的。
等等。

了解问题究竟是什么,只有写下解决scheme才是重要的。

如果你正在使用wamp 3.0.6或者stable 2.5以外的版本,你可能会遇到这个问题,首先问题是sql。 你必须相应地命名字段。 但还有另一种方法可以解决这个问题。 点击wamp的绿色图标。 mysql-> mysql设置 – > sql_mode-> none。 或从控制台,您可以更改默认值。

 mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'; mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'; 

对于mac:

1.将默认的my-default.cnf复制到/etc/my.cnf

 sudo cp $(brew --prefix mysql)/support-files/my-default.cnf /etc/my.cnf 

2.使用你最喜欢的编辑器在my.cnf中更改sql_mode并将其设置为此

 sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 

重新启动MySQL服务器。

 mysql.server restart 

对于localhost / wampserver 3,我们可以设置sql-mode = user_mode来删除这个错误:

 click on wamp icon -> MySql -> MySql Setting -> sql-mode -> user_mode 

然后重启wamp或者apache

这是帮助我理解整个问题的原因:

  1. https://stackoverflow.com/a/20074634/1066234
  2. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

并在下面的另一个有问题的查询的例子。

问题:

 SELECT COUNT(*) as attempts, SUM(elapsed) as elapsedtotal, userid, timestamp, questionid, answerid, SUM(correct) as correct, elapsed, ipaddress FROM `gameplay` WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 1 DAY) AND cookieid = # 

通过添加到最后解决:

  GROUP BY timestamp, userid, cookieid, questionid, answerid, elapsed, ipaddress 

注意:请参阅PHP中的错误消息,它会告诉您问题出在哪里。

例:

MySQL查询错误1140:在没有GROUP BY的聚合查询中,SELECT列表的expression式#4包含非聚集列'db.gameplay.timestamp'; 这是不符合sql_mode = only_full_group_by – 查询:SELECT COUNT(*)作为尝试,SUM(elapsed)作为elapsedtotal,userid,时间戳,questionid,答案ID,SUM(正确)正确,已过去,IP地址从游戏玩法WHERE timestamp> = DATE_SUB (NOW(),INTERVAL 1 DAY)和userid = 1

在这种情况下,GROUP BY中缺lessexpression式#4

在文件/etc/mysql/my.cnf中添加行(在下面提到)

 [mysqld] sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 

为我工作得很好。 服务器版本:5.7.18-0ubuntu0.16.04.1 – (Ubuntu)

你可以添加一个unique index group_id ; 如果你确定group_id是唯一的。

它可以解决你的情况,而无需修改查询

答案很晚,但答案中还没有提到。 也许它应该完成已经全面的答案。 至less它解决了我的情况,当我不得不分裂一个桌子太多领域。

抱歉不使用你的确切的SQL

我用这个查询来克服Mysql的警告。

 SELECT count(*) AS cnt, `regions_id` FROM regionables WHERE `regionable_id` = '115' OR `regionable_id` = '714' GROUP BY `regions_id` HAVING cnt > 1 

记下我的存在的关键

 count(*) AS cnt 

如果Symfony使用原则查询生成器时出现此错误,并且此错误是由orderBy引起的:

注意select你要groupBy的列,并使用addGroupBy而不是groupBy

 $query = $this->createQueryBuilder('smth')->addGroupBy('smth.mycolumn'); 

Symfony3运行