问题描述:请你写出一个sql语句查询在2025-10-15以后,如果有一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程,那么输出这个用户的user_id,以及满足前面条件的第一次购买成功的C++课程或Java课程或Python课程的日期first_buy_date,以及满足前面条件的第二次购买成功的C++课程或Java课程或Python课程的日期second_buy_date,以及购买成功的C++课程或Java课程或Python课程的次数cnt,并且输出结果按照user_id升序排序,以上例子查询结果如下:
图片说明
方案1:采用窗口函数ROW_NUMBER为user_id的订单排序,COUNT函数计算每个user_id的订单数量
第一步:添加窗口函数ROW_NUMBER和COUNT

SELECT *,ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY date ASC) AS row_rank,
     COUNT(*) OVER (PARTITION BY user_id) AS cnt
FROM order_info
WHERE date>'2025-10-15'
    AND status = 'completed'
    AND product_name IN ('C++','Java','Python')

第二步:将第一步获得的数据按要求过滤(将第一步获得的结果作为临时表t_f

SELECT t_f.user_id,t_f.date,t_f.cnt
FROM t_f
 WHERE t_f.cnt >= 2 AND t_f.row_rank <= 2

第三步:将第二步获得的数据集命名为临时表t

WITH t_f AS (
         SELECT *,ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY date ASC) AS row_rank,
        COUNT(*) OVER (PARTITION BY user_id) AS cnt
        FROM order_info
        WHERE date>'2025-10-15'
         AND status = 'completed'
         AND product_name IN ('C++','Java','Python')
        ),
       t AS (
             SELECT t_f.user_id,t_f.date,t_f.cnt
         FROM t_f
         WHERE t_f.cnt >= 2 AND t_f.row_rank <= 2
            )

SELECT t.user_id,MIN(t.date) AS first_buy,MAX(t.date) AS second_buy_date,t.cnt
FROM  t
GROUP BY t.user_id
ORDER BY t.user_id ASC;

这里采用了WITH语句整理了子查询语句,使代码可读性增强。
关于with子句的相关知识可以参考https://www.modb.pro/db/25773


另外贴一个采用lead窗口函数的回答
https://blog.nowcoder.net/n/5f3463c52f1e42ce976f65fe700d1f6d?f=comment

lead窗口函数:计算同一结果集中当前行的后续行结果
语法:LEAD(expr [, N[, default]]) [null_treatment] over_clause
参数说明:
expr:参考行
N:正整数,1表示后续一行,2表示后续两行,0表示当前行
default:当数据集无可反馈行时返回的缺省值
OVER_clause:按……分组(和其他窗口函数功能一样)

例子:
例子的数据集,创建一个try的表,插入几条数据

DROP TABLE IF EXISTS try;
CREATE TABLE try(
id INT NOT NULL auto_increment,
name_1 VARCHAR(255) NOT NULL,
date_1 DATE NOT NULL,
PRIMARY KEY (id))

INSERT INTO try (name_1,date_1) VALUES('a','2021-1-2'),('a','2021-1-3'),('a','2021-1-4');
select * from try;

下面试验一下

SELECT *,LEAD(date_1,1,'此处没有数据') OVER (PARTITION BY name_1) as lead_date
FROM try;

图片说明
有兴趣的同学可以令N等于其他数
另外:LAG()函数与LEAD()函数相反,他是取数据集前N个数据,语法跟LEAD()相同。