#1055 - SELECT列表中的表达式不在GROUP BY子句中,且包含非聚合列,这与sql_mode=only_full_group_by不兼容。

76

我的查询:

select libelle,credit_initial,disponible_v,sum(montant) as montant 
FROM fiche,annee,type where type.id_type=annee.id_type and annee.id_annee=fiche.id_annee 
and annee = year(current_timestamp) GROUP BY libelle order by libelle asc
  • Mysql 5.7.9可以正常运行查询,但Mysql 5.7.12显示了上述错误,请帮忙解决。

2
它期望你在group by语句中包含libelle、credit_initila和disponible_v。 - Marshall Tigerus
1
http://mechanics.flite.com/blog/2013/02/12/why-i-use-only-full-group-by/ - bishop
3
可能是一个重复的问题,与执行查询时出现的only_full_group_by相关的MySql错误。参考链接 - gr1zzly be4r
1
问题在于 MySQL 本身,而不是查询。 - Miloud BAKTETE
14个回答

111

我曾经遇到困难,使这个工作进行了测试,并在lamp服务器mysql版本5.12上运行。

因此,成功的步骤如下:

  1. sudo vim /etc/mysql/conf.d/mysql.cnf
  2. 滚动到文件底部并复制和粘贴

    [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

到文件底部

  1. 保存并退出输入模式
  2. sudo service mysql restart 重新启动MySQL。

完成!


6
我通过从Ubuntu 16.04(MySQL 5.7)的/etc/mysql/my.cnf文件中的sql_mode=字符串中仅删除STRICT_TRANS_TABLES并重新启动mysql:systemctl restart mysql来解决了相同的问题。 - Grant
3
对于那些找不到这个文件的人,我的文件名叫做my.ini,与mysql.cnf相同。 - Radmation
6
这里的文档提供了一些信息: https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html如果要避免编辑mysql.cnf文件(或像gr1zzly be4r和scaisEdge建议的那样修复SQL语句),还有一个不那么剧烈的解决办法: https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_any-value - keithpjolley
5
不要像我一样混淆[mysqld][mysql]。请注意它们的区别。 - Henry
3
答案错误,正确答案是修复查询。 - Salman A
显示剩余6条评论

70

这对我起了作用:

mysql -u root -p
mysql > SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

对于第一步,您可能需要sudo权限:

sudo mysql -u root -p

3
最后这也是对我有效的唯一方法。 - Xoundboy
1
我开始认为这个解决方案只能在mysql重新启动之前持续存在。被接受的方案更好。 - Henry
3
Henry,这种方法的优点在于可以有选择性地应用。如果您修改 my.cnf,服务器上的每个应用程序和数据库都会受到影响。但是,如果该应用程序/帐户具备 SET GLOBAL 特权(并非保证但可实现),则可以在其他查询运行之前,从应用程序中的 DB 准备阶段运行此查询。这已经拯救了我一个老旧遗留应用程序的生命,该应用程序违反了 FULL_ORDER_GROUP_BY 规则... 我只需在 DB 连接初始化后立即调用它... - Kevin_Kinsey
1
如果重新启动MySQL,则问题将再次出现。因此,这不是一个永久性的解决方法。 - Abdur Rehman
1
我使用UniserverZero,打开控制台并输入该代码,现在正常工作,谢谢。 - matasoy
1
请先使用SUDO命令:sudo mysql -u root -p - Shehan Hasintha

33

你需要在GROUP BY子句中指定所有没有使用聚合函数的列,就像这样:

select libelle,credit_initial,disponible_v,sum(montant) as montant 
FROM fiche,annee,type where type.id_type=annee.id_type and annee.id_annee=fiche.id_annee 
and annee = year(current_timestamp) GROUP BY libelle,credit_initial,disponible_v order by libelle asc
full_group_by模式基本上使您编写更符合惯用法的SQL。如果您愿意,可以关闭此设置。有不同的方法可以做到这一点,在MySQL文档中有详细说明。以下是MySQL对我上面所说的内容的定义:
MySQL 5.7.5及以上版本实现了功能依赖检测。如果启用了ONLY_FULL_GROUP_BY SQL模式(默认启用),MySQL将拒绝那些选择列表、HAVING条件或ORDER BY列表引用既不在GROUP BY子句中命名也不与之功能依赖的非聚合列的查询。(在5.7.5之前,MySQL不会检测功能依赖关系,并且ONLY_FULL_GROUP_BY默认未启用。有关pre-5.7.5行为的描述,请参见MySQL 5.6参考手册。)
您之所以收到错误是因为您使用的版本小于5.7.5。

1
我正在使用Ubuntu MySQL 5.7.12,是否有其他选项可用?因为我还有其他查询需要,我需要知道如何仅打开完整的GROUP BY。 - Miloud BAKTETE
5
如果您正在编写数据库逻辑,这是一种实际的解决方案,因为它可以使您的代码更加精确,并减少输出中的许多不确定性。 - Mohd Abdul Mujib

24

您可以通过一些命令来禁用sql_mode=only_full_group_by,您可以尝试使用终端或MySql IDE

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';

我尝试过这个方法,对我有效。 谢谢 :)


3
如果重新启动MySQL,则问题将再次出现,因此这并不是一个永久性的解决方案。 - Abdur Rehman
你可以将这个语句添加到你的 my.cnf 文件中,以使设置更改永久生效。 - Keiron Stoddart

20

解决方案1:从mysql控制台中移除ONLY_FULL_GROUP_BY

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

你可以在这里阅读更多

解决方法2:从phpmyadmin中移除ONLY_FULL_GROUP_BY

Open phpmyadmin & select localhost
Click on menu Variables & scroll down for sql mode
Click on edit button to change the values & remove ONLY_FULL_GROUP_BY & click on save. 

点击这里查看图片


1
嗨Tauqueer,請將mysql行格式化為代碼。同時,您還缺少指向其他閱讀材料的鏈接。 - hakamairi
3
如果重新启动MySQL,问题将再次出现。因此,这不是一个永久性的解决方法。 - Abdur Rehman
解决方案无法工作。 - Kamlesh

8

您必须在group by子句中聚合任何NOT IN的内容。

所以,有两个选项......将Credit_InitialDisponible_v添加到group by中。

或者

如果您知道这些值是恒定的且没有其他影响,请更改它们为MAX(Credit_Initial)作为Credit_Initial,MAX(Disponible_v)作为Disponible_v


1
这是正确的方法。给最大值分配一个名称是做到这一点的方法,感谢6年后。 - bonjonbovi

8

因此让我们充分了解一下。假设您有一个在本地主机上运行但在生产模式中不起作用的查询,这是因为在MySQL 5.7及以上版本中,默认启用 sql_mode=only_full_group_by ,它基本上是一种严格模式,防止您选择非聚合字段。

以下是查询(在本地工作但在生产模式中无效):

SELECT post.*, YEAR(created_at) as year
FROM post
GROUP BY year

SELECT post.id, YEAR(created_at) as year  // This will generate an error since there are many ids
FROM post
GROUP BY year

要验证是否启用了sql_mode=only_full_group_by,您应执行以下查询:

SELECT @@sql_mode;   //localhost

输出IGNORE_SPACE、STRICT_TRANS、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER、NO_ENGINE_SUBSTITUTION (如果您看不到它,这意味着它被禁用了)

但是如果在生产模式下尝试,或者在某个地方出现应该激活错误的情况:

SELECT @@sql_mode;   //production

输出: ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO... 我们需要关注的是 ONLY_FULL_GROUP_BY

否则,如果您正在使用phpMyAdmin,可以进入- > Variables 并搜索 sql_mode

让我们将之前的示例适应一下:

SELECT MIN(post.id), YEAR(created_at) as year  //Here we are solving the problem with MIN()
FROM post
GROUP BY year

同样适用于MAX()

如果我们想要所有的ID,我们需要:

SELECT GROUP_CONCAT(post.id SEPARATOR ','), YEAR(created_at) as year
FROM post
GROUP BY year

或另一个新添加的功能:

SELECT ANY_VALUE(post.id), YEAR(created_at) as year 
FROM post
GROUP BY year

⚠️ MariaDB 中不存在 ANY_VALUE。

如果你想获取所有字段,你可以使用相同的方法:

SELECT ANY_VALUE(post.id), ANY_VALUE(post.slug), ANY_VALUE(post.content) YEAR(created_at) as year 
FROM post
GROUP BY year

❌ 要关闭sql_mode=only_full_group_by,您需要执行以下查询:

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

抱歉篇幅有点长,希望能对您有所帮助。


7

基于5.7.5版本的默认配置ONLY_FULL_GROUP_BY,您应该在group by语句中使用所有非聚合列。

select libelle,credit_initial,disponible_v,sum(montant) as montant 
FROM fiche,annee,type 
where type.id_type=annee.id_type 
and annee.id_annee=fiche.id_annee 
and annee = year(current_timestamp) 
GROUP BY libelle,credit_initial,disponible_v order by libelle asc

1
如果您按某个ID(指向另一个表的索引)进行计数,那么为什么需要在GROUP BY中添加与计数无关的其他列,特别是如果您不想按这些列分组呢?但这样做毫无意义。 - Phil
1
@fdsfdsfdsfds 这就是该条款强制你做的事情。ONLY_FULL_GROUP_BY要求所有不受聚合函数管理的列都必须在GROUP BY中声明。虽然OP提供的解决方案更改了ONLY_FULL_GROUP_BY sql_mode,但这并不是正确的SQL语法(即使默认情况下MySQL允许使用5.7)。 - ScaisEdge

4
在Laravel中,您只需在database.php文件中设置false即可。
...
'mysql' => [
    ...
    'strict' => false,
    ...
]

4
如果您使用的是MySql 8+,请在控制台中尝试以下命令:
打开MySql控制台
mysql -u user_name -p

设置全局SQL模式

SET GLOBAL sql_mode='STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_ENGINE_SUBSTITUTION';

完美的回答!!!+1 让我开心了 :) - SagarPPanchal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接