如何实现MySQL NOT EXISTS查询:筛选属于某分类但不属于另一分类的联系人
问题根因
你编写的NOT EXISTS子查询没有和外层查询的联系人做关联,子查询的判断逻辑是「全局是否存在任意一个属于category_2的联系人」,只要你的数据库里有哪怕一个联系人被分配了category_2,NOT EXISTS的结果就为假,外层所有符合category_1条件的联系人都会被过滤,最终返回结果为空。
修正后的SQL
把外层联系人的ID关联到子查询的过滤条件中,实现判断「当前遍历的联系人是否属于category_2」的逻辑:
SELECT DISTINCT contact.* FROM Contact contact INNER JOIN ContactCategory categories ON contact.ContactId = categories.ContactId INNER JOIN Category category ON categories.CategoryId = category.CategoryId WHERE LOWER(category.Name) = 'category_1' AND NOT EXISTS ( SELECT 1 FROM Contact contact_temp INNER JOIN ContactCategory categories_temp ON contact_temp.ContactId = categories_temp.ContactId INNER JOIN Category category_temp ON categories_temp.CategoryId = category_temp.CategoryId WHERE contact_temp.ContactId = contact.ContactId -- 新增关联条件,绑定外层当前联系人 AND LOWER(category_temp.Name) = 'category_2' )
注:子查询里用
SELECT 1替代SELECT DISTINCT contact_temp.*可以提升查询性能,NOT EXISTS只判断是否存在行,不需要返回实际字段内容。
多分类场景扩展建议
如果前端传入多个正负分类,比如category_1,category_2,-category_3,-category_4,可以按以下逻辑改写:
- 正向分类用
IN批量匹配,同时可以加GROUP BY contact.ContactId HAVING COUNT(DISTINCT category.Name) = 正向分类数量保证命中所有要求的正向分类 - 每个负向分类对应一个NOT EXISTS子查询,或者用聚合条件加
SUM(CASE WHEN LOWER(category.Name) IN ('category_3','category_4') THEN 1 ELSE 0 END) = 0实现
内容的提问来源于stack exchange,提问作者Burton
相关产品推荐
相关产品推荐

