首页 > 试题广场 >

牛客直播开始时各直播间在线人数

[编程题]牛客直播开始时各直播间在线人数
  • 热度指数:31976 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
牛客某页面推出了数据分析系列直播课程介绍。用户可以选择报名任意一场或多场直播课。
已知课程表course_tb如下(其中course_id代表课程编号,course_name表示课程名称,course_datetime代表上课时间):
course_id course_name course_datetime
1 Python 2021-12-1 19:00-21:00
2 SQL 2021-12-2 19:00-21:00
3 R 2021-12-3 19:00-21:00
上课情况表attend_tb如下(其中user_id表示用户编号、course_id代表课程编号、in_datetime表示进入直播间的时间、out_datetime表示离开直播间的时间):
user_id course_id in_datetime out_datetime
100 1 2021-12-01 19:00:00
2021-12-01 19:28:00
100 1 2021-12-01 19:30:00
2021-12-01 19:53:00
101 1 2021-12-01 19:00:00
2021-12-01 20:55:00
102 1 2021-12-01 19:00:00
2021-12-01 19:05:00
104 1 2021-12-01 19:00:00
2021-12-01 20:59:00
101 2 2021-12-02 19:05:00
2021-12-02 20:58:00
102 2 2021-12-02 18:55:00
2021-12-02 21:00:00
104 2 2021-12-02 18:57:00
2021-12-02 20:56:00
107 2 2021-12-02 19:10:00
2021-12-02 19:18:00
100 3 2021-12-03 19:01:00
2021-12-03 21:00:00
102 3 2021-12-03 18:58:00
2021-12-03 19:05:00
108 3 2021-12-03 19:01:00
2021-12-03 19:56:00
请你统计直播开始时(19:00),各科目的在线人数,以上例子的输出结果为(按照course_id升序排序):
course_id course_name online_num
1 Python 4
2
SQL 2
3 R 1
示例1

输入

CREATE TABLE course_tb(
course_id int(10) NOT NULL, 
course_name char(10) NOT NULL,
course_datetime char(30) NOT NULL);
INSERT INTO course_tb VALUES(1, 'Python', '2021-12-1 19:00-21:00');
INSERT INTO course_tb VALUES(2, 'SQL', '2021-12-2 19:00-21:00');
INSERT INTO course_tb VALUES(3, 'R', '2021-12-3 19:00-21:00');

CREATE TABLE attend_tb(
user_id int(10) NOT NULL, 
course_id int(10) NOT NULL,
in_datetime datetime NOT NULL,
out_datetime datetime NOT NULL
);
INSERT INTO attend_tb VALUES(100, 1, '2021-12-1 19:00:00', '2021-12-1 19:28:00');
INSERT INTO attend_tb VALUES(100, 1, '2021-12-1 19:30:00', '2021-12-1 19:53:00');
INSERT INTO attend_tb VALUES(101, 1, '2021-12-1 19:00:00', '2021-12-1 20:55:00');
INSERT INTO attend_tb VALUES(102, 1, '2021-12-1 19:00:00', '2021-12-1 19:05:00');
INSERT INTO attend_tb VALUES(104, 1, '2021-12-1 19:00:00', '2021-12-1 20:59:00');
INSERT INTO attend_tb VALUES(101, 2, '2021-12-2 19:05:00', '2021-12-2 20:58:00');
INSERT INTO attend_tb VALUES(102, 2, '2021-12-2 18:55:00', '2021-12-2 21:00:00');
INSERT INTO attend_tb VALUES(104, 2, '2021-12-2 18:57:00', '2021-12-2 20:56:00');
INSERT INTO attend_tb VALUES(107, 2, '2021-12-2 19:10:00', '2021-12-2 19:18:00');
INSERT INTO attend_tb VALUES(100, 3, '2021-12-3 19:01:00', '2021-12-3 21:00:00');
INSERT INTO attend_tb VALUES(102, 3, '2021-12-3 18:58:00', '2021-12-3 19:05:00');
INSERT INTO attend_tb VALUES(108, 3, '2021-12-3 19:01:00', '2021-12-3 19:56:00');

输出

1|Python|4
2|SQL|2
3|R|1
select c.course_id,
c.course_name,
count(distinct a.user_id) online_num
from course_tb c
inner join attend_tb a on a.course_id=c.course_id
where time(a.in_datetime) <= '19:00:00'
and time(a.out_datetime) >= '19:00:00'
group by c.course_id,c.course_name
order by c.course_id
实际上这个问题就是要求取在直播开始之前就进入直播间的用户加上正好在直播开始时(19:00:00)进入直播间的用户的个数。
第一次遇到求取时间需要精确到小时分钟秒的这种题目,抱着尝试的心态直接使用了time(a.in_datetime)是可行的!
参考大家的做法给自己写个学习笔记:
第一种:
date_format(a.in_datetime,'%H:%i:%s') <= '19:00:00'
date_format(a.out_datetime,'%H:%i:%s') >= '19:00:00'
第二种:
right(a.in_datetime,8) <= '19:00:00'
right(a.out_datetime,8) >= '19:00:00'
第三种:
time(a.in_datetime) <= '19:00:00'
time(a.out_datetime) >= '19:00:00'




发表于 2021-12-04 17:08:28 回复(6)
直播开始时的在线人数:在直播开始的瞬间,或开始之前进入直播间的所有用户。

所以有:
用户的in_datetime <= 直播开始时间。

虽然答案可以写19:00:00(数据太简单。。。),但是真正的直播开始时间,是应该从course_datetime字段提取获得的:

我们考虑提取course_datetime字段的前15个字符,然后再连上 【:00】

字段的提取,有两种方法:
LEFT(course_datetime, 15)
SUBSTRING_INDEX(course_datetime, '-', 3)

(有其他方案也欢迎分享~)


SELECT
  course_id,
  course_name,
  COUNT(*) online_num
FROM 
(
  SELECT 
    user_id, 
    in_datetime,
    course_id,
    course_name
  FROM attend_tb a 
  LEFT JOIN course_tb c USING(course_id)
  WHERE in_datetime <= CONCAT(LEFT(course_datetime, 15), ':00')
) t
GROUP BY 1, 2
ORDER BY 1




发表于 2021-12-06 15:18:26 回复(7)
这题也太不严谨了,怎么可以把不同日期的19:00一起累加呢?这样的直播间在线人数还有意义吗?
发表于 2022-05-30 11:19:33 回复(3)
假设没有跨天的直播,那只需要考虑每次进入直播间的HH:mm:ss是否小于等于19:00:00,并且出直播间的HH:mm:ss是否大于等于19:00:00

select
    at.course_id,
    ct.course_name,
    count(distinct case when (substr(at.in_datetime,12,8) <= '19:00:00' and substr(at.out_datetime,12,8) >= '19:00:00') 
    then at.user_id else null end) as online_num
from attend_tb at
left join course_tb ct
on at.course_id = ct.course_id
group by at.course_id,
    ct.course_name
order by at.course_id asc


发表于 2023-03-29 14:44:16 回复(0)
简单题
# 遇事不要慌,先建一张大宽表
with total_info as(
    select ct.course_name,ct.course_datetime,
    at.*
    from course_tb ct
    left join attend_tb at
    on ct.course_id=at.course_id
)

select course_id,	course_name,
count(case when in_datetime<=course_datetime and out_datetime>=course_datetime then 1 else null end) as online_num
from total_info
group by course_id,	course_name
order by course_id asc


发表于 2023-02-24 09:35:07 回复(0)
select
course_id,
course_name,
# substr(course_datetime,1,15)
sum(if(in_datetime<=substr(course_datetime,1,15),1,0)) 
as online_num
from attend_tb a
join course_tb b using(course_id)
group by course_id,course_name
order by course_id
发表于 2022-05-18 14:45:28 回复(0)
select ct.course_id,course_name,count(user_id) online_num
from course_tb ct
left join attend_tb at on ct.course_id=at.course_id
where date(course_datetime)=date(in_datetime) and time(in_datetime) <= '19:00:00' and time(out_datetime) > '19:00:00' /*进入时间在7点前,出来时间在7点后*/
group by ct.course_id,course_name
order by ct.course_id
编辑于 2023-12-28 19:24:47 回复(0)
select c.course_id,c.course_name,count(distinct a.user_id) as online_num
from course_tb c
inner join attend_tb a
on c.course_id = a.course_id
where time(a.in_datetime) <= '19:00:00'
and time(a.out_datetime) >= '19:00:00'
group by c.course_id,c.course_name
order by c.course_id;

发表于 2022-11-20 12:40:51 回复(0)

【场景】:某时刻同时在线人数

【分类】:窗口函数、多表连接

分析思路

难点:

1.题目中说统计直播开始时的在线人数,使用小于等于。

注意窗口函数和分组函数的区别!见题解

(1)统计进入为增加人数,出去为减少人数

用tag来标记,进去增加人数1人,出去减少人数1人;然后把表连接起来

  • [使用]:union

(2)统计直播开始时(19:00),各科目的在线人数

统计直播开始时,所以要用小于等于

  • [条件]:datetime <= '19:00'

  • [使用]:窗口函数sum()

最终结果

select 查询结果 [课程号;课程名称;在线人数]
from 从哪张表中查询数据[多表]
where 查询条件 [时间小于等于19点]
order by 对查询结果排序 [课程号];

求解代码

方法一:

with子句 + 分组函数

with
    main as(
        #进入为增加人数,出去为减少人数
        select
            user_id,
            course_id,
            date_format(in_datetime,'%H:%i') as datetime,
            1 as tag
        from attend_tb
        union
        select
            user_id,
            course_id,
            date_format(out_datetime,'%H:%i') as datetime,
            -1 as tag
        from attend_tb
    )
#统计直播开始时(19:00),各科目的在线人数
select
    course_id,
    course_name,
    sum(tag) as online_num
from course_tb
left join main using(course_id)
where datetime <= '19:00'
group by course_id,course_name
order by course_id

方法二:

with子句 + 窗口函数

注意:因为有where条件不大于19:00的限制,所以窗口函数里面不需要再用order by tag desc;使用窗口函数必须去重,但是使用分组函数是course_id是唯一的,不需要去重。

with
    main as(
        #进入为增加人数,出去为减少人数
        select
            user_id,
            course_id,
            date_format(in_datetime,'%H:%i') as datetime,
            1 as tag
        from attend_tb
        union
        select
            user_id,
            course_id,
            date_format(out_datetime,'%H:%i') as datetime,
            -1 as tag
        from attend_tb
    )
#统计直播开始时(19:00),各科目的在线人数
select distinct
    course_id,
    course_name,
    sum(tag) over(partition by course_id) as online_num
from course_tb
left join main using(course_id)
where datetime <= '19:00'
order by course_id

方法三:

表连接

#统计直播开始时(19:00),各科目的在线人数
select
    course_id,
    course_name,
    sum(tag) as online_num
from course_tb
left join(
    #进入为增加人数,出去为减少人数
    select
        user_id,
        course_id,
        date_format(in_datetime,'%H:%i') as datetime,
        1 as tag
    from attend_tb
    union
    select
        user_id,
        course_id,
        date_format(out_datetime,'%H:%i') as datetime,
        -1 as tag
    from attend_tb
) main using(course_id)
where datetime <= '19:00'
group by course_id,course_name
order by course_id
发表于 2022-11-17 22:28:56 回复(0)
# 考点:日期函数的使用:date_format(日期,'%Y-%m-%d %H-%i-%s');timestampdiff(维度,小日期,大日期)

with t1 as (SELECT course_id,course_name,date_format(substring_index(course_datetime,'-',3),'%Y-%m-%d %H:%i:%s') as begin_dt FROM course_tb)

SELECT A.course_id,course_name,count(distinct user_id) as online_num
FROM attend_tb A left join t1 on A.course_id = t1.course_id
where timestampdiff(SECOND,in_datetime,begin_dt) >= 0
group by A.course_id,course_name
order by A.course_id asc

发表于 2022-08-26 10:14:43 回复(0)

不知道为什么是对的。。。

select a.course_id,course_name,
sum(if(course_datetime between in_datetime and out_datetime,1,0)) online_num
from attend_tb a
join course_tb c using(course_id)
group by a.course_id,course_name
order by a.course_id
发表于 2022-04-20 22:55:37 回复(3)
select 
	c.course_id,
	c.course_name,
	count(*) online_num
from attend_tb a
left join
course_tb c
on a.course_id=c.course_id
where date_format(in_datetime,'%H%i')<='1900' #注意判断条件,要19:00以前就在直播间的
group by 1,2
order by 1

发表于 2022-01-05 08:21:34 回复(1)
筛选条件是时点人数,一开始误解成来上课的人数了
select
    distinct t1.course_id,
    course_name,
    count(distinct(user_id)) as online_num
from course_tb t
inner join attend_tb t1
    on t.course_id=t1.course_id
where time(in_datetime)<='19:00:00'
    and time(out_datetime)>='19:00:00'
group by 1,2
order by 1


发表于 2026-05-08 20:55:59 回复(0)
日期前面还要加一个空格,我说怎么卡了我好久。
发表于 2026-03-21 11:08:11 回复(0)
select q2.course_id,q2.course_name,count(q1.user_id) online_num
from (
    select *
    from attend_tb
    where time(in_datetime)<='19:00:00' and time(out_datetime)>'19:00:00'
) q1 left join course_tb q2 on q1.course_id=q2.course_id
group by q2.course_id,q2.course_name
order by q2.course_id

发表于 2026-02-23 12:27:14 回复(0)
select
attend_tb.course_id
,course_name
,sum(if("19:00:00" between time(in_datetime) and time(out_datetime),1,0))
from attend_tb
left join course_tb
on course_tb.course_id=attend_tb.course_id
group by 1,2
order by 1
发表于 2025-12-15 14:42:14 回复(0)
select
  t1.course_id
  ,course_name
  ,online_num
from
(
    select
      course_id
      ,count(distinct user_id) as online_num
    from attend_tb
    where date_format(in_datetime,'%H-%i')<='19:00:00' and date_format(out_datetime,'%H-%i')>='19:00:00'
    group by 1
)t1
left join course_tb t2 on t1.course_id=t2.course_id
order by 1
不知道为啥不对
发表于 2025-10-17 21:43:50 回复(0)
with t1 as (
select 
x.course_id
,x.course_name
,in_datetime 
,out_datetime
from course_tb x 
join attend_tb y
using(course_id)
),t2 as (
select course_id,course_name,in_datetime as dt,1 as tag
from t1 
union all
select course_id,course_name,out_datetime as dt,-1 as tag
from t1 
),t3 as (
select course_id,course_name,dt,sum(tag) over(partition by course_id,course_name order by dt) as cnt
from t2
where time(dt)<="19:00:00"
)
select distinct course_id,course_name,last_value(cnt) over(partition by course_id,course_name order by dt rows between unbounded preceding and unbounded following) as online_num
from t3
order by 1

发表于 2025-10-14 11:23:20 回复(0)
 select
        t2.course_id,
        t2.course_name,
        sum(if(time(in_datetime)<='19:00:00',1,0)) as online_num -- 此处使用DATE_FORMAT(in_datetime, '%H:%i:%s')一样效果
    from attend_tb t1 join course_tb t2 using (course_id)
    group by t2.course_id,t2.course_name;
发表于 2025-09-29 21:14:33 回复(0)
select
    at.course_id 
    , course_name
    , count(
        case 
            when in_datetime <= left(course_datetime, 15) and out_datetime >= left(course_datetime, 15) then user_id
            end
        ) as online_num
from attend_tb at
    left join course_tb co on at.course_id = co.course_id
group by at.course_id 
    , course_name
order by course_id
;

发表于 2025-09-25 10:17:33 回复(0)

问题信息

难度:
153条回答 1410浏览

热门推荐

通过挑战的用户

查看代码
牛客直播开始时各直播间在线人数