在MySql中执行查询时与only_full_group_by相关的错误
我已经升级了我的系统,并安装了MySql 5.7.9与我的工作的Web应用程序的PHP。 我有一个dynamic创build的查询,并在较旧版本的MySql中运行时,它工作正常。 由于升级到5.7我得到这个错误:
SELECT列表的expression式#1不在GROUP BY子句中,并且包含非聚集列'support_desk.mod_users_groups.group_id',它在function上不依赖于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
我在这个问题上做了一些search,但我不明白only_full_group_by
足以找出我需要做什么来修复查询。 我可以closuresonly_full_group_by
选项only_full_group_by
,还是还有其他的我需要做的?
让我知道如果你需要更多的信息。
我只是将group_id
添加到GROUP BY
。
当SELECT
一个不属于GROUP BY
组成部分的列时,组内的该列可能会有多个值,但结果中只有一个空间可用于单个值。 所以, 通常需要告诉数据库如何将这些多个值合并为一个值。 通常,这是用像COUNT()
, SUM()
, MAX()
等集合函数完成的…我通常说,因为大多数其他stream行的数据库系统坚持这一点。 但是,在5.7之前的MySQL中,默认行为更加宽容,因为它不会抱怨,然后随意select任何值 ! 它还有一个ANY_VALUE()
函数,如果你真的需要和以前一样的行为,可以作为这个问题的另一个解决scheme。 这种灵活性是有代价的,因为它是非确定性的,所以我不会推荐它,除非你有一个很好的理由需要它。 MySQL现在开启了默认情况下的only_full_group_by
设置,所以最好习惯它,并使查询符合它。
那么为什么我上面的简单答案? 我做了一些假设:
1) group_id
是唯一的。 看起来合理,毕竟这是一个“身份证”。
2) group_name
也是唯一的。 这可能不是这样一个合理的假设。 如果情况并非如此,并且您有一些重复的group_names
,然后按照我的build议将group_id
添加到GROUP BY
,则可能会发现现在获得的结果比以前更多,因为具有相同名称的组现在将具有单独的行结果。 对我来说,这会比隐藏这些重复组更好,因为数据库已经悄悄地select了一个值!
当涉及多个表时,使用表名或别名限定所有列也是一个好习惯。
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
您可以尝试通过执行以下操作来禁用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';
您可以按照其他答案中的说明closures警告消息,或者您可以了解发生的情况并解决问题。
从MySQL 5.7.5开始,默认的SQL模式包括ONLY_FULL_GROUP_BY ,这意味着当您对行进行分组,然后从这些组中select某些内容时,您需要明确说明应从哪个行进行select。
Mysql需要知道您要查找的组中的哪一行,这给了您两个选项
- 您还可以
group by rect.color, rect.value
将您想要的列添加到组语句group by rect.color, rect.value
在某些情况下可以是您想要的,否则将使用您可能不想要的相同颜色返回重复的结果 - 你也可以使用mysql的聚合函数来指示你在
AVG()
MIN()
MAX()
完整列表 - 最后你可以使用
ANY_VALUE()
如果你确定组内的所有结果是相同的。 DOC
如果您不想在当前查询中进行任何更改,请按照以下步骤操作 –
- stream浪ssh到你的盒子里
- 键入:
sudo vim /etc/mysql/my.cnf
- 滚动至文件底部并键入
A
进入插入模式 -
复制和粘贴
[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
-
input
esc
退出input模式 - 键入
:wq
保存并closuresvim。 - 键入
sudo service mysql restart
重启MySQL。
我使用Laravel 5.3,MySQL 5.7.12,在laravel宅基地(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
从true
更改为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
使用ANY_VALUE()
来引用非ANY_VALUE()
列。
从MySQL 5.7文档 :
您可以通过使用
ANY_VALUE()
来引用非ANY_VALUE()
列来实现相同的效果,而不禁用ONLY_FULL_GROUP_BY
。…
由于select列表中的非
ONLY_FULL_GROUP_BY
地址列未在GROUP BY
子句中命名,因此此查询可能无效,ONLY_FULL_GROUP_BY
启用ONLY_FULL_GROUP_BY
:SELECT name, address, MAX(age) FROM t GROUP BY name;
…
如果您知道,对于给定的数据集,每个名称值实际上唯一确定地址值,地址在function上实际上取决于名称。 要告诉MySQL接受查询,可以使用
ANY_VALUE()
函数:SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;
我会尽力向你解释这个错误是关于什么的。
从MySQL 5.7.5开始,选项ONLY_FULL_GROUP_BY
是默认启用的。
因此,根据标准的SQL92及更早的版本:
不允许查询select列表,HAVING条件或ORDER BY列表引用既未在GROUP BY子句中命名也未在function上依赖于GROUP BY列(由其唯一确定)的非聚合列
( 更多文档 )
所以,例如:
SELECT * FROM `users` GROUP BY `name`;
执行上面的查询后,您将收到错误消息。
#1055 – SELECT列表的expression式#1不在GROUP BY子句中,并且包含非聚集列“testsite.user.id”,它在function上不依赖于GROUP BY子句中的列; 这与sql_mode = only_full_group_by不兼容
为什么?
因为MySQL不完全明白,从分组logging中检索什么特定值,这就是重点。
IE让我们说你有这个logging在你的users
表中:
你会执行上面的无效查询showen。
你会得到上面显示的错误,因为有3个logging名为John
,这是很好的,但是,他们都有不同的email
字段值。
所以,MySQL根本不明白哪个返回结果分组logging。
你可以通过改变你的查询来解决这个问题:
SELECT `name` FROM `users` GROUP BY `name`
此外,你可能想要添加更多的字段到SELECT部分,但你不能这样做,如果他们不汇总,但有拐杖,你可以使用(但非常reccomended):
SELECT ANY_VALUE(`id`), ANY_VALUE(`email`), `name` FROM `users` GROUP BY `name`
现在,您可能会问,为什么不推荐使用ANY_VALUE
?
因为MySQL并不完全知道分组logging的检索价值,所以通过使用这个函数,你可以提取它们中的任何一个(在这种情况下,第一个logging的名字= John的电子邮件被提取)。
确切地说,我不能想出为什么你会想这种行为存在的任何想法。
请,如果你不了解我,阅读更多关于如何分组在MySQL中的作品,这是非常简单的。
最后,这是一个更简单,但有效的查询。
如果要根据可用年龄查询总计用户数,则可能需要记下此查询
SELECT `age`, COUNT(`age`) FROM `users` GROUP BY `age`;
根据MySQL规则,这是完全有效的。
等等。
了解问题究竟是什么,只有写下解决scheme才是重要的。
如果你正在使用wamp 3.0.6或者stable 2.5以外的版本,你可能会遇到这个问题,首先问题是sql。 你必须相应地命名字段。 但还有另一种方法可以解决这个问题。 点击wamp的绿色图标。 mysql-> mysql设置 – > 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';
对于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
重新启动MySQL服务器。
mysql.server restart
对于localhost / wampserver 3,我们可以设置sql-mode = user_mode来删除这个错误:
click on wamp icon -> MySql -> MySql Setting -> sql-mode -> user_mode
然后重启wamp或者apache
这是帮助我理解整个问题的原因:
- https://stackoverflow.com/a/20074634/1066234
- 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列表的expression式#4包含非聚集列'db.gameplay.timestamp'; 这是不符合sql_mode = only_full_group_by – 查询:SELECT COUNT(*)作为尝试,SUM(elapsed)作为elapsedtotal,userid,时间戳,questionid,答案ID,SUM(正确)正确,已过去,IP地址从游戏玩法WHERE timestamp> = DATE_SUB (NOW(),INTERVAL 1 DAY)和userid = 1
在这种情况下,GROUP BY中缺lessexpression式#4 。
在文件/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)
你可以添加一个unique index
group_id
; 如果你确定group_id
是唯一的。
它可以解决你的情况,而无需修改查询 。
答案很晚,但答案中还没有提到。 也许它应该完成已经全面的答案。 至less它解决了我的情况,当我不得不分裂一个桌子太多领域。
抱歉不使用你的确切的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
如果Symfony使用原则查询生成器时出现此错误,并且此错误是由orderBy引起的:
注意select
你要groupBy
的列,并使用addGroupBy
而不是groupBy
:
$query = $this->createQueryBuilder('smth')->addGroupBy('smth.mycolumn');
在Symfony3上运行 –