【问题标题】:Expression is not in GROUP BY clause表达式不在 GROUP BY 子句中
【发布时间】:2018-09-24 16:29:06
【问题描述】:

我在 MySQL (v5.7) 中有一个记录用户请求的日志表,我从中提取活动细分,显示每个月的用户数量和总点击量,例如:

Date            Users   Hits
September 2018  20      1,839
August 2018     23      2,723
July 2018       21      1,632
June 2018       22      2,981

目前使用以下查询来实现:

SELECT month(l.time) m, year(l.time) y, date_format(l.time, '%M %Y') monthyear, 
  (select count(distinct userid) from log lm 
    where month(lm.time) = month(l.time) and year(lm.time) = year(l.time)) users,
  count(u.name) hits
FROM log l left join users u on u.id=l.userid
group by date_format(l.time, '%M %Y')
order by l.time desc, l.id desc

启用 only_full_group_by 后,此 SQL 将失败,这是 MySQL 中的默认设置,因为并非所有表达式都在 GROUP BY 子句中。我发现的解决方案通常涉及使用聚合函数(例如 MAX() 或将所有表达式添加到 GROUP BY 子句,但“用户”子查询使这些方法存在问题:我不能使用 MAX() 方法(语法无效)并将其添加到 GROUP BY 子句会导致查询速度太慢,以至于我还没有看到测试完成。

我觉得可能有一种优雅且高性能的解决方案,而无需禁用 only_full_group_by,但我对 SQL 的深度有限。

【问题讨论】:

  • 有点好笑......据预测,mysql 实现适当的 Group By 约束将揭示大量可怕的代码。在这种情况下考虑重写选项,因为子选择语法是解决这个问题的一个非常糟糕的方法。

标签: mysql sql group-by aggregate


【解决方案1】:

这是一个简化的查询:

SELECT DATE_FORMAT(l.time, '%M %Y') AS monthyear, 
  COUNT(DISTINCT l.userid) AS users,
  COUNT(*) AS hits
FROM log l
GROUP BY monthyear

您不需要选择列表中的单个月份或年份,因为您没有在所需的结果中显示它。

您根本不需要加入 users 表,除非您的意思是只计算具有非 NULL name 列的用户的命中(COUNT 忽略 NULL,我猜您的意思是计算日志中的所有命中,这意味着您应该使用COUNT(*) 而不是COUNT(u.name)

我删除了 ORDER BY 子句,因为它引用了不在结果中的列。如果您想按月年排序,您应该考虑按照您想要的方式来格式化月年:

SELECT DATE_FORMAT(l.time, '%Y-%m') AS monthyear, 
  COUNT(DISTINCT l.userid) AS users,
  COUNT(*) AS hits
FROM log l
GROUP BY monthyear

默认情况下,GROUP BY 将按值对组进行排序。

【讨论】:

  • 谢谢 - 只见树木不见森林!
【解决方案2】:

我不确定您为什么要为此使用子查询。这不是你想要的吗?

SELECT month(l.time) as m, year(l.time) as y, date_format(l.time, '%M %Y') as monthyear, 
       count(distinct l.userid) as users,
       count(u.name) as hits
FROM log l left join
     users u
     on u.id = l.userid
GROUP BY m, y, monthyear
ORDER BY max(l.time) desc, l.id desc;

【讨论】:

  • 谢谢,我在 SQL 方面有点盲点!这是来自一些相当老的代码,我不知道是我拼凑的还是有人为我提供的,但它显然非常丑陋且效率低下。
猜你喜欢
  • 2017-05-04
  • 2012-08-19
  • 1970-01-01
  • 2018-06-12
  • 2018-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-14
相关资源
最近更新 更多