表达式不在group by子句中

hvvq6cgz  于 2021-06-18  发布在  Mysql
关注(0)|答案(2)|浏览(471)

我在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

此sql失败,只启用了\u full \u group \u by,这是mysql中的默认值,因为并非所有表达式都在GROUPBY子句中。我发现的解决方案通常涉及使用聚合函数(如max())或将所有表达式添加到GROUPBY子句中,但是'users'子查询使这些方法成了问题:我不能使用max()方法(无效语法),将其添加到groupby子句会导致查询非常慢,以至于我还没有看到测试完成。
我觉得可能有一种解决方案既优雅又高效,而不必仅禁用“完全分组”,但我对sql的了解还不够深入。

kse8i1jr

kse8i1jr1#

下面是一个简化的查询:

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)忽略空值,我猜您的意思是计算日志中的所有命中数,这意味着您应该使用 COUNT(*) 而不是 COUNT(u.name) .
我删除了orderby子句,因为它引用了结果中不存在的列。如果要按月份排序,则应考虑按所需的排序方式格式化月份:

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

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

lp0sw83n

lp0sw83n2#

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

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;

相关问题