如何过滤SQL结果,实现每个客户仅保留一条商品记录(甜瓜优先)
解决方案:筛选客户商品购买记录
针对你的需求——同时购买Melon和Rice的客户仅保留Melon记录,仅购买其中一种的保留对应商品记录,这里提供几种可行的实现方式,同时解答你关于HAVING子句使用CASE的疑问:
方法一:窗口函数(推荐)
利用ROW_NUMBER()窗口函数给商品设置优先级,Melon优先级高于Rice,再取每个客户的第一条记录:
WITH ranked_products AS ( SELECT CustomerId, Name, Product, Price, -- 给Melon标记优先级1,Rice标记2,按客户分组排序 ROW_NUMBER() OVER (PARTITION BY CustomerId, Name ORDER BY CASE WHEN Product = 'Melon' THEN 1 ELSE 2 END) AS rn FROM LIST WHERE Product IN ('Melon', 'Rice') -- 仅筛选目标商品 ) SELECT CustomerId, Name, Product, Price FROM ranked_products WHERE rn = 1;
逻辑说明:每个客户的记录组内,Melon会排在最前面,因此取rn=1就能保证同时买两种的客户只保留Melon,只买一种的保留对应商品。
方法二:UNION ALL + EXISTS子查询
分两部分查询后合并:先取所有Melon记录,再取未购买Melon的客户的Rice记录:
-- 取所有购买过Melon的记录 SELECT CustomerId, Name, Product, Price FROM LIST WHERE Product = 'Melon' UNION ALL -- 取仅购买Rice的客户记录(排除买过Melon的) SELECT CustomerId, Name, Product, Price FROM LIST WHERE Product = 'Rice' AND NOT EXISTS ( SELECT 1 FROM LIST AS L2 WHERE L2.CustomerId = LIST.CustomerId AND L2.Name = LIST.Name AND L2.Product = 'Melon' );
关于HAVING子句中使用CASE的问题
可以使用,但更适合在SELECT子句结合聚合函数来实现逻辑(HAVING主要用于分组后的过滤,这里需求不需要过滤分组,而是选择分组内的特定记录)。示例如下:
SELECT CustomerId, Name, -- 判断客户是否买过Melon,有则取Melon,否则取Rice CASE WHEN COUNT(CASE WHEN Product = 'Melon' THEN 1 END) > 0 THEN 'Melon' ELSE 'Rice' END AS Product, -- 对应取Melon的价格,无则取Rice的价格 COALESCE(MAX(CASE WHEN Product = 'Melon' THEN Price END), MAX(CASE WHEN Product = 'Rice' THEN Price END)) AS Price FROM LIST WHERE Product IN ('Melon', 'Rice') GROUP BY CustomerId, Name;
逻辑说明:通过聚合函数统计客户是否有Melon记录,再用CASE选择对应的商品和价格,最终每个客户返回一条符合要求的记录。
内容的提问来源于stack exchange,提问作者Waren Schild
相关产品推荐
相关产品推荐

