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

Dan*_*ski 394 mysql sql group-by mysql-error-1055

我已经升级了我的系统,并为我正在处理的Web应用程序安装了MySql 5.7.9和php.我有一个动态创建的查询,当在旧版本的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
Run Code Online (Sandbox Code Playgroud)

我在这个问题上做了一些谷歌搜索,但我不明白only_full_group_by弄清楚我需要做些什么来修复查询.我可以关掉这个only_full_group_by选项,还是我需要做些什么呢?

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

Wei*_*uan 332

您可以尝试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';
Run Code Online (Sandbox Code Playgroud)

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

  • 这是一种解决方法,您最好修复查询而不是静音警告 (77认同)
  • 这种"解决方案"非常危险.您可以通过盲目更改它们而不是仅删除有问题的一个设置标志来激活先前已禁用的模式.这可能会导致意外行为,并且在最坏的情况下会导致错误的结果或阻止您的应用完全正常工作.因此我认为这个答案是错误的. (3认同)
  • 我通过`SELECT @@sql_mode;`找出我当前的sql_mode,然后将结果添加到my.cnf:`sql_mode=[来自查询的模式列表,减去ONLY_FULL_GROUP_BY]` (3认同)
  • 当所有查询都是几年前由不再在公司工作的另一个人完成时,“修复您的查询”很困难;) (3认同)
  • 更新 /etc/mysql/my.cnf(如下所示)是一个更可持续的解决方案,因为默认设置往往会在重启后恢复。对于那些说你应该修复查询的人,那么有时当你需要一个快速调试查询并执行诸如“SELECT COUNT(*), t.* FROM my_table t GROUP BY col”之类的事情时,这并不容易,而你有 20 -50 列,您想花那么多时间将每一列添加到 group by 中吗? (2认同)

dav*_*mos 323

我只想补充group_id一下GROUP 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_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
Run Code Online (Sandbox Code Playgroud)

  • 在MySQL 5.7中,他们设置了一个属性,该属性要求查询中的所有非聚合字段都是GROUP BY.所以像SELECT a,SUM(b)FROM table这样的查询; 表示字段"a"必须位于GROUP BY中.因此,如果您没有GROUP BY,则必须将其添加到查询中.如果您在查询的SELECT部分​​中至少有一个聚合字段,那就是关键. (2认同)

aze*_*ati 305

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

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

Mysql需要知道您正在寻找的组中的哪一行,这为您提供了两个选项

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

  • 我不认为MySQL支持`FIRST()`方法/函数? (24认同)
  • 我已经知道了答案,但是带有彩色矩形的例子很容易理解,下次有人问我时我会重复使用它. (5认同)
  • 我相信MySQL(至少在5.7之前)默认采用它在组中找到的第一个值.因此,没有FIRST()因为它曾经是GROUP BY函数本身的同义词. (3认同)
  • @DrDamnit,我相信在这种情况下更像是随机选择,这会导致混乱,因此默认情况下启用“ ONLY_FULL_GROUP_BY” (2认同)

Aja*_*jai 166

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

  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
    
    Run Code Online (Sandbox Code Playgroud)
  5. 键入esc退出输入模式

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

  • 如果您使用的是 MYSQL 8,请删除 NO_AUTO_CREATE_USER。 (2认同)

Ita*_*tto 55

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

来自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; -- fails
SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name; -- works
Run Code Online (Sandbox Code Playgroud)

...

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

SELECT name, address, MAX(age) FROM t GROUP BY name;
Run Code Online (Sandbox Code Playgroud)

  • 作为已经遇到这个问题一段时间的人 - 我特别喜欢这个解决方案,因为它不需要您更改 MySQL 设置中的任何文件或设置。有趣的是,我没有看到类似讨论中其他任何地方提到的“ANY_VALUE”——对于我的“GROUP_BY”“包含非聚合列”错误非常适合。 (2认同)

Abr*_*lov 45

我会试着解释一下这个错误是什么.
从MySQL 5.7.5开始ONLY_FULL_GROUP_BY,默认情况下启用选项.
因此,根据标准SQL92和更早版本:

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

(在文档中阅读更多内容)

所以,例如:

SELECT * FROM `users` GROUP BY `name`;
Run Code Online (Sandbox Code Playgroud)

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

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

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

IE可以说你的users表中有这些记录:
哟

并且您将执行上面的无效查询showen.
并且您将得到上面显示的错误,因为,有3个记录具有名称John,并且它很好,但是,它们都具有不同的email字段值.
因此,MySQL根本不了解它们中的哪一个返回到结果分组记录中.

您可以通过简单地更改您的查询来解决此问题:

SELECT `name` FROM `users` GROUP BY `name`
Run Code Online (Sandbox Code Playgroud)

此外,您可能希望向SELECT部分​​添加更多字段,但是如果它们没有聚合,您可能无法这样做,但是您可以使用拐点(但非常不推荐):

SELECT ANY_VALUE(`id`), ANY_VALUE(`email`), `name` FROM `users` GROUP BY `name`
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在,你可能会问,为什么使用ANY_VALUE高度不推荐?
因为MySQL并不确切知道要检索的分组记录的值,并且通过使用此函数,您要求它获取它们中的任何一个(在这种情况下,获取名称= John的第一条记录的电子邮件).
究竟我无法想出为什么你希望这种行为存在的想法.

如果你不理解我,请阅读更多关于如何在MySQL中进行分组的工作,这很简单.

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

SELECT `age`, COUNT(`age`) FROM `users` GROUP BY `age`;
Run Code Online (Sandbox Code Playgroud)

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

重要的是要了解问题到底是什么,然后记下解决方案.


Rya*_*yan 39

我在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
Run Code Online (Sandbox Code Playgroud)

我还是收到了错误.

我不得不改变config/database.php来自truefalse:

    'mysql' => [
        'strict' => false, //behave like 5.6
        //'strict' => true //behave like 5.7
    ], 
Run Code Online (Sandbox Code Playgroud)

进一步阅读:

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


Ani*_*pta 23

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

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
Run Code Online (Sandbox Code Playgroud)


小智 18

如果您正在使用wamp 3.0.6或除稳定版2.5之外的任何高级版本,您可能会遇到此问题,首先问题是sql.你必须相应地命名字段.但还有另一种方法可以解决它.点击wamp的绿色图标.mysql-> mysql settings-> 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';
Run Code Online (Sandbox Code Playgroud)


Jag*_*ngh 16

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

对我来说很好.服务器版本:5.7.18-0ubuntu0.16.04.1 - (Ubuntu)


小智 9

对于mac:

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

sudo cp $(brew --prefix mysql)/support-files/my-default.cnf /etc/my.cnf
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

3.Restart MySQL服务器.

mysql.server restart
Run Code Online (Sandbox Code Playgroud)

  • @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服务器. (2认同)

Kai*_*ack 6

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

  1. /sf/answers/1405224411/
  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 = #
Run Code Online (Sandbox Code Playgroud)

通过将其添加到末尾来解决:

  GROUP BY timestamp, userid, cookieid, questionid, answerid, elapsed, ipaddress
Run Code Online (Sandbox Code Playgroud)

注意:请参阅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(正确)为正确,经过,ipaddress from gameWhere时间戳> = DATE_SUB (现在(),间隔1天)和用户ID = 1

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


Bra*_*dav 6

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

click on wamp icon -> MySql -> MySql Setting -> sql-mode -> user_mode
Run Code Online (Sandbox Code Playgroud)

然后重启wamp或apache