NOT IN子查询无结果求助:获取bus_user_perms表中不在分组结果的数据
解决NOT IN查询无结果的问题
这个问题很常见,根源在于SQL的三值逻辑以及NOT IN对NULL值的特殊处理方式。当你的子查询返回的结果集中包含NULL的Perm_id时,NOT IN会直接返回空结果——因为任何值和NULL比较都会得到UNKNOWN,而NOT IN要求所有比较结果都为TRUE才会返回行,只要有一个UNKNOWN,整个条件就不成立。
第一步:验证问题原因
先检查你的子查询是否包含NULL值:
SELECT COUNT(*) FROM ( SELECT Perm_id FROM bus_user_perms GROUP BY Perm_username, Perm_BusArId ) sub_query WHERE Perm_id IS NULL;
如果这个查询返回大于0的数字,那就坐实了是NULL导致的问题。
解决方案
这里提供三种可靠的替代方案,都能避开NOT IN的NULL陷阱:
方案1:在子查询中排除NULL值
直接过滤掉子查询里的NULL,让NOT IN可以正常工作:
SELECT * FROM `bus_user_perms` WHERE `Perm_id` NOT IN ( SELECT `Perm_id` FROM `bus_user_perms` GROUP BY `Perm_username`, `Perm_BusArId` WHERE `Perm_id` IS NOT NULL -- 新增这行排除NULL );
方案2:使用LEFT JOIN + IS NULL
这是处理这类排除查询的经典写法,逻辑清晰且不受NULL影响:
SELECT bup.* FROM `bus_user_perms` bup LEFT JOIN ( SELECT `Perm_id` FROM `bus_user_perms` GROUP BY `Perm_username`, `Perm_BusArId` ) sub ON bup.Perm_id = sub.Perm_id WHERE sub.Perm_id IS NULL;
原理是:将原表和子查询结果左连接,那些在子查询中没有匹配到的行(也就是你要找的61条),sub.Perm_id会是NULL,通过这个条件就能筛选出来。
方案3:使用NOT EXISTS
NOT EXISTS是更推荐的写法之一,它的逻辑是“不存在匹配子查询条件的记录”,天然不受NULL影响:
SELECT bup.* FROM `bus_user_perms` bup WHERE NOT EXISTS ( SELECT 1 FROM `bus_user_perms` bup_sub WHERE bup_sub.Perm_username = bup.Perm_username AND bup_sub.Perm_BusArId = bup.Perm_BusArId AND bup_sub.Perm_id = bup.Perm_id GROUP BY bup_sub.Perm_username, bup_sub.Perm_BusArId );
额外提示
你的原查询中,GROUP BY Perm_username, Perm_BusArId后直接选择Perm_id,在严格SQL模式下会报错(因为Perm_id既不在GROUP BY列表中,也没有使用聚合函数)。如果你的数据库允许这种写法,它会返回每个分组中随机的一条Perm_id。如果你想明确获取每个分组的第一条/最后一条Perm_id,建议加上聚合函数,比如MIN(Perm_id)或MAX(Perm_id):
SELECT MIN(Perm_id) AS Perm_id FROM `bus_user_perms` GROUP BY `Perm_username`, `Perm_BusArId`
内容的提问来源于stack exchange,提问作者BACode
相关产品推荐
相关产品推荐

