查询无耳机的活跃用户:SQL语句返回空结果问题求助
解决未分配耳机的摩洛哥活跃用户查询问题
表结构说明
Table user with id, email, first_name, last_name, country, activated Table assets with id, serial, model_id, assigned_to Table models with id, name, category_id Table categories with id, name Table status_labels with id, name
原查询的问题分析
- 第一条查询逻辑完全错误:子查询筛选的是
c.name = 'Desktop',实际是排除了拥有台式机的用户,和“未分配耳机”的需求不沾边。 - 第二条查询条件矛盾:左连接后,若用户没有耳机,
c.name会是NULL,但WHERE条件要求c.name = 'Headset',这直接过滤掉所有无耳机的用户;同时又要求a.id IS NULL(无任何资产),两个条件不可能同时满足,所以返回空结果。
正确的查询方法
方法一:NOT EXISTS(推荐,性能更优)
SELECT u.id, u.email, u.first_name, u.last_name FROM users u WHERE u.activated = 1 AND u.country = 'MA' AND NOT EXISTS ( SELECT 1 FROM assets a JOIN models m ON a.model_id = m.id JOIN categories c ON m.category_id = c.id WHERE a.assigned_to = u.id AND c.name = 'Headset' );
这个查询直接检查用户是否没有任何耳机类资产,不管用户有没有笔记本、台式机等其他设备,只要没分配耳机就会被选中。
方法二:左连接+筛选
SELECT DISTINCT u.id, u.email, u.first_name, u.last_name FROM users u LEFT JOIN assets a ON a.assigned_to = u.id LEFT JOIN models m ON m.id = a.model_id LEFT JOIN categories c ON c.id = m.category_id AND c.name = 'Headset' WHERE u.activated = 1 AND u.country = 'MA' AND a.id IS NULL;
把c.name = 'Headset'放到JOIN条件里,只左连接用户的耳机资产;如果用户没有耳机,a.id会是NULL,此时就能筛选出目标用户。加DISTINCT是避免用户有多个其他资产时产生重复行。
方法三:GROUP BY+HAVING统计
SELECT u.id, u.email, u.first_name, u.last_name FROM users u LEFT JOIN assets a ON a.assigned_to = u.id LEFT JOIN models m ON m.id = a.model_id LEFT JOIN categories c ON c.id = m.category_id WHERE u.activated = 1 AND u.country = 'MA' GROUP BY u.id, u.email, u.first_name, u.last_name HAVING SUM(CASE WHEN c.name = 'Headset' THEN 1 ELSE 0 END) = 0;
通过CASE语句统计用户的耳机数量,HAVING条件要求数量为0,即用户没有任何耳机资产,同时保留有其他设备的用户。
内容的提问来源于stack exchange,提问作者Siwams
相关产品推荐
相关产品推荐

