Bootstrap

2. 查询至少连续三天下单的用户

题目需求

查询订单信息表(order_info)中 最少连续3天 下单的用户id,期望结果如下:

user_id
101

订单信息表:order_info

order_id
(订单id)
user_id
(用户id)
create_date (下单日期)total_amount
(订单金额)
11012021-09-3029000.00
101032020-10-0228000.00
思路一:(作差法)

通过与行号作差的方式判断是否连续(推荐)

在这里插入图片描述

实现一
-- 4) 按照 user_id, sub_res 进行分组,对每组记录进行计数,选出>=3的user_id
select
	distinct user_id
from
(
  -- 3)计算 create_date - row_num 得到 sub_res
  -- 2)对order_info中的每条记录编号。对 user_id 进行分组,组内按照 create_date 升序排序,并对每条记录使用 row_number 进行编号 row_num
  SELECT
      user_id,
      --create_date,
      --row_number() over(partition by user_id order by create_date) as  row_num
      date_add(create_date, -row_number() over(partition by user_id order by create_date))  as  sub_res
  from 
  (
    -- 1) 对用户进行去重。原因:用户一天可能存在多次下单的情况,我们此处只需要一次即可
    SELECT
      DISTINCT user_id,
      order_id,
      create_date
    from order_info
  )t1
)t2
group by user_id,sub_res having count(*)>=3;
思路二:(使用lead函数)

通过 lead() 开窗函数获取往后第二次的登录日期

在这里插入图片描述

实现二
-- 3) 筛选出 sub_res=2 的记录
select
	DISTINCT user_id
from
(
  -- 2) 通过 lead() 开窗函数获取每个用户往后第二次的登录日期
  select
      user_id,
      -- lead(create_date, 2, '9999-12-31') over(partition by user_id order by create_date) next_2_date
      datediff(lead(create_date, 2, '9999-12-31') over(partition by user_id order by create_date), create_date) sub_res
  from
  (
    -- 1) 对用户进行去重。原因:用户一天可能存在多次下单的情况,我们此处只需要一次即可
    SELECT
        DISTINCT user_id,
        order_id,
        create_date
    from order_info
  )t1
)t2
where sub_res=2;
思路三:(自连接)

新增于 2024.07.03。
思路:来自于牛客评论区。

with record as (
    -- 1) 对用户进行去重。原因:用户一天可能存在多次下单的情况,我们此处只需要一次即可
    select distinct user_id,
                    create_date
    from order_info
)

select distinct t1.user_id
from record t1
         inner join record t2
                    on t1.user_id = t2.user_id
                        and date_add(t1.create_date, 1) = t2.create_date
         inner join record t3
                    on t1.user_id = t3.user_id
                        and date_add(t1.create_date, 2) = t3.create_date;
;