如何筛选:存在type=AB时取该类记录,无则取最旧行
解决按user_id筛选记录:优先取type=AB,无则取最早记录
下面给你三种可行的写法,根据你的习惯选就行:
方法1:窗口函数(最直观易维护)
用窗口函数给每个用户的记录排优先级:type=AB的直接排第一,剩下的按日期从早到晚排,最后取每个用户的第一条记录。
SELECT x_id, type, user_id, other_id, date FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY CASE WHEN type = 'AB' THEN 0 ELSE 1 END, date ASC ) AS rn FROM your_table ) t WHERE rn = 1;
这里PARTITION BY user_id把数据按用户分组,ORDER BY里先把AB类型的权重设为0(比其他类型的1优先级高),同优先级的再按日期升序取最早的,最后筛选rn=1就是每个用户的目标记录。
方法2:修正NOT EXISTS的写法
你之前用NOT EXISTS出错,大概率是没把user_id的关联和双重条件卡准。正确的逻辑是:要么这条记录是AB类型,要么(该用户根本没有AB记录,且这条是该用户最早的记录)。
SELECT t1.* FROM your_table t1 WHERE t1.type = 'AB' OR ( NOT EXISTS ( SELECT 1 FROM your_table t2 WHERE t2.user_id = t1.user_id AND t2.type = 'AB' ) AND NOT EXISTS ( SELECT 1 FROM your_table t3 WHERE t3.user_id = t1.user_id AND t3.date < t1.date ) );
这个写法里,有AB记录的用户只会返回他们的AB记录,不会带出其他类型;没有AB记录的用户,只会返回他们最早的那条记录。
方法3:UNION ALL分情况合并
把两种场景分开查询再合并,逻辑更直白:
-- 先取所有有AB类型的用户的AB记录 SELECT x_id, type, user_id, other_id, date FROM your_table WHERE type = 'AB' UNION ALL -- 再取没有AB类型的用户的最早记录 SELECT t1.x_id, t1.type, t1.user_id, t1.other_id, t1.date FROM your_table t1 WHERE NOT EXISTS ( SELECT 1 FROM your_table t2 WHERE t2.user_id = t1.user_id AND t2.type = 'AB' ) AND NOT EXISTS ( SELECT 1 FROM your_table t3 WHERE t3.user_id = t1.user_id AND t3.date < t1.date );
因为两种场景的用户集合是完全互斥的(有AB的和没AB的),用UNION ALL合并不会有重复,结果就是你要的。
内容的提问来源于stack exchange,提问作者Crimp
相关产品推荐
相关产品推荐

