首页 > 试题广场 >

某宝店铺连续2天及以上购物的用户及其对应的天数

[编程题]某宝店铺连续2天及以上购物的用户及其对应的天数
  • 热度指数:44516 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
11月结束后,小牛同学需要对其在某宝的网店就11月份用户交易情况和产品情况进行分析以更好的经营小店。
11月份销售数据表sales_tb如下(其中,sales_date表示销售日期,user_id指用户编号,item_id指货号,sales_num表示销售数量,sales_price表示结算金额):
sales_date user_id item_id sales_num sales_price
2021-11-01 1 A001 1 90
2021-11-01
2 A002 2 220
2021-11-01
2 B001 1 120
2021-11-02
3 C001 2 500
2021-11-02
4 B001 1 120
2021-11-03
5 C001 1 240
2021-11-03
6 C002 1 270
2021-11-04
7 A003 1 180
2021-11-04
8 B002 1 140
2021-11-04
9 B001 1 125
2021-11-05
10 B003 1 120
2021-11-05
10 B004 1 150
2021-11-05
10 A003 1 180
2021-11-06
11 B003 1 120
2021-11-06
10 B004 1 150
请你统计连续2天及以上在该店铺购物的用户及其对应的次数(若有多个用户,按user_id升序排序),以上例子的输出结果如下:
user_id days_count
10 2

示例1

输入

drop table if exists sales_tb;
CREATE TABLE sales_tb(
sales_date date NOT NULL,
user_id int(10) NOT NULL,
item_id char(10) NOT NULL,
sales_num int(10) NOT NULL,
sales_price int(10) NOT NULL
);

INSERT INTO sales_tb VALUES('2021-11-1', 1, 'A001',  1, 90);
INSERT INTO sales_tb VALUES('2021-11-1', 2, 'A002',  2, 220);
INSERT INTO sales_tb VALUES('2021-11-1', 2, 'B001',  1, 120);
INSERT INTO sales_tb VALUES('2021-11-2', 3, 'C001',  2, 500);
INSERT INTO sales_tb VALUES('2021-11-2', 4, 'B001',  1, 120);
INSERT INTO sales_tb VALUES('2021-11-3', 5, 'C001',  1, 240);
INSERT INTO sales_tb VALUES('2021-11-3', 6, 'C002',  1, 270);
INSERT INTO sales_tb VALUES('2021-11-4', 7, 'A003',  1, 180);
INSERT INTO sales_tb VALUES('2021-11-4', 8, 'B002',  1, 140);
INSERT INTO sales_tb VALUES('2021-11-4', 9, 'B001',  1, 125);
INSERT INTO sales_tb VALUES('2021-11-5', 10, 'B003',  1, 120);
INSERT INTO sales_tb VALUES('2021-11-5', 10, 'B004',  1, 150);
INSERT INTO sales_tb VALUES('2021-11-5', 10, 'A003',  1, 180);
INSERT INTO sales_tb VALUES('2021-11-6', 11, 'B003',  1, 120);
INSERT INTO sales_tb VALUES('2021-11-6', 10, 'B004',  1, 150);

输出

10|2
with t1 as (
select distinct sales_date,user_id
from sales_tb
where month(sales_date)=11
),t2 as (
select sales_date,user_id,row_number() over(partition by user_id order by sales_date) as rk
from t1
),t3 as (
select user_id,date_sub(sales_date,interval rk day) as diff,count(*) as num
from t2
group by 1,2
having count(*)>=2
)
select user_id,num as days_count
from t3
order by 1

发表于 2025-10-14 13:03:05 回复(0)
 
with daily_user_purchase as
(
    select
        distinct sales_date
        , user_id
    from sales_tb
    where date_format(sales_date, '%Y-%m') = '2021-11'
)
select
    user_id
    , count(grp) as days_cnt
from
(
    select 
        user_id
        , sales_date - row_number() over(partition by user_id order by sales_date) as grp
    from daily_user_purchase
) as tmp
group by user_id
    , grp
having count(grp) >= 2
order by user_id
;


  1. 使用的是连续登录天数的思路
  2. 先对用户购买记录表进行去重,去重掉同一天有多条购买记录的用户
  3. 将每个用户的购买日期进行升序排名,将购买日期减去这个排名获得一个差值列,如果多个日期之间是连续购买的,这个差值列的值就会相同
  4. 写一个子查询,按照user_id和差值列进行分组,对差值列进行计数就得到了连续购买天数,写一个having对连续购买天数在2天及以上的数据进行筛选
发表于 2025-09-30 10:13:10 回复(0)
with user as(
    select distinct user_id, sales_date,
    sales_date - interval dense_rank() over( partition by user_id order by sales_date) day dt
    from sales_tb
    where sales_date between '2021-11-01' and '2021-11-30'
)
select user_id,count(*) days_count
from user
group by user_id,dt
having days_count >1
order by user_id
此题是一个常见的连续登陆日期题,需注意去重后,对日期进行排序,连续登陆时,日期减排序为相同值。不过这题有点漏洞,若某人此月内先连续登4天,间隔一天后连续登陆5天,是希望输出5(最大连续登陆)还是4和5分别输出
发表于 2025-09-10 17:35:16 回复(0)

select user_id,(count(*)+1) days_count

from (

    select user_id, sales_date,

    lead(sales_date,1)over(partition by user_id order by sales_date) late_date

    from sales_tb

)t1

where datediff(late_date,sales_date) = 1

group by user_id,sales_date

order by user_id;

发表于 2024-12-04 16:17:04 回复(0)
select user_id,count(distinct sales_date) as ck
from sales_tb
group by user_id
having count(distinct sales_date) >= 2
order by user_id
这明显错了的也能过

发表于 2024-09-29 22:27:28 回复(0)
with t0 as(
select
sales_date,
user_id
from 
sales_tb
group by 1,2)

select

user_id,
count(user_id) as days_count

from(

select
date1,
user_id,
DATE_ADD(date1, INTERVAL -rk DAY) as date2


from(
select
sales_date as date1,
user_id,
row_number()over(partition by user_id order by sales_date) as rk

from
t0) as t1
) as t2

group by 1
having count(user_id)>1

发表于 2024-09-27 15:03:22 回复(0)
with t1 as (
select user_id, sales_date,
dense_rank()over(partition by user_id order by sales_date) rk
from sales_tb
)
,t2 as (
select user_id, sales_date,
dense_rank()over(partition by user_id, date_sub(sales_date, interval rk day) order by sales_date) days
from t1
)

select user_id, max(days) days_count from t2
group by user_id
having days_count >= 2
order by user_id


发表于 2024-09-24 15:05:38 回复(0)
-- 第一步:从 sales_tb 表中获取唯一的 sales_date 和 user_id
WITH
    users_tb AS (
        SELECT DISTINCT
            sales_date,
            user_id
        FROM
            sales_tb
    ),

-- 第二步:为每个用户按 sales_date 生成行号 user_rank
    rank_users_tb AS (
        SELECT
            sales_date,
            user_id,
            ROW_NUMBER() OVER (
                PARTITION BY
                    user_id
                ORDER BY
                    sales_date
            ) user_rank
        FROM
            users_tb
    ),

-- 第三步:计算每个用户从第一个销售日期开始的 beg_dt
    date_users_tb AS (
        SELECT
            sales_date,
            user_id,
            DATE_SUB(sales_date, INTERVAL user_rank DAY) beg_dt
        FROM
            rank_users_tb
    ),

-- 第四步:为每个用户按 beg_dt 生成新的行号 days
    day_users_tb AS (
        SELECT
            sales_date,
            user_id,
            ROW_NUMBER() OVER (PARTITION BY user_id, beg_dt ORDER BY sales_date) days
        FROM
            date_users_tb
    )

-- 最终查询:计算每个用户的最大连续销售天数,且这些天数要大于等于2
SELECT 
    user_id,
    MAX(days) AS days_count
FROM day_users_tb
WHERE days >= 2
GROUP BY user_id;

发表于 2024-07-19 14:26:03 回复(0)
with date_table as
    (select sales_date, user_id
        from sales_tb
      group by sales_date, user_id)

select a.user_id, count(a.sales_date) days_count
    from date_table a left join date_table b
    on (a.sales_date = date_sub(b.sales_date, interval 1 day) and a.user_id = b.user_id)
    group by user_id
    having sum(b.sales_date is not null) > 0

思路:先建立一个CTE,包含不重不漏的购买日期, user_id字符
将两个CTE做left_join, 条件是右边的CTE的日期是左边的CTE + 1
这时候按user_id group 之后, 可以统计出天数和右边的CTE非空的数量,只保留不全为空的用户
发表于 2024-07-13 22:30:43 回复(0)
-- 思路:所有用户购买过的日期,根据购买日期dense_rank再使用做差法统计出连续购买的日期分组,用户下有几个相同的做差日期,就是连续工作了几天。再筛选≥2天的

select user_id,days_count
from (--
select
user_id,day_,count(day_) days_count
from (--
select user_id,sales_date
,date_sub(sales_date,interval day_dense_rank day) day_
,当日购物次数
from (--
select
user_id,sales_date
,dense_rank() over(partition by user_id order by sales_date asc) day_dense_rank
,当日购物次数
from (--
select user_id,sales_date,count(user_id) 当日购物次数
from sales_tb
group by user_id,sales_date
) a) b) c
group by user_id,day_
having count(day_)>=2) t
;

发表于 2024-07-11 14:43:40 回复(0)
select user_id,max(days_count) days_count
from(
select user_id,count(*) days_count,dt
from(
select distinct sales_date,user_id
,sales_date-dense_rank() over(partition by user_id order by sales_date) dt
from sales_tb) t1
group by user_id,dt
having count(*)>=2) t2
group by user_id,dt
order by 1 

发表于 2024-06-07 10:03:16 回复(0)
可算是会一题了
WITH A AS(
    SELECT user_id, sales_date - rk AS cd
    FROM(
    SELECT DISTINCT user_id, sales_date, DENSE_RANK()OVER(PARTITION BY user_id ORDER BY sales_date ASC) AS rk 
    FROM sales_tb
    ) AS subq
), B AS(
    SELECT user_id, COUNT(*) AS cc
    FROM A
    GROUP BY user_id, cd
)
SELECT * 
FROM B 
WHERE cc >= 2
ORDER BY user_id


发表于 2024-04-29 12:44:53 回复(0)
select 
    user_id,
    count(sales_date) days_cnt
from(
    select
        user_id,
        sales_date,
        sales_date - interval (rk-1) day as fday
    from(
        select
            distinct
            user_id,
            sales_date,
            dense_rank() over(partition by user_id order by sales_date) as rk
        from
            sales_tb
    )t1
)t2
group by 
    user_id,
    fday
having 
    days_cnt >= 2
order by
    user_id

编辑于 2024-04-18 10:06:33 回复(0)
思路:开窗对每一个日期进行排序得到位次,然后日期和位次做差(date_sub)得到新的日期,若新日期相等,则相等的日期个数即为连续登录天数
比如日期11-01,11-02,11-03,    11-05,11-06
排序得到他们的位次为1,2,3,     4,5
做差得到日期10-31,10-31,10-31,    11-1,11-1
因此10-31有三个,表明3天连续登录
with
t as # 用户分组,按照登陆日期开窗排序得到每一个日期的位次
(
select
    uid
    ,dt
    , dense_rank() over(partition by uid order by dt) as rk
from 
   (select distinct *  # 去重,因为用户可能一天登录几次
   from 
        (select sales_date as dt, user_id as uid 
        from sales_tb 
        where date_format(sales_date, '%Y-%m')='2021-11')t #筛选出每一个用户的登录日期
    )t
),
t1 as  # 日期和位次做差,得到一个新的日期day_tag
(
select 
    uid
    , date_sub(dt, interval rk day) as day_tag 
from t
),
t2 as # 按照用户和day_tag分组,并计数相同day_tag有多少(连续登录天数)
(
select 
    uid, count(day_tag) as day_tag
from t1
group by uid, day_tag
)

# 按照用户分组,max()得到最大的连续登录天数
select uid, max(day_tag) 
from t2
group by uid
having max(day_tag)>1;


发表于 2024-02-14 17:06:17 回复(0)
select user_id, max(days_count) as days_count
from (
select user_id, count(date_sub(sales_date, interval rk day)) as days_count
from (
select distinct user_id, sales_date, dense_rank() over(partition by user_id order by sales_date asc) as rk
from sales_tb ) a
group by user_id
having days_count >= 2
) a
group by user_id
order by user_id asc
编辑于 2024-01-22 14:46:27 回复(0)
SELECT user_id,
count(distinct st1.sales_date)+1 as days_count
from sales_tb st1 join sales_tb st2 using(user_id)
where  DATEDIFF(st2.sales_date,st1.sales_date)=1
group by user_id order by user_id asc;
这个题目还是有点意思,容易出错
发表于 2024-01-15 23:02:00 回复(0)
with t1 as (
    select  distinct user_id,sales_date
    from sales_tb
)
,
t2 as (
    select  user_id,
            row_number() over (partition by user_id order by sales_date) rk 
    from t1
)
select user_id,max(rk)
from t2 
where rk>=2
group by user_id

发表于 2023-10-09 18:47:25 回复(1)
select uf,count(n)
from 
(select (row_number() over (order by sales_date) - row_number() over (partition by uf order by sales_date)) as n,
uf,sales_date
 from(
select distinct
    user_id as uf,
    sales_date
from
    sales_tb
order by
    sales_date) as t1) t2
group by uf
having count(n)>=2

发表于 2023-08-22 11:33:12 回复(0)