SQL查询报错:关联用户与会话表统计企业用户及活跃用户数
正确的SQL查询方案及错误分析
先帮你梳理下问题根源,再给出能得到目标结果的正确查询方案:
原来SQL的核心问题
- LEFT JOIN导致总用户数重复计数:当你用
LEFT OUTER JOIN sessions时,若某个用户有多条会话记录,这条用户数据会被重复返回多次,COUNT(users.user_id)会把这些重复行全部统计进去,导致totalUsers远大于实际总用户数。 - 聚合函数嵌套语法错误:你在
activeUsers的统计里写了COUNT(DISTINCT(CASE WHEN COUNT(sessions.session_id) > 0 ...)),聚合函数(比如COUNT)不能直接嵌套在另一个聚合函数的参数中,这会直接触发SQL语法报错。 - GROUP BY字段不匹配:SELECT里用的是
users.company,但GROUP BY写的是users.company_name,字段名不一致会导致分组逻辑错误或直接报错。
方案一:先去重会话用户再关联(推荐)
这个方法先从sessions表提取所有有会话的唯一用户ID,再和users表关联,彻底避免重复行问题,统计逻辑清晰直观:
SELECT u.company, COUNT(u.user_id) AS totalUsers, COUNT(s.user_id) AS activeUsers FROM users u LEFT JOIN ( -- 先获取所有有会话记录的唯一用户ID SELECT DISTINCT user_id FROM sessions ) s ON u.user_id = s.user_id GROUP BY u.company;
逻辑说明:
COUNT(u.user_id):users表中每个用户唯一,且关联后的结果里每个用户最多出现一次(子查询已去重),因此这个统计的就是该公司的总用户数。COUNT(s.user_id):没有会话记录的用户,s.user_id会是NULL,而COUNT不会统计NULL值,所以这个结果就是该公司的活跃用户数。
方案二:用子查询标记用户会话状态
如果更倾向于先标记每个用户是否有会话,再分组统计,可以用这个方案:
SELECT company, COUNT(user_id) AS totalUsers, SUM(CASE WHEN has_session = 1 THEN 1 ELSE 0 END) AS activeUsers FROM ( -- 先给每个用户标记是否存在会话记录 SELECT u.company, u.user_id, CASE WHEN EXISTS (SELECT 1 FROM sessions s WHERE s.user_id = u.user_id) THEN 1 ELSE 0 END AS has_session FROM users u ) AS user_session_info GROUP BY company;
逻辑说明:
- 内层子查询通过
EXISTS快速判断每个用户是否有会话记录,生成has_session标记字段。 - 外层按公司分组,
COUNT(user_id)统计总用户数,SUM(CASE ...)统计标记为1的用户数量,也就是活跃用户数。
这两个方案都能精准输出你想要的结果,且完全规避了原SQL的所有问题。
内容的提问来源于stack exchange,提问作者tshaw
相关产品推荐
相关产品推荐

