如何使用SQL筛选从未参与跑步和游泳的举重运动用户
你现有的SQL逻辑正确,但存在两个可以优化的点:
- 使用
NOT IN存在逻辑隐患:如果子查询返回的user字段包含NULL值,整个查询会返回空结果,不符合预期。 - 外层查询未去重:如果同一用户有多条举重活动记录,会返回重复的用户名结果。
下面是几种更优的实现方式:
方案1:LEFT JOIN 自关联写法(兼容性最优)
这种写法规避了NOT IN的NULL值陷阱,大部分数据库的查询优化器对这种关联逻辑的优化效率都高于子查询写法:
SELECT DISTINCT a.user FROM activity_log a LEFT JOIN activity_log b ON a.user = b.user AND b.activity IN ('running', 'swimming') WHERE a.activity = 'lifting' AND b.user IS NULL
逻辑说明:先匹配所有有举重记录的用户,再关联查找这些用户有没有跑步/游泳记录,最后过滤掉关联到记录的用户,剩下的就是符合要求的用户。
方案2:聚合分组写法(大数据量性能最优)
这种写法只需要扫描一次全表,不需要自关联,在表数据量较大时性能优势非常明显:
SELECT user FROM activity_log GROUP BY user HAVING SUM(CASE WHEN activity = 'lifting' THEN 1 ELSE 0 END) > 0 AND SUM(CASE WHEN activity IN ('running', 'swimming') THEN 1 ELSE 0 END) = 0
逻辑说明:按用户维度分组,直接判断两个条件:该用户至少有1次举重记录、该用户没有任何跑步/游泳记录。
方案3:EXCEPT 集合运算写法(可读性最优)
如果你的数据库支持EXCEPT语法(PostgreSQL、SQL Server、BigQuery等均支持),可以用集合差集的写法,逻辑最直观:
SELECT DISTINCT user FROM activity_log WHERE activity = 'lifting' EXCEPT SELECT DISTINCT user FROM activity_log WHERE activity IN ('running', 'swimming')
内容的提问来源于stack exchange,提问作者user16251889
相关产品推荐
相关产品推荐

