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


441

我已经升级了系统,并为正在使用的Web应用程序安装了带有PHP的MySql 5.7.9。我有一个动态创建的查询,当在旧版本的MySql中运行时,它运行良好。自升级到5.7以来,出现此错误:

SELECT列表的表达式#1不在GROUP BY子句中,并且包含未聚合的列'support_desk.mod_users_groups.group_id',该列在功能上不依赖于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

我在该问题上进行了一些谷歌搜索,但是我对它的理解还only_full_group_by不足以弄清楚我需要做什么来解决该查询。我可以仅关闭该only_full_group_by选项,还是需要做其他事情?

如果您需要更多信息,请与我们联系。


在这里,我找到了解决方案stackoverflow.com/a/7588442/612987
Wasim A.

21
这必须是我遇到的最复杂的错误消息。
罗尔夫(Rolf)'18

2
@Rolf您是否看到Oracle中相同类型问题的错误?” not a GROUP BY expression“就是这样。他们也可能只有数字错误代码而根本没有消息。
比尔·卡温

Answers:


359

我只是添加group_idGROUP BY

什么时候 SELECT不属于的GROUP BY列时,组中该列可能有多个值,但是结果中只有一个值的空间。因此,通常需要准确告知数据库如何将多个值变成一个值。通常,这是与像一个聚合函数中完成COUNT()SUM()MAX()等...我说一般,因为大多数其他流行的数据库系统坚持这一点。但是,在版本5.7之前的MySQL中,默认行为更为宽容,因为它不会抱怨,然后可以任意选择任何值!它也有一个ANY_VALUE()如果您确实需要与以前相同的行为,则可以将该函数用作该问题的另一个解决方案。这种灵活性要付出一定的代价,因为它是不确定性的,因此除非您有充分的理由需要它,否则我不建议您这样做。MySQL现在only_full_group_by有充分的理由默认启用该设置,因此最好习惯它,并使您的查询符合它。

那么,为什么我上面的简单答案呢?我做了两个假设:

1)group_id是唯一的。似乎合理,毕竟它是一个“ ID”。

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

当涉及多个表时,最好用表名或别名来限定所有列...

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

谢谢,效果很好。我也同意我需要对列进行限定。它消除了任何歧义的可能性。我现在正在修复代码。感谢一百万的帮助。
Dan Bemowski

我什至GROUP BY在查询中都没有子句,但出现此错误。
aitchkhan

@HaroonKhan,这听起来像是一个新问题。如果您提出要求,请告诉我,我会看看。
davmos

2
在MySQL 5.7中,它们设置了一个属性,该属性要求查询中的所有非聚合字段均为GROUP BY。因此,像SELECT a,SUM(b)FROM table这样的查询;表示字段“ a”必须在GROUP BY中。因此,如果您没有GROUP BY,则必须将其添加到查询中。这与查询的SELECT部分​​中是否至少有一个聚合字段有关。
user1567291

我必须按照此答案中的建议,通过将项目添加到group by子句来解决“警告”问题,因为没有任何建议sql_mode修复的答案起作用。(我的MySQL在存储过程中,但不知道是否相关)
zzapper

353

您可以尝试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';

MySQL 8不接受,NO_AUTO_CREATE_USER因此需要删除。


85
这是一种解决方法,您最好解决查询而不是静默警告
azerafati

1
更新/etc/mysql/my.cnf(如下所示)是一种更具可持续性的解决方案,因为默认设置在重启后往往会恢复。对于那些说您应该修复查询的人,那么有时候当您需要快速调试查询并执行诸如SELECT COUNT(*), t.* FROM my_table t GROUP BY col20-50列之类的事情时,这并不是一件容易的事,您是否想花费那么多时间将每个列添加到通过...分组?
Shadoweb

3
这种“解决方案”非常危险。您可以通过盲目的更改它们来激活以前禁用的模式,而不是仅删除有问题的一个设置标志。这可能会导致意外的行为,并且在最坏的情况下可能导致错误的结果或使您的应用完全无法运行。因此,我认为这个答案是错误的。
克里斯·S

1
我通过确定当前的sql_mode SELECT @@sql_mode;并将其结果添加到my.cnf中,从而通过刷新使此持久化:sql_mode=[list of modes from query, minus ONLY_FULL_GROUP_BY]
wbharding

323

您可以按照其他答案中的说明关闭警告消息,也可以了解发生的情况并进行修复。

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

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

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

25
我不认为MySQL支持该FIRST()方法/功能吗?
本·吉尔德

3
我认为MySQL(至少在5.7之前)默认使用其在组中找到的第一个值。因此,没有FIRST(),因为它曾经与GROUP BY函数本身同义。
DrDamnit '16

2
@DrDamnit,我认为在这种情况下,它更像是随机选择,这会导致混乱,因此ONLY_FULL_GROUP_BY默认情况下启用
azerafati 2016年

6
我已经知道答案了,但是带有彩色矩形的示例非常容易理解,下次有人问我时,我将重用该示例。
user327961

@azerafati是否有类似FIRST()的查询或可以用于获取第一个值的查询,例如我。
哈里斯

169

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

  1. 流浪者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. 键入esc退出输入模式

  6. 键入:wq以保存并关闭vim。
  7. 键入sudo service mysql restart以重新启动MySQL。

只是想尝试将所有Vagrant用户与AdonisJS一起使用时,您需要它来运行该paginate功能。
Michael J. Calkins,2016年

显然,这不仅适用于Vagrant用户,而且适用于所有Unix系统。请注意,对我而言,my.cnf文件的位置为/etc。阿尔斯(Als)注意到新的语法MySQL 5.7.8: sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
瓦伦丁·格雷戈尔

在薄荷19.3对我的作品(Ubuntu的18.04)感谢
马尔科·洛佩斯

71

使用ANY_VALUE()来指代非聚集列。

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

MySQL 5.7 docs

ONLY_FULL_GROUP_BY 通过使用ANY_VALUE()引用未聚合的列,可以在不禁用的情况下实现相同的效果。

...

此查询ONLY_FULL_GROUP_BY启用后可能无效,因为GROUP BY子句中未命名选择列表中的非聚合地址列:

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

...

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

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

1
作为已经有一段时间遇到此问题的人-我特别喜欢此解决方案,因为它不需要您更改MySQL设置中的任何文件或设置。有趣的是,ANY_VALUE 在类似的讨论中,我没有看到其他地方提到过-完全可以解决我的GROUP_BY contains nonaggregated column错误。
adstwlearn

50

我将尝试向您解释此错误的含义。
从MySQL 5.7.5开始ONLY_FULL_GROUP_BY,默认情况下启用该选项。
因此,根据标准SQL92和更早版本:

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

在文档中阅读更多

因此,例如:

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

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

#1055-SELECT列表的表达式#1不在GROUP BY子句中,并且包含未聚合的列'testsite.user.id',该列在功能上不依赖于GROUP BY子句中的列;这与sql_mode = only_full_group_by不兼容

为什么?
因为MySQL不能完全理解,所以要从分组记录中检索某些值,这就是重点。

IE可以说您在users表中有以下记录:
哟

您将执行上面显示的无效查询。
而且您会得到上面显示的错误,因为有3条记录具有name John,这很不错,但是它们都有不同的email字段值。
因此,MySQL根本不理解在结果分组记录中返回哪个。

您可以通过如下更改查询来解决此问题:

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

另外,您可能想向SELECT部分​​添加更多字段,但是,如果它们没有聚合,则不能这样做,但是您可以使用拐杖(但不推荐):

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

在此处输入图片说明

现在,您可能会问,为什么ANY_VALUE不强烈建议使用?
由于MySQL并不完全知道要检索的分组记录的值,因此通过使用此功能,您要求它提取其中的任何一个(在这种情况下,将提取名称为John的第一条记录的电子邮件)。
确实,我无法提出任何有关为什么您希望这种行为存在的想法。

请,如果您不了解我,请阅读更多有关MySQL中分组工作原理的信息,这非常简单。

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

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

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

重要的是要了解问题的根源,然后写下解决方案。


感谢您的答复。如果我也希望将电子邮件作为结果组中的数组怎么办?
约西亚

1
您始终可以在GROUP_CONCAT必填字段中获取所有条目。
亚伯拉罕·图加洛夫'17

哦! 所以有办法!请帮助我解决这个问题
Josiah

感谢您的出色回答。如果我想怎么办GROUP BY DAY(created_date)?如果DAY()添加,它似乎不起作用。
eskimo

41

我在Laravel Homestead(0.5.0,我相信)上使用Laravel 5.3,mysql 5.7.12

即使在明确设置编辑/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.php来自truefalse

    '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


ang!这对Laravel用户很有帮助。+1。
Okafor T Kosiso

20

如果您使用的是wamp 3.0.6或稳定版2.5以外的任何更高版本,则可能会遇到此问题,首先是sql问题。您必须相应地命名字段。但是还有另一种解决方法。单击沼泽的绿色图标。mysql-> mysql设置-> sql_mode->无。或从控制台,您可以更改默认值。

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';

太棒了,以他所说的为基础,show variables like '%sql_mode%';在mysql命令行中插入命令,sql_mode设置将暴露出来
Jade Han,


16

转到mysql或phpmyadmin并选择数据库,然后简单地执行此查询即可。它对我来说很好。

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

太好了。:)
mohitesachin217

我的荣幸:) @mohit
Anil Gupta

节省了我很多时间,谢谢。
JoeRaid

1
欢迎兄弟@TharinduEranga
Anil Gupta

1
但是解决方案的问题是每次我重新启动mysql时我都需要再次执行查询。这意味着解决方案不是永久性或持久性的。
Mushfiqur Ra​​hman

10

对于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

3,重启MySQL服务器

mysql.server restart

谢谢,也为我工作。但是我使用Mac的mysql默认值,所以没有酿造路径。只是sudo cp my-default.cnf /etc/my.cnf
Mike Nguyen

2
@Mike Nguyen sudo cp /usr/local/mysql-5.7.17-macos10.12-x86_64/support-files/my-default.cnf /etc/my.cnf sudo vi /etc/my.cnf设置sql_model 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服务器。
高永

7

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

  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列表的表达式#4包含非聚合列'db.gameplay.timestamp';这与sql_mode = only_full_group_by不兼容-查询:SELECT COUNT(*)作为尝试,SUM(elapsed)作为经过,total,userid,timestamp,questionid,answerid,SUM(correct)为正确,经过,ipaddress FROM gameplay WHERE timestamp> = DATE_SUB (现在(),间隔1天)和用户ID = 1

在这种情况下,GROUP BY中缺少表达式#4



解决这个问题的好答案。非常感谢
Hansana Athukorala,

7

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

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

然后重新启动WAMP或Apache


1
我知道这可能不是解决此问题的长期方法,但现在肯定可以解决问题。我的托管公司Go Daddy使用MySQL V5.6.33,而WampServer 3使用MySQL V5.7.14。感谢您提供此快速解决方案
艾伦N

4

您可以添加unique indexgroup_id; 如果您确定那group_id是独一无二的。

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

答案较晚,但尚未在答案中提及。也许它应该完成现有的全面答案。至少当我不得不拆分具有太多字段的表时,它确实解决了我的情况。


2

如果使用doctrine query builder出现Symfony错误,并且此错误是由orderBy引起的

注意select您要的列groupBy,并使用addGroupBy代替groupBy

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

Symfony3工作 -


1

不使用您确切的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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.