WHERE/GROUP BY场景下多产品用户的标记筛选与分组问题
你的核心问题在于:当前的Flag字段是行级标记(只表示这条记录是不是Car),但你想要的是用户级的区分(判断这个用户有没有买过Car)。直接用WHERE flag !=1只会排除Car的记录,没法排除买过Car的用户的其他订单,所以才会错误保留Bob的Apples/Pears记录。
下面分几种场景给出针对性解决方案:
场景1:筛选出从未买过Car的用户的所有记录
如果你只想保留完全没买过Car的用户(比如John)的所有订单,可以先找出买过Car的用户列表,再排除他们:
方法1:子查询+NOT IN
SELECT Name, Product, 0 AS Flag FROM your_table WHERE Name NOT IN ( SELECT DISTINCT Name FROM your_table WHERE Product = 'Car' )
方法2:LEFT JOIN筛选NULL
SELECT t.Name, t.Product, 0 AS Flag FROM your_table t LEFT JOIN ( SELECT DISTINCT Name FROM your_table WHERE Product = 'Car' ) car_users ON t.Name = car_users.Name WHERE car_users.Name IS NULL
这两种方法都会只返回John的Apples和Pears记录,完全排除Bob的所有订单。
场景2:保留所有记录,但标记用户是否买过Car
如果你需要保留所有订单,同时明确标记每个用户是否买过Car(方便后续筛选/分组),可以用CTE先计算用户级的状态,再关联回原表:
WITH user_car_status AS ( -- 先给每个用户标记是否买过Car SELECT Name, CASE WHEN EXISTS (SELECT 1 FROM your_table t2 WHERE t2.Name = t1.Name AND t2.Product = 'Car') THEN 1 ELSE 0 END AS Has_Bought_Car FROM your_table t1 GROUP BY Name ) -- 关联回原表,同时保留行级的Flag SELECT t.Name, t.Product, CASE WHEN t.Product = 'Car' THEN 1 ELSE 0 END AS Flag, u.Has_Bought_Car FROM your_table t JOIN user_car_status u ON t.Name = u.Name
这样结果里会多一个Has_Bought_Car字段:Bob的所有记录这个值都是1,John的都是0。之后你想筛选买过Car的用户的所有记录,就用WHERE Has_Bought_Car =1;筛选没买过的就用WHERE Has_Bought_Car =0,完全不会出错。
场景3:按Product分组,统计不同用户群体的情况
如果需要按Product分组,同时统计每个产品对应的"买过Car的用户数"和"没买过Car的用户数",可以基于上面的CTE进一步聚合:
WITH user_car_status AS ( SELECT Name, CASE WHEN EXISTS (SELECT 1 FROM your_table t2 WHERE t2.Name = t1.Name AND t2.Product = 'Car') THEN 1 ELSE 0 END AS Has_Bought_Car FROM your_table t1 GROUP BY Name ) SELECT t.Product, COUNT(DISTINCT CASE WHEN u.Has_Bought_Car =1 THEN t.Name END) AS bought_car_user_count, COUNT(DISTINCT CASE WHEN u.Has_Bought_Car =0 THEN t.Name END) AS never_bought_car_user_count FROM your_table t JOIN user_car_status u ON t.Name = u.Name GROUP BY t.Product
这个查询会输出每个Product对应的两类用户数量,比如Car对应的bought_car_user_count是1(Bob),never_bought_car_user_count是0;Apples对应的bought_car_user_count是1(Bob),never_bought_car_user_count是1(John)。
内容的提问来源于stack exchange,提问作者JohnRambo

