使用子查询与GROUP BY计算各国每日DAU平均值的问题排查
解决各国近1个月DAU平均值计算问题
你的核心问题出在外层查询的逻辑完全偏离了需求,咱们一步步拆解问题,给出精准的解决方案:
原查询的关键错误
你的子查询思路是对的(计算每日各国的DAU),但外层查询犯了两个致命错误:
- 逻辑匹配完全错位:子查询返回的是每日各国的DAU统计数值(比如某国某天有1500个活跃用户),但你用
User_ID IN (...)是把用户ID和这些统计数做匹配——用户ID是用户的唯一标识,DAU是计数结果,两者没有任何关联,这直接导致筛选出的UserID全是错误的,自然结果混乱。 - 聚合对象完全错误:外层用
AVG(User_ID)是对用户ID取平均值,而你真正需要的是对每日DAU数值取平均,这完全搞错了聚合的目标。
另外还有个细节问题:原查询用DAY(Opened)分组,只会提取日期的“日”部分(比如11月20日和12月20日的DAY都是20),跨月的同一天会被错误合并,导致DAU计算失真,应该用DATE(Opened)获取完整日期。
正确的查询写法
我们先通过子查询算出近1个月内每个国家每天的DAU,再基于这些每日数据计算平均值:
SELECT Country, ROUND(AVG(daily_dau), 0) AS Average -- 用ROUND保留整数,符合用户数的计数逻辑 FROM ( -- 子查询:统计每日每个国家的活跃用户数(DAU) SELECT Country, DATE(Opened) AS login_date, -- 用完整日期分组,避免跨月重复 COUNT(DISTINCT UserID) AS daily_dau FROM usersession WHERE Opened >= CURRENT_TIMESTAMP - INTERVAL 1 MONTH GROUP BY DATE(Opened), Country ) AS daily_country_dau GROUP BY Country ORDER BY Country;
逻辑拆解
- 子查询部分:
- 筛选近1个月内的所有登录记录
- 按
完整登录日期和国家分组,用COUNT(DISTINCT UserID)计算每个国家每天的去重活跃用户数(即当日DAU)
- 外层查询部分:
- 按
国家分组,对每个国家的所有daily_dau值取平均,得到该国家近1个月的DAU平均值 - 用
ROUND函数把结果转成整数,因为DAU是用户数量,用整数更符合业务逻辑
- 按
这个写法会输出你预期的格式:每个国家对应其近1个月的平均DAU,不会出现NULL或错误的数值。
内容的提问来源于stack exchange,提问作者Suinelas
相关产品推荐
相关产品推荐

