490

我已经升级了我的系统,并为我正在开发的 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选项,还是我需要做其他事情?

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

4

18 回答 18

395

我只想添加group_idGROUP BY.

SELECTing 一个不属于的GROUP BY列时,组中的该列可能有多个值,但结果中只有一个值的空间。因此,通常需要准确地告诉数据库如何将这些多个值变成一个值。通常,这是通过聚合函数来完成的,例如,COUNT()等。我之所以这么说,因为大多数其他流行的数据库系统都坚持这一点。然而,在 MySQL 5.7 之前的版本中,默认行为更加宽容,因为它不会抱怨然后任意选择任何值!它还有一个SUM()MAX()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
于 2015-12-06T08:19:41.273 回答
388

您可以尝试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,因此需要删除。

于 2016-03-01T17:40:29.293 回答
356

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

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

Mysql 需要知道您要查找的组中的哪一行,这为您提供了两种选择

  • 您还可以将您想要的列添加到 group 语句group by rect.color, rect.value中,这在某些情况下可能是您想要的,否则会返回您可能不想要的具有相同颜色的重复结果
  • 您还可以使用mysql 的聚合函数来指示您在组中查找的行,例如AVG() MIN() MAX() 完整列表
  • 最后,ANY_VALUE()如果您确定组内的所有结果都相同,则可以使用。文档
于 2016-07-24T11:27:39.157 回答
181

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

  1. vagrant 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。
于 2016-07-04T08:23:24.147 回答
96

用于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_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;
于 2016-11-13T21:11:17.360 回答
58

我将尝试向您解释此错误的含义。
从 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 子句中,并且包含在功能上不依赖于 GROUP BY 子句中的列的非聚合列“testsite.user.id”;这与 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 并不确切知道要检索的分组记录的值,并且通过使用此函数,您要求它获取其中任何一个(在这种情况下,获取了 name = John 的第一条记录的电子邮件)。
确切地说,我想不出任何关于您为什么希望这种行为存在的想法。

如果你不明白我的意思,请阅读更多关于 MySQL 中的分组是如何工作的,这很简单。

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

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

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

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

于 2017-04-29T19:03:23.843 回答
43

我在 laravel 宅基地上使用 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.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

于 2016-08-31T14:09:11.123 回答
27

转到 mysql 或 phpmyadmin 并选择数据库,然后只需执行此查询即可。它对我来说工作正常。

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
于 2019-10-11T10:44:48.807 回答
20

如果您使用的是 wamp 3.0.6 或除稳定版 2.5 之外的任何更高版本,您可能会遇到此问题,首先问题出在 sql 上。您必须相应地命名字段。但是还有另一种方法可以解决它。点击 wamp 的绿色图标。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';
于 2017-03-21T14:15:57.190 回答
19

在文件中添加行(下面提到):/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)

于 2017-06-20T10:34:35.547 回答
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
于 2016-11-17T16:43:03.697 回答
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(*) as尝试,SUM(elapsed) as elapsedtotal,userid,timestamp,questionid,answerid,SUM(correct) as correct,elapsed,ipaddress FROM games WHERE timestamp >= DATE_SUB (现在(),间隔 1 天)和用户 ID = 1

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

于 2016-08-14T05:35:10.330 回答
7

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

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

然后重新启动 wamp 或 apache

于 2017-01-14T17:47:08.873 回答
4

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

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

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

于 2017-09-10T16:07:10.773 回答
3

我必须在我的 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

于 2020-07-04T12:39:03.340 回答
2

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

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

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

适用于Symfony3 -

于 2017-08-09T12:30:50.340 回答
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
于 2017-03-02T03:03:42.493 回答
0

上面的共识答案很好,但如果您在修复 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 禁用的情况下重新编译。之后,它们似乎按预期工作。

于 2020-08-11T14:42:05.260 回答