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

Error related to only_full_group_by when executing a query in MySql

提问人:Dan Bemowski 提问时间:12/6/2015 最后编辑:Muhammad Dyas YaskurDan Bemowski 更新时间:5/31/2023 访问量:726224

问:

我已经升级了我的系统,并为我正在开发的 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不兼容

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

这是给我带来麻烦的查询:

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_byonly_full_group_by

mysql sql group-by mysql-error-1055

评论

0赞 Wasim A. 1/14/2018
在这里,我找到了解决方案 stackoverflow.com/a/7588442/612987
0赞 Skull Kid 1/16/2021
我很幸运地在我的选择查询前面加上“创建临时表temp”,然后从第二个查询“select * from temp”中获取结果,然后从最后一个查询中清理“如果存在临时,则删除表”。如果这值得任何代表,也许我会得到足够的答案。

答:

407赞 davmos 12/6/2015 #1

我只会添加到.group_idGROUP BY

当 ping 不属于 的列时,组中该列可能有多个值,但结果中只有一个值的空间。因此,通常需要确切地告诉数据库如何将这些多个值转换为一个值。通常,这是通过聚合函数(如 、 等)完成的......我之所以说通常,是因为大多数其他流行的数据库系统都坚持这一点。但是,在 MySQL 5.7 版本之前,默认行为更加宽容,因为它不会抱怨然后任意选择任何值!它还具有一个功能,如果您确实需要与以前相同的行为,则可以用作此问题的另一种解决方案。这种灵活性是有代价的,因为它是不确定的,所以我不推荐它,除非你有很好的理由需要它。MySQL现在默认打开该设置是有充分理由的,因此最好习惯它并使您的查询符合它。SELECTGROUP BYCOUNT()SUM()MAX()ANY_VALUE()only_full_group_by

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

1)是唯一的。看起来很合理,毕竟是“ID”。group_id

2)也是独一无二的。这可能不是一个合理的假设。如果不是这种情况,并且您有一些重复项,然后按照我的建议添加到 中,您可能会发现您现在得到的结果比以前更多,因为具有相同名称的组现在将在结果中具有单独的行。对我来说,这比隐藏这些重复的组要好,因为数据库已经悄悄地任意选择了一个值!group_namegroup_namesgroup_idGROUP 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

评论

2赞 bytor99999 2/23/2018
在MySQL 5.7中,他们设置了一个属性,该属性要求查询中的所有非聚合字段都是GROUP BY。所以像 SELECT a, SUM(b) FROM 表这样的查询;表示字段 “a” 必须位于 GROUP BY 中。因此,如果您没有 GROUP BBY,则必须将其添加到查询中。这完全取决于查询的 SELECT 部分中是否至少有一个聚合字段。
397赞 WeiYuan 3/2/2016 #2

您可以尝试通过执行以下命令来禁用该设置: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

评论

102赞 azerafati 7/12/2016
这是一种解决方法,最好修复查询,而不是静音警告
2赞 Shadoweb 6/8/2018
更新 /etc/mysql/my.cnf(如下所示)是一种更可持续的解决方案,因为默认设置往往会在重新启动后恢复。对于那些说你应该修复查询的人来说,有时当你需要快速调试查询并做一些事情时,这并不容易,你有 20-50 列,你想花那么多时间将每一列添加到组中吗?SELECT COUNT(*), t.* FROM my_table t GROUP BY col
6赞 Chris S. 9/25/2018
这个“解决方案”非常危险。您可以通过盲目更改它们来激活之前禁用的模式,而不是仅删除有问题的设置标志。这可能会导致意外行为,在最坏的情况下会导致错误的结果或完全停止应用运行。因此,我认为这个答案是错误的。
3赞 wbharding 3/2/2019
我通过弄清楚我当前的sql_mode,然后将结果添加到my.cnf,从而通过刷新来持久化这一点:SELECT @@sql_mode;sql_mode=[list of modes from query, minus ONLY_FULL_GROUP_BY]
3赞 golimar 10/27/2020
当所有查询都是在几年前由另一个不再在公司的人完成的时,“修复您的查询”是很困难的;)
184赞 Ajai 7/4/2016 #3

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

  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. 键入以保存并关闭 vim。:wq
  7. 键入以重新启动 MySQL。sudo service mysql restart

评论

1赞 Michael J. Calkins 8/26/2016
请注意所有尝试将其与 AdonisJS 一起使用的 Vagrant 用户,您需要它来运行该函数。paginate
1赞 Valentin Grégoire 10/29/2018
这显然不仅适用于 Vagrant 用户,也适用于任何 Unix 系统。请注意,对我来说,文件的位置是 .Als 注意到新语法,因为my.cnf/etcMySQL 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"
0赞 be3 5/29/2021
[错误][MY-000077][服务器] /usr/bin/mysqld:将值“STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION”设置为“sql_mode”时出错
2赞 Keiron Stoddart 2/19/2022
如果您使用的是 MYSQL 8,请删除NO_AUTO_CREATE_USER。
364赞 azerafati 7/24/2016 #4

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

从MySQL 5.7.5开始,默认的SQL模式包括ONLY_FULL_GROUP_BY这意味着当您对行进行分组,然后从该组中选择某些内容时,您需要明确说明应该从哪一行进行选择。

例如,给定以下记录:

同上 颜色 价值
1 1
2 黄色 4
3 8
4 黄色 9
5 2
6 5
7 3

我们可以要求MySQL按颜色字段进行分组,从而为我们提供以下组:

同上 颜色 价值
2 黄色 4
4 黄色 9
同上 颜色 价值
3 8
6 5
同上 颜色 价值
1 1
5 2
7 3

但是,如果我们要求每个组的值字段,我们会得到一个错误,因为每个组都有很多行带有值字段。

或者,以图像形式:Pictorial representation of the tables above

MySQL需要知道你要查找的组中的哪一行,这给了你三个选项

  • 将所需的列添加到组语句中,在某些情况下,这可能是您想要的,但否则会返回具有相同颜色的重复结果,而您可能不需要group by rect.color, rect.value
  • 使用 MySQL 的聚合函数来指示您在组(如 、 、 或AVG()MIN()MAX()FIRST()
  • 如果确定组内的所有结果都相同,请使用 ANY_VALUE()。

评论

0赞 Felype 8/1/2020
例如,您从 、 和 中进行选择。 and 是 1x1,to 是 1xN;现在,由于您正在选择多个项目,并且每个项目都将是重复的值,如果您分组依据(例如)将销售项目值相加,则必须将所有和字段。salessalesitemscustomerssalescustomerssalessalesitemssalescustomerssalesitemssales.idANY_VALUEsalescustomers
7赞 Avatar 8/14/2016 #5

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

  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 不兼容 - 查询:选择 COUNT(*) 作为尝试次数,SUM(elapsed) 作为 elapsedtotal、userid、timestamp、questionid、answerid、SUM(correct) 作为正确、已用完、ipaddress FROM 游戏玩法 其中时间戳 >= DATE_SUB(NOW(),间隔 1 天) AND 用户 ID = 1

在本例中,GROUP BY 中缺少表达式 #4

43赞 Ryan 8/31/2016 #6

我在 laravel homestead 上使用 Laravel 5.3、mysql 5.7.12(我相信是 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.phptruefalse

    '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

108赞 Italo Borssatto 11/14/2016 #7

使用 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 文档

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

...

启用此查询可能无效,因为选择列表中的非聚合地址列未在子句中命名:ONLY_FULL_GROUP_BYGROUP 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;

评论

3赞 adstwlearn 11/21/2019
作为一个已经遇到这个问题一段时间的人 - 我特别喜欢这个解决方案,因为它不需要您更改MySQL设置中的任何文件或设置。有趣的是,我在类似的讨论中没有看到其他任何地方提到 - 我的错误非常适合我。ANY_VALUE GROUP_BYcontains nonaggregated column
10赞 Tanvir Hasan Anick 11/18/2016 #8

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

评论

0赞 Mike Nguyen 12/12/2016
谢谢,也为我工作。但是我使用 Mac 的 mysql 默认值,所以我没有 brew 路径。只需 sudo cp my-default.cnf /etc/my.cnf
2赞 Yong Gao 12/30/2016
@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 set 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赞 Braham Dev Yadav 1/15/2017 #9

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

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

然后重新启动 Wamp 或 Apache

1赞 Harry Bosh 3/2/2017 #10

很抱歉没有使用您的确切 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
20赞 PiyaChakraborty 3/21/2017 #11

如果您使用的是 wamp 3.0.6 或稳定版 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';

评论

0赞 Jade Han 5/31/2018
太棒了,在他所说的基础上,在MySQL命令行中插入命令,sql_mode设置将暴露show variables like '%sql_mode%';
61赞 Abraham Tugalov 4/30/2017 #12

我将尝试向您解释此错误是关于什么的。
从 MySQL 5.7.5 开始,选项默认启用。
因此,根据标准 SQL92 及更早版本:
ONLY_FULL_GROUP_BY

不允许选择列表、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并不完全理解,从分组记录中检索哪些某些值,这就是重点。

即假设您的表中有以下记录:users
Yo

您将执行上面显示的无效查询。
你会得到上面显示的错误,因为,有 3 条带有名称的记录,这很好,但是,它们都有不同的字段值。
因此,MySQL根本不了解在生成的分组记录中返回哪些内容。
Johnemail

只需按如下方式更改查询即可解决此问题:

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

此外,您可能希望向 SELECT 部分添加更多字段,但如果它们未聚合,则无法这样做,但您可以使用拐杖(但强烈建议):

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

enter image description here

现在,你可能会问,为什么强烈不建议使用?
因为MySQL并不完全知道要检索的分组记录的值,并且通过使用此函数,您要求它获取其中的任何一条(在本例中,获取了名称为= John的第一条记录的电子邮件)。
确切地说,我想不出任何关于你为什么希望这种行为存在的想法。

拜托,如果你不理解我,请阅读更多关于MySQL中的分组是如何工作的,它非常简单。
ANY_VALUE

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

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

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

重要的是要了解问题到底是什么,然后才能写下解决方案。

18赞 Jagdeep Singh 6/20/2017 #13

在文件中添加行(如下所述):/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)

评论

1赞 Mubasshir Pawle 7/17/2017
您使用的是 RDS 吗?
0赞 Jagdeep Singh 7/20/2017
@MubasshirPawle否
3赞 Gangai Johann 8/9/2017 #14

如果您在使用 doctrine 查询生成器Symfony 中遇到此错误,并且此错误是由 orderBy 引起的:

注意你想要的列,并使用代替:selectgroupByaddGroupBygroupBy

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

Symfony3 上工作 -

4赞 Mike Casan Ballester 9/11/2017 #15

您可以将 a 添加到 ;如果您确定这是独一无二的。unique indexgroup_idgroup_id

它可以在不修改查询的情况下解决您的情况

一个迟到的答案,但答案中还没有提到。也许它应该完成已经全面的答案。至少当我不得不拆分一个包含太多字段的表时,它确实解决了我的情况。

评论

0赞 yoni 7/22/2020
只有当您的数据在该组 ID 中实际上是唯一的时,这才是好的
30赞 Anil Gupta 10/11/2019 #16

转到 mysql 或 phpmyadmin 并选择数据库 然后只需执行此查询,它就会起作用。 它对我来说工作得很好。

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

评论

1赞 devnull Ψ 12/12/2019
如果您提供一些解释它的作用,那就太好了
0赞 Anil Gupta 12/13/2019
@devnull Ψ 它实际上从变量中删除了“ONLY_FULL_GROUP_BY”,您可以在 phpmyadmin 中找到它>变量菜单> sql_mode选项您可以直接在此处删除
1赞 Mushfiqur Rahman 1/25/2020
但是解决方案的问题是每次重新启动mysql时,我都需要再次执行查询。这意味着解决方案不是永久性的或持久的。
3赞 Kiran Sone 7/4/2020 #17

我不得不在我的 Ubuntu 18.04 上编辑以下文件:

/etc/mysql/mysql.conf.d/mysqld.cnf

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

sudo service mysql restart

1赞 RayCh 8/11/2020 #18

上面的共识答案很好,但如果在修复 my.cnf 文件后在存储过程中运行查询时遇到问题,请尝试再次加载 SP。

我怀疑 MySQL 一定是用最初设置的默认only_full_group_by编译了 SP。因此,即使我更改了 my.cnf 并重新启动了 mysqld,它对 SP 也没有影响,并且它们一直失败,并显示“SELECT 列表不在 GROUP BY 子句中并且包含非聚合列......在功能上不依赖于 GROUP BY 子句中的列;这与 sql_mode=only_full_group_by“不兼容。

重新加载 SP 必须导致它们现在被重新编译并禁用only_full_group_by。在那之后,它们似乎按预期工作。