首页 > 试题广场 >

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

[编程题]某宝店铺连续2天及以上购物的用户及其对应的天数
  • 热度指数:30538 时间限制: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 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


发表于 今天 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)
select user_id,cnt from 
(
select
user_id,
date_sub(sales_date, interval rn day) sub_day,
count(1) cnt
from
(
select 
user_id,
sales_date,
row_number()over(partition by user_id order by sales_date) rn
from (select user_id, sales_date from sales_tb group by user_id, sales_date) t1
 ) t2
group by user_id, date_sub(sales_date, interval rn day)
) t3
where cnt>=2
order by 1;

发表于 2023-08-11 11:57:56 回复(0)
select
    t.user_id,
    max(t.cnt) as days_count
from
    (
        select
            user_id,
            dense_rank() over (
                partition by
                    user_id
                order by
                    sales_date
            ) as cnt
        from
            sales_tb
    ) t
where
    t.cnt >= 2
group by
    user_id

发表于 2023-08-11 00:11:52 回复(0)
-- step6:得到连续天最长的一组的用户编号和连续天数,最后根据用户编号升序排序
select user_id,counts as days_count
from (
	-- step5:考虑到可能有多组连续天,找到连续天最长的一组,用row_number来排序
	select *,row_number()over(partition by user_id order by counts desc) rk
	from (
		-- step4:根据差值日期和用户编号分组,计算每组的天数,天数>= 2的,则为连续2天及2天以上的
		select date_diff,user_id,count(distinct sales_date) counts
		from (
			-- step3:用销售日期减去辅助列,得到差值日期,(思路:如果差值日期相同,则代表相同的几个差值日期为连续天)
			select date_sub(sales_date,interval rk_1 day) as date_diff,user_id,sales_date
			from (
				-- step2:用row_number,添加辅助列
				select *,row_number()over(partition by user_id order by sales_date) rk_1
				from (
					-- step1:去重 用户编号 和 销售日期
					select distinct sales_date,user_id
					from sales_tb
				) a
			) a
		) a
		group by date_diff,user_id
		having count(distinct sales_date) >= 2
	) a
) a
where rk = 1
order by user_id

发表于 2023-05-31 10:16:37 回复(0)
select user_id, count(*) as days_count

from 

(select 
distinct user_id,
sales_date,
dense_rank()over(partition by user_id order by sales_date asc) as rnk,
sales_date - dense_rank()over(partition by user_id order by sales_date asc) as date_minus_rnk

from sales_tb) as t

group by user_id, date_minus_rnk
having count(*) >= 2

发表于 2023-04-23 21:01:12 回复(0)
思路:
(1)假设(user_id,sales_date)为
10 11-01
10 11-02
10 11-03
10 11-05
(2)增加一列 row_number over(partition by user_id order by sales_date)为rk
10 11-01 1
10 11-02 2
10 11-03 3
10 11-05 4
(3)增加一列 sales_date-rk 为sub_date
10 11-01 1 10-31
10 11-02 2 10-31
10 11-03 3 10-31
10 11-05 4 11-01
(4)数sub_date的个数cnt
10 10-31 3
10 11-01 1
(5)输出max(cnt)>=2的user_id以及max(cnt)
10 3


select
    user_id,
    max(cnt) as days_count
from
(
    select
        user_id,
        sub_date,
        count(1) as cnt
    from
    (
        select
            user_id,
            subdate(sales_date,rk) as sub_date 
        from
        (
            select
                user_id,
                sales_date,
                row_number() over(partition by user_id order by sales_date asc) as rk
            from
            (
                select
                    distinct user_id,
                    sales_date
                from sales_tb
            ) st
        ) tmp
    ) tmp1
    group by user_id,
        sub_date
) tmp2
group by user_id
having max(cnt) >= 2
order by user_id asc



发表于 2023-03-29 13:51:54 回复(0)
就是连续天数问题,板子题
# 就是连续天数问题,和SQL194
# 某乎问答最大连续回答问题天数大于等于3天的用户及其对应等级 思路是一样的


# 代码由chatgpt给出
# Keep in mind that MySQL user variables are deprecated since MySQL 8.0.13, so using window functions might be a better approach for future-proofing your query.

WITH sales_dates AS (
    SELECT
        sales_date,
        user_id,
        IF(sales_date = @prev_date + INTERVAL 1 DAY AND user_id = @prev_user_id, @consec_days := @consec_days + 1, @consec_days := 1) AS consec_days,
        @prev_date := sales_date,
        @prev_user_id := user_id
    FROM
        (SELECT @prev_date := NULL, @prev_user_id := NULL, @consec_days := 1) vars,
        (SELECT sales_date, user_id FROM sales_tb ORDER BY user_id, sales_date) ordered_dates
)


SELECT
    user_id,
    cast(MAX(consec_days) as unsigned)  AS days_count
FROM
    sales_dates
GROUP BY
    user_id
HAVING
    max_consec_days >= 2




发表于 2023-03-23 11:08:15 回复(0)
with t as
(select distinct user_id,
    sales_date,
    dense_rank() over(partition by user_id order by sales_date) rk
from sales_tb)

select user_id,count(1) days_count
from t
group by user_id,sales_date-rk
having count(1) >= 2
发表于 2023-03-16 23:02:52 回复(0)
  • 二维码

    扫描二维码,关注牛客网

  • 二维码

    下载牛客APP,随时随地刷题