SQL Server:购物篮存在键盘购买记录时排除该篮的查询实现
排除含指定关联记录的整体条目 SQL 实现
问题根源
你当前遇到的过滤偏差,本质是把行级过滤和聚合维度过滤搞混了:直接写WHERE Name NOT LIKE 'Keyboard'只会逐行判断当前商品是不是键盘,只要某购物篮里同时存在键盘和其他商品,那些非键盘的商品行就会被正常返回,导致本该整体排除的购物篮混在结果里——和你的测试场景里BSecond被查出Cup、Smartphone记录的情况完全一致。
可落地的实现方案
所有方案的核心逻辑统一:先定位所有“存在键盘购买记录”的购物篮全集,再从全量购物篮中整体剔除这个集合,剩下的就是从未买过键盘的购物篮。
- 方案1:NOT EXISTS 关联子查询(生产环境优先推荐)
执行效率最高,无空值匹配隐患,完全适配大表场景:
逻辑说明:逐行匹配每个购物篮,只要关联到任意一条当前购物篮的键盘购买记录,就直接将该购物篮标记为排除项,不会逐商品行返回冗余数据。SELECT b.ID_Basket FROM Basket b WHERE NOT EXISTS ( SELECT 1 FROM Items i WHERE i.FK_ID_Basket = b.ID_Basket AND i.Name = 'Keyboard' ) - 方案2:NOT IN 嵌套子查询
写法简单,但存在隐性坑:
注意事项:如果Items表的SELECT ID_Basket FROM Basket WHERE ID_Basket NOT IN ( SELECT DISTINCT FK_ID_Basket FROM Items WHERE Name = 'Keyboard' AND FK_ID_Basket IS NOT NULL -- 必须加这个条件,否则遇到空值会返回空结果 )FK_ID_Basket存在NULL值,不加空值过滤的话NOT IN的三值逻辑会导致整个查询返回空集,实际使用很容易踩坑。 - 方案3:左连接空值匹配
写法直观,适合需要关联商品维度做扩展的场景:SELECT DISTINCT b.ID_Basket FROM Basket b LEFT JOIN Items i ON b.ID_Basket = i.FK_ID_Basket AND i.Name = 'Keyboard' -- 关联条件只匹配键盘,不要把其他商品拉进来 WHERE i.ID_Items IS NULL -- 没匹配到键盘记录的购物篮就是目标结果
结果验证
用你给出的测试数据跑以上三种SQL,最终返回的购物篮仅包含BThird:
- BFirst因存在键盘购买记录被排除
- BSecond因包含键盘购买记录(哪怕同时有杯子、手机商品)被整体排除
- BThird无任何键盘购买记录,符合查询要求
内容的提问来源于stack exchange,提问作者Jon Doe
相关产品推荐
相关产品推荐

