SQL Developer 查询先购买产品A后购买产品B的客户ID
SQL实现方案
要实现的筛选逻辑本质是匹配「同客户下存在产品A的购买记录早于产品B的购买记录」的场景,以下两种方案都可以直接得到正确结果:
方案1:自连接匹配(逻辑直观易调试)
将同一张购买表分别筛选出A的购买子集、B的购买子集做内连接,直接匹配同客户下B交易时间晚于A的记录,去重后即可得到目标客户ID:
SELECT DISTINCT a.`customer ID` FROM Purchase a JOIN Purchase b ON a.`customer ID` = b.`customer ID` AND a.`Product ID` = 'A' AND b.`Product ID` = 'B' -- 以下日期转换根据你的数据库类型调整,字段本身是日期类型可直接比较 AND STR_TO_DATE(b.`Transaction Date`, '%d/%m/%Y') > STR_TO_DATE(a.`Transaction Date`, '%d/%m/%Y')
这个写法逻辑非常直白,排查问题时可以直接去掉DISTINCT查看匹配到的交易对,适合数据量中等的场景。
方案2:聚合判断(大表性能更优)
不需要做表关联,直接按客户分组聚合,通过条件聚合判断客户是否同时买过A、B,且B的最早购买时间晚于A的最早购买时间:
SELECT `customer ID` FROM Purchase GROUP BY `customer ID` HAVING SUM(`Product ID` = 'A') > 0 AND SUM(`Product ID` = 'B') > 0 AND MIN(CASE WHEN `Product ID` = 'B' THEN STR_TO_DATE(`Transaction Date`, '%d/%m/%Y') END) > MIN(CASE WHEN `Product ID` = 'A' THEN STR_TO_DATE(`Transaction Date`, '%d/%m/%Y') END)
这个写法只需要全表扫描一次,在百万级以上数据量的场景下性能远好于自连接方案。判断逻辑完全成立:只要客户最早购买B的时间晚于最早购买A的时间,就必然满足B购买晚于A的要求;如果最早的B购买时间早于A,后续所有B的购买时间都不会早于这个最早时间,不会出现漏判。
注意事项
- 如果
Transaction Date字段本身已经是DATE/DATETIME类型,不需要加任何日期转换函数,直接比较字段即可 - 日期转换语法需要匹配你使用的数据库,不要直接套用MySQL的
STR_TO_DATE:- PostgreSQL 用
TO_DATE("Transaction Date", 'DD/MM/YYYY') - SQL Server 用
CONVERT(DATE, "Transaction Date", 103)
- PostgreSQL 用
- 两种方案在提供的样例数据上执行,都会正确返回
jones、blogs两个客户,客户lane因为没有购买产品B,会被直接过滤。
内容的提问来源于stack exchange,提问作者Roundup
相关产品推荐
相关产品推荐

