您不应禁用strict 或删除ONLY_FULL_GROUP_BY。问题是您的查询不明确。这可能不会对您的输出产生影响,或者可能会导致巨大的问题。你最好确定一下。
可以在Percona 上阅读很好的解释(总结如下)。
问题
考虑以下情况:
+----+--------------------+---------+---------------------+
| id | page_url | user_id | ts |
+----+--------------------+---------+---------------------+
| 1 | /index.html | 1 | 2019-04-17 12:21:32 |
| 2 | /index.html | 2 | 2019-04-17 12:21:35 |
| 3 | /news.php | 1 | 2019-04-17 12:22:11 |
| 4 | /store_offers.php | 3 | 2019-04-17 12:22:41 |
| 5 | /store_offers.html | 2 | 2019-04-17 12:23:04 |
| 6 | /faq.html | 1 | 2019-04-17 12:23:22 |
| 7 | /index.html | 3 | 2019-04-17 12:32:25 |
| 8 | /news.php | 2 | 2019-04-17 12:32:38 |
+----+--------------------+---------+---------------------+
现在我们要发出一个查询来计算访问次数最多的页面。这可能是你习惯写的:
SELECT page_url, user_id, COUNT(*) AS visits
FROM web_log
GROUP BY page_url
ORDER BY COUNT(*) DESC;
但是看看结果:
+-------------------+---------+--------+
| page_url | user_id | visits |
+-------------------+---------+--------+
| /index.html | 1 | 3 |
| /news.php | 1 | 2 |
| /store_offers.php | 3 | 2 |
| /faq.html | 1 | 1 |
+-------------------+---------+--------+
查询有效,但并不真正正确。很容易理解,page_url 是分组函数的列,是我们最感兴趣的值,我们希望计数是唯一的。此外,visits 列也不错,因为它是计数器。但是user_id 呢?此列代表什么?
我们对page_url 进行了分组,因此user_id 返回的值只是该组中的值之一。事实上,不仅是用户访问了 index.html,用户 2 和 3 也访问了该页面。那么我们应该如何看待这个价值呢?是第一个访客吗?是最后一个吗?
我们不知道正确的答案! user_id 列的值是组的随机项!
解决方案
您需要考虑是否需要groupBy() 中未使用的值。如果没有,那么只需使用 select() 来明确命名您需要的列。
如果您确实需要 groupBy() 中未使用的列,请使用聚合函数(如 ANY_VALUE() 或 GROUP_CONCAT() 或 MAX())作为 Laravel selectRaw 查询的一部分。然后,您可以确定您的查询提供了您所期望的。
所以在上面的例子中,你可以这样做:
SELECT page_url, ANY_VALUE(user_id), COUNT(*) AS visits
FROM web_log
GROUP BY page_url
ORDER BY COUNT(*) DESC;
或者在 Laravel 中:
WebLog::selectRaw('page_url', 'ANY_VALUE(user_id)', 'COUNT(*) AS visits')
->groupBy('page_url')
->orderBy('visits')
->get();