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

时间:2015-12-06 07:42:08

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

我已经升级了我的系统并安装了MySql 5.7.9和php,用于我正在处理的Web应用程序。我有一个动态创建的查询,当在旧版本的MySql中运行时,它可以正常工作。自升级到5.7后,我收到此错误:

  

SELECT列表的表达式#1不在GROUP BY子句中并且包含   nonaggregated列'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选项,还是还有其他我需要做的事情?

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

18 个答案:

答案 0 :(得分:293)

您可以尝试通过执行以下操作来禁用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,因此需要删除。

答案 1 :(得分:286)

我只想将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_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

答案 2 :(得分:278)

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

As of MySQL 5.7.5, the default SQL mode includes ONLY_FULL_GROUP_BY这意味着当您对行进行分组然后从这些组中选择某些内容时,您需要明确说明应该从哪个行进行选择。 Mysql needs to know which row in the group you're looking for, which gives you two options

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

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

答案 3 :(得分:153)

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

  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。

答案 4 :(得分:46)

使用ANY_VALUE()来引用非聚合列。

来自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;

答案 5 :(得分:41)

我会试着解释一下这个错误是什么 从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不完全理解,从分组记录中检索哪些特定值,这就是重点。

即。假设你在users表中有这些记录:
Yo

您将在上面执行无效查询showen 并且您将收到上面显示的错误,因为有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`

enter image description here

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

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

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

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

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

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

答案 6 :(得分:35)

我在Laravel宅基地上使用Laravel 5.3,mysql 5.7.12(我相信0.5.0)

即使明确设置编辑storage/public以反映:

com/google/guava

我仍然收到错误。

我必须将/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

true

进一步阅读:

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

答案 7 :(得分:18)

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

答案 8 :(得分: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)

答案 9 :(得分:9)

对于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.Restart MySQL服务器。

mysql.server restart

答案 10 :(得分:6)

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

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

然后重启wamp或apache

答案 11 :(得分:6)

转到mysql或phpmyadmin并选择数据库 然后只需执行此查询即可。 对我来说很好。

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

答案 12 :(得分:4)

这有助于我理解整个问题:

  1. https://stackoverflow.com/a/20074634/1066234
  2. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
  3. 以下是另一个有问题的查询示例。

    <强>有问题的:

    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(已用)为elapsedtotal,userid,timestamp,questionid,answerid,SUM(正确)为正确,已过去,ipaddress FROM gameplay                               时间戳&gt; = DATE_SUB(NOW(),INTERVAL 1天)                               AND userid = 1

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

答案 13 :(得分:2)

如果您使用 doctrine查询构建器 Symfony 发生此错误,并且此错误是由 orderBy 引起的:

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

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

适用于 Symfony3 -

答案 14 :(得分:2)

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

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

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

答案 15 :(得分: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。之后,它们似乎按预期工作。

答案 16 :(得分:0)

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

答案 17 :(得分:0)

不使用您的确切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