牛客网SQL进阶127: 月总刷题数和日均刷题数

官网链接:

月总刷题数和日均刷题数_牛客题霸_牛客网现有一张题目练习记录表practice_record,示例内容如下:。题目来自【牛客题霸】https://www.nowcoder.com/practice/f6b4770f453d4163acc419e3d19e6746?tpId=240

0 问题描述

基于练习记录表practice_record,统计出2021年每个月里用户的月总刷题数month_q_cnt 和日均刷题数avg_day_q_cnt(按月份升序排序)以及该年的总体情况,示例数据输出如下:

1 数据准备

sql 复制代码
CREATE TABLE  practice_record (
    id int PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid int NOT NULL COMMENT '用户ID',
    question_id int NOT NULL COMMENT '题目ID',
    submit_time datetime COMMENT '提交时间',
    score tinyint COMMENT '得分'
)CHARACTER SET utf8 COLLATE utf8_general_ci;

INSERT INTO practice_record(uid,question_id,submit_time,score) VALUES
(1001, 8001, '2021-08-02 11:41:01', 60),
(1002, 8001, '2021-09-02 19:30:01', 50),
(1002, 8001, '2021-09-02 19:20:01', 70),
(1002, 8002, '2021-09-02 19:38:01', 70),
(1003, 8002, '2021-08-01 19:38:01', 80);

2 数据分析

方式一:union all 常规做法

sql 复制代码
-- 方式一:
select
    DATE_FORMAT(submit_time,'%Y%m') as submit_month,
    count(1)as month_q_cnt,
    round(count(1)/ max(day(last_day(submit_time))) ,3) as avg_day_q_cnt
from practice_record
where year(submit_time) = '2021'
 group by DATE_FORMAT(submit_time,'%Y%m')
union all
select
     '2021汇总' as submit_month,
     count(1) as month_q_cnt,
     round(count(1) / 31 ,3) as avg_day_q_cnt
from practice_record 
where score is not null and year(submit_time) = '2021'
order by submit_month;

上述代码用到的函数:last_day()返回参数日期的最后一天,day(last_day())返回当月的天数

ps:这里最容易出错的点在于:每月天数的计算

(1) 计算每个月的天数可以用函数:day(last_day(datetime));

(2) 一年12月,每个月的天数: case when month(datetime) in (1,3,5,7,8,10,12) then 31 else 30 end

(3) 最容易出错的点在于 : group by DATE_FORMAT(submit_time,'%Y%m') 分组后,select后面只能跟:group by 分组字段、常量、以及 count()/ max()/min()/avg()/sum()等聚合函数;

由于 count(1) / max(day(last_day(submit_time)) 中 分子count(1)用的是聚合函数,分母也必须用聚合函数,而函数day() 不是聚合函数,因此分母最终的逻辑为:max(day(last_day(submit_time)) 或min(day(last_day(submit_time))

方式二:with rollup

sql 复制代码
select coalesce(months,'2021汇总') as submit_month,
       count(question_id) as month_q_cnt,
       round(count(question_id)/max(days),3) as avg_day_cnt
from(select question_id,
            date_format(submit_time,'%Y%m') as months,
            day(last_day(submit_time)) as days
    from practice_record
    where year(submit_time)= '2021')  tmp1
group by months
with rollup;

上述代码拆解:

**step1:**利用date_format函数及day(last_day(submit_time)) 函数分别获取月份及当月的天数

sql 复制代码
select question_id,
       date_format(submit_time,'%Y%m') as months,
       day(last_day(submit_time)) as days
from practice_record
 where year(submit_time)= '2021'

step2: 利用 group by with rollup 实现分组加和, 利用ifnull/coalesce函数进行null值判断及补全:coalesce(months,'2021汇总') as submit_month

最终的代码如下:

sql 复制代码
select coalesce(months,'2021汇总') as submit_month,
       count(question_id) as month_q_cnt,
       round(count(question_id)/max(days),3) as avg_day_cnt
from(select question_id,
            date_format(submit_time,'%Y%m') as months,
            day(last_day(submit_time)) as days
    from practice_record
    where year(submit_time)= '2021')  tmp1
group by months
with rollup;

group by with rollup具体使用案例见文章:

MySQL ------group by子句使用with rollup-CSDN博客MySQL ------group by子句使用with rolluphttps://blog.csdn.net/SHWAITME/article/details/136078305?spm=1001.2014.3001.5502

3 小结

上述案例最关键的点在于:group by 分组后,select后面只能跟:

(1) groupby 分组的字段;

(2)常量;

(3) count()、 max()、 min()、avg()、sum()等聚合函数;

相关推荐
w_t_y_y19 小时前
Nginx Plus
运维·数据库·nginx
源代码•宸19 小时前
分布式缓存-GO(分布式算法之一致性哈希、缓存对外服务化)
开发语言·经验分享·分布式·后端·算法·缓存·golang
川贝枇杷膏cbppg19 小时前
dm_unknown_202512.log:达梦数据库 “未分类日志“
数据库·oracle
计算机毕设VX:Fegn089520 小时前
计算机毕业设计|基于springboot + vue图书商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
yongui4783420 小时前
MATLAB的指纹识别系统实现
算法
高山上有一只小老虎20 小时前
翻之矩阵中的行
java·算法
jghhh0120 小时前
RINEX文件进行卫星导航解算
算法
求学中--20 小时前
MySQL 数据库完整操作命令与使用指南
数据库·sql·mysql·oracle
爱思德学术21 小时前
中国计算机学会(CCF)推荐学术会议-A(计算机科学理论):LICS 2026
算法·计算机理论·计算机逻辑
CVHub21 小时前
多模态图文训推一体化平台 X-AnyLabeling 3.0 版本正式发布!首次支持远程模型推理服务,并新增 Qwen3-VL 等多款主流模型及诸多功能特性,等
算法