【问题标题】:Error related to only_full_group_by when executing a query in MySql在 MySql 中执行查询时与 only_full_group_by 相关的错误
【发布时间】:2016-03-10 23:16:35
【问题描述】:

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

请注意有关 Server SQL Modes 主题的 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
  • 这一定是我遇到过的最复杂的错误信息。
  • @Rolf 您是否在 Oracle 中看到过相同类型问题的错误? “not a GROUP BY expression”就是这样。他们可能只是有一个数字错误代码而根本没有消息。
  • 我很幸运在我的选择查询前面加上“创建临时表 temp”,然后从第二个查询“select * from temp”得到结果,然后最后一个查询清理“drop table if exists temp” ”。如果这值得任何代表,也许我会得到足够的答案。

标签: mysql sql group-by mysql-error-1055


【解决方案1】:

我只想将group_id 添加到GROUP BY

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

【讨论】:

  • 谢谢,完美。我也同意我需要限定列。它消除了任何歧义的可能性。我现在正在修复代码。感谢一百万的帮助。
  • 我的查询中什至没有GROUP BY 子句,但我收到了这个错误。
  • @HaroonKhan,这听起来像是一个新问题。如果你问,请告诉我,我会看看。
  • 在 MySQL 5.7 中,他们设置了一个属性,要求查询中的所有非聚合字段都是 GROUP BY。所以像 SELECT a, SUM(b) FROM table 这样的查询;表示字段“a”必须在 GROUP BY 中。因此,如果您没有 GROUP BY,则必须将其添加到查询中。如果您在查询的 SELECT 部分中至少有一个聚合字段,这就是全部。
  • 我必须按照此答案中的建议通过将项目添加到 group by 子句来修复“警告”,因为没有一个建议 sql_mode 修复的答案有效。 (我的 MySQL 在一个存储过程中,但不知道这是否相关)
【解决方案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,因此需要将其删除。

【讨论】:

  • 这是一种变通方法,您最好修复查询而不是消除警告
  • 更新 /etc/mysql/my.cnf(如下所示)是一种更可持续的解决方案,因为默认设置往往会在重启后恢复。对于那些说您应该修复查询的人,有时当您需要快速调试查询并执行SELECT COUNT(*), t.* FROM my_table t GROUP BY col 之类的操作并且您有 20-50 列时,这并不容易,您想花那么多时间添加每个列分组依据?
  • 这个“解决方案”相当危险。您可以通过盲目更改它们而不是仅删除有问题的一个设置标志来激活先前禁用的模式。这可能会导致意外行为,在最坏的情况下会导致错误的结果或完全停止您的应用程序运行。因此我认为这个答案是错误的。
  • 我通过刷新通过SELECT @@sql_mode; 找出我当前的sql_mode,然后将结果从那里添加到my.cnf:sql_mode=[list of modes from query, minus ONLY_FULL_GROUP_BY]
  • “修复您的查询”很困难,因为所有查询都是几年前由不在公司的另一个人完成的;)
【解决方案3】:

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

  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。

【讨论】:

  • 提醒所有尝试将它与 AdonisJS 一起使用的 Vagrant 用户,您需要它来运行 paginate 函数。
  • 这显然不仅适用于 Vagrant 用户,也适用于任何 Unix 系统。请注意,对我来说,my.cnf 文件的位置是/etc。另请注意 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" 之后的新语法
  • [ERROR] [MY-000077] [Server] /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' 时出错
【解决方案4】:

您可以按照其他答案中的说明关闭警告消息,或者您可以了解发生了什么并修复它。

As of MySQL 5.7.5, the default SQL mode includes ONLY_FULL_GROUP_BY 这意味着当您对行进行分组然后从这些组中选择某些内容时,您需要明确说明应该从哪一行进行选择

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

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

【讨论】:

  • 我不认为 MySQL 支持 FIRST() 方法/函数?
  • 我相信 MySQL(至少在 5.7 之前)默认采用它在组中找到的第一个值。因此,没有 FIRST(),因为它曾经是 GROUP BY 函数本身的同义词。
  • @DrDamnit,我相信在这种情况下它更像是随机选择,导致混淆,因此默认启用ONLY_FULL_GROUP_BY
  • 我已经知道答案了,但是彩色矩形的例子很容易理解,下次有人问我时我会重复使用它。
  • @azerafati 是否有类似 FIRST() 或一些可用于获取第一个值的查询,就像我的情况一样。
【解决方案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 不兼容 - 查询:SELECT COUNT(*) 作为尝试,SUM(elapsed) 作为 elapsedtotal,userid,timestamp,questionid,answerid,SUM(correct) 作为正确,elapsed,ipaddress FROM 游戏 WHERE 时间戳 >= DATE_SUB(NOW(), INTERVAL 1 DAY) AND 用户 ID = 1

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

【讨论】:

【解决方案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.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

【讨论】:

  • 该死!这对 Laravel 用户很有帮助。为此 +1。
【解决方案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 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;

【讨论】:

  • 作为一个已经遇到这个问题一段时间的人 - 我特别喜欢这个解决方案,因为它不需要您更改 MySQL 设置中的任何文件或设置。有趣的是,在类似的讨论中,我没有看到任何其他地方提到过ANY_VALUE - 对我来说非常适合我的GROUP_BY contains nonaggregated column 错误。
  • 很好的解决方案,比 set 'sql_mode' 更有价值
  • 很棒的解决方案。这项工作无需对配置进行任何更改
【解决方案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

【讨论】:

  • 谢谢,也为我工作。但是我使用的是 Mac 的 mysql 默认值,所以我没有 brew 路径。只需 sudo cp my-default.cnf /etc/my.cnf
  • @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 服务器。
【解决方案9】:

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

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

然后重启 wamp 或 apache

【讨论】:

  • 我知道这可能不是这个问题的长期解决方案,但它现在肯定有所帮助。我的托管公司 Go Daddy 使用 MySQL V5.6.33,而 WampServer 3 使用 MySQL V5.7.14。感谢您提供此快速修复解决方案
【解决方案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

【讨论】:

    【解决方案11】:

    如果您使用的是 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';
    

    【讨论】:

    • 太棒了,在他所说的基础上,在mysql命令行中插入命令show variables like '%sql_mode%';,sql_mode设置会暴露
    【解决方案12】:

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

    不允许查询包含选择列表、HAVING 条件、 或 ORDER BY 列表指的是未命名的非聚合列 在 GROUP BY 子句中也不在功能上依赖于(唯一 由) GROUP BY 列确定

    (read more in docs)

    所以,例如:

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

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

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

    为什么?
    因为 MySQL 不完全理解,从分组记录中检索哪些特定值,这就是重点。

    I.E.假设您的 users 表中有这些记录:

    您将执行上面显示的无效查询。
    你会得到上面显示的错误,因为有 3 条记录的名称为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 规则,这是完全有效的。
    等等。

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

    【讨论】:

    • 感谢您的回答。如果我也想要电子邮件,作为结果组中的数组怎么办?
    • 您始终可以使用 GROUP_CONCAT 必填字段来获取每个条目。
    • 哦!所以有办法!请帮帮我in this question
    • 感谢您的出色回答。如果我想做GROUP BY DAY(created_date)怎么办?加了DAY()好像不行。
    【解决方案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)

    【讨论】:

    • 你在使用 RDS 吗?
    • @MubasshirPawle No
    【解决方案14】:

    如果您在使用 doctrine query builderSymfony 中遇到此错误,并且如果此错误是由 orderBy 引起的:

    注意select你要groupBy的栏目,用addGroupBy代替groupBy

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

    适用于 Symfony3 -

    【讨论】:

      【解决方案15】:

      您可以将unique index 添加到group_id;如果您确定 group_id 是唯一的。

      无需修改查询即可解决您的情况

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

      【讨论】:

      • 只有当您的数据在该组 id 上实际上是唯一的时候才会这样做
      【解决方案16】:

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

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

      【讨论】:

      • 太好了..谢谢:)
      • 我的荣幸 :) @mohit
      • 如果你能提供一些解释它的作用会很好
      • 欢迎兄弟@TharinduEranga
      • 但是解决方案的问题是每次重启mysql都需要再次执行查询。这意味着解决方案不是永久的或持久的。
      【解决方案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

      【讨论】:

      • 为我工作。非常感谢。
      • 我在使用 pgloader 时遇到了这个错误,所以修改 SQL 请求不是一个选项,这很好用,谢谢!
      【解决方案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 禁用的情况下重新编译。之后,它们似乎按预期工作。

      【讨论】:

        猜你喜欢
        • 2018-01-25
        • 2017-02-26
        • 2019-09-21
        • 2018-06-18
        • 2020-10-22
        • 2017-07-11
        • 2020-02-29
        相关资源
        最近更新 更多