如何在 Laravel 中禁用 only_full_group_by 选项
Posted
技术标签:
【中文标题】如何在 Laravel 中禁用 only_full_group_by 选项【英文标题】:How to disable only_full_group_by option in Laravel 【发布时间】:2018-06-17 03:24:26 【问题描述】:我是 laravel 的新手,我遇到了数据库问题。
我通过编辑/etc/mysql/my.cnf
文件禁用了“only_full_group_by”sql_mode。我使用SELECT @@GLOBAL.sql_mode;
和SELECT @@SESSION.sql_mode;
检查了sql_mode
的全局和会话,并确认sql_mode
不再具有only_full_group_by
。
但是,当我通过邮递员发出请求时,它给了我this is incompatible with sql_mode=only_full_group_by
的错误消息。
我很困惑。为什么我更改了sql_mode
后仍会出现此错误?我做错了吗?
任何建议或意见将不胜感激。
谢谢。
使用 toSql() 的 SQL
select A.*
from `A`
inner join `B` on `A`.`id` = `B`.`a_id`
inner join `C` on `C`.`id` = `B`.`c_id`
group by `A`.`id` having COUNT(A.id) > 0;
【问题讨论】:
SELECT *
与 GROUP BY
不兼容。在 5.7.5 版本之前,MySQL 曾经接受无效的GROUP BY
查询,但它保留为未出现在GROUP BY
子句中的SELECT
表达式返回indeterminate values 的权利。查询可以使用不同机器上的相同输入返回不同的值。禁用only_full_group_by
并不能解决问题,它只是隐藏它。
【参考方案1】:
这是错误的处理方式。与其关闭only_full_group_by
模式,不如修复查询,以免破坏 MySQL:
SELECT a1.*
FROM A a1
INNER JOIN
(
SELECT A.id
FROM A
INNER JOIN B
ON A.id = B.a_id
INNER JOIN C
ON C.id = B.c_id
GROUP BY A.id
HAVING COUNT(A.id) > 0
) a2
ON a1.id = a2.id;
我不知道您关闭严格模式的尝试为何失败,但无论如何您都不应该依赖它。
【讨论】:
具体问题的正确答案由下面的@Brian 提供。有一些您不希望设置 only_full_group_by 的有效用例。尤其是当您希望通过一个键区分大型数据集的不同值时。 @Dom 关闭严格模式几乎总是一个坏主意。我的答案提供了一个正确的查询,它将在 MySQL 上运行是 any 模式,它也可能在大多数其他数据库上运行。 @TimBiegeleisen 我完全不同意。请阅读 Dom DaFonte 的回答并做一些研究。【参考方案2】:要回答最初的问题,如果您想在 Laravel 中禁用此功能,您必须在 config/database.php 中的数据库配置中将 'strict' 值更改为 false。
'connections' => [
...
'mysql' => [
...
'strict' => false,
...
],
]
【讨论】:
这是这个问题的正确答案并解决了我的问题。我需要按一列分组,我的 my.cnf 配置正确,但我必须删除 laravel 的严格模式。确实,如果您的数据库正确配置了所需的严格性,则无需将应用程序设置为严格模式。 @Dom 这个答案不反映最佳 SQL 实践。在选择所有其他列的同时按一列分组仅在该列恰好是唯一键时才有效。 这是提出的问题,“如何在 Laravel 中禁用 only_full_group_by 选项”。 @Brian 提供了该问题的答案。尽管您确实帮助他更正了他的 sql,但仍有一些有效的用例不设置 full_group_by。否则,为什么 mysql 会允许从 my.cnf 中删除它。此设置仅在数据库 > 5.7 上启用。您当然可以在回复中提供 OP 最佳实践,这很有帮助,但 *** 的基本目标是让未来的读者搜索问题并找到答案。这是正确的答案。 应该保留 strict=true。 @thebvg1ne-zoren 提供了正确的答案。我还添加了全套参数。 "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】:将此模式添加到 config/database.php
'mysql' => [
...
'modes' => [
'STRICT_ALL_TABLES',
],
],
如果你设置
'strict' => true
。一些sql异常不会像sql数据完整性异常那样抛出。
【讨论】:
【参考方案4】:在 Laravel 中,您可以在运行时执行此操作,而不是进行全局设置
//disable ONLY_FULL_GROUP_BY
DB::statement("SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));");
//Your SQL goes here - The one throwing the error (:
//re-enable ONLY_FULL_GROUP_BY
DB::statement("SET sql_mode=(SELECT CONCAT(@@sql_mode, ',ONLY_FULL_GROUP_BY'));");
【讨论】:
我怎样才能让它全球化?请告诉我。谢谢 @Kamlesh 查看 thebvg1ne-zoren 的答案。有用。我添加了全套“sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION” @blackmambo 我正在使用 Lumen 8。我在每个控制器的构造函数中添加了这个语句DB::statement("SET sql_mode = '' ");
,它对我有用。顺便说一句,我们也可以在全局中间件中编写此语句,然后我们不必在每个控制器中编写此语句。非常感谢亲爱的。
@Kamlesh 你永远不应该抛出 sql_mode 配置参数。至少,保留我上面提到的基本设置。此外,如果您无权访问 mysql 配置文件,则应尝试在配置与数据库的连接时配置 use 语句。以上是关于如何在 Laravel 中禁用 only_full_group_by 选项的主要内容,如果未能解决你的问题,请参考以下文章
如何在 daterangepicker JS 和 Laravel 中禁用占用的日期
在 Laravel 5 中,如何禁用特定路由的 VerifycsrfToken 中间件?