题解 | #月总刷题数和日均刷题数#

月总刷题数和日均刷题数

http://www.nowcoder.com/practice/f6b4770f453d4163acc419e3d19e6746

开始的想法

开始就想着先算出来然后最后一行用union加上

就遇到了个问题:

计算平均

这里开始我的想法就是计算这个月与下个月之间的日期差datediff然后发现没办法用,要求两个都是date类型,怎么把下个月表示出来是个问题,除非两次转换,所以就放弃了

last_day()

然后看到一个神奇的函数就是last_day()返回参数日期的最后一天那再用day不就能获取这个月的天数了嘛

也就是day(last_day(subnit_time))

select 
DATE_FORMAT(submit_time,'%Y%m') as submit_month,
count(*) as month_q_cnt,
round(count(*) / day(last_day(submit_time)) ,3) as avg_day_q_cnt
from practice_record 
and year(submit_time) = '2021'
group by DATE_FORMAT(submit_time,'%Y%m')

union all 

select 
'2021汇总' as submit_month,
count(*) as month_q_cnt,
round(count(*) /31 ,3) as avg_day_q_cnt -- /30 会不通过用例
from practice_record where score is not null 
and year(submit_time) = '2021' 

order by submit_month ;
    

再然后就做好了嘛,就看看题解,发现了这两个东西

SELECT
    coalesce(DATE_FORMAT(submit_time,"%Y%m"),'2021汇总') submit_month,
    COUNT(submit_time) month_q_cnt,
    round(COUNT(submit_time) / MAX(DAY(last_day(submit_time))),3)avg_day_q_cnt
FROM
    practice_record
WHERE
    year(submit_time) = '2021'
GROUP BY
    DATE_FORMAT(submit_time,"%Y%m") WITH ROLLUP;

新知识时间

coalesce

COALESCE是一个函数,coalesce (expression_1, expression_2, ...,expression_n)依次参考各参数表达式,遇到非null值即停止并返回该值。

SQL实例

select coalesce(success_cnt, 1) from tableA

当success_cnt 为null值的时候,将返回1,否则将返回success_cnt的真实值。

select coalesce(success_cnt,period,1) from tableA

success_cnt不为null,那么无论period是否为null,都将返回success_cnt的真实值(因为success_cnt是第一个参数),当success_cnt为null,而period不为null的时候,返回period的真实值。只有当success_cnt和period均为null的时候,将返回1。

在这里题解用的是第一种,也就是当submit_time为null的时候返回一个‘2021汇总’加到最后 那最后的均值呢?

with rollup

with在sql语句中定义在group by之后。当需要对数据库数据进行分类统计的时候,往往会用上groupby进行分组。而在groupby后面还可以加入withcube和withrollup等关键字对数据进行汇总。不过这个cube在mysql中并不适用。

使用 WITH ROLLUP,此函数是对聚合函数进行求和,注意 with rollup是对 group by 后的第一个字段,进行分组计算

题目应该也是想让用这个函数因为题上给的最后平均就是总数/31而不是一年的365 or366

所以使用这个函数刚好可以

全部评论
因为不是以day(last_day())这一大堆东西进行分组的,所以一个分组里面都带有同一个月的日期,尽管对他们使用last_day之后得到的结果都是一样的30或者31,但select之前并不知道他们是一样的,导致多出了很多条记录,用聚合函数处理一下就行,min max avg都行因为是一样的
21 回复 分享
发布于 2022-07-09 21:51
会报错,SQL_ERROR_INFO: "Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'practice_record.submit_time' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by"
21 回复 分享
发布于 2022-02-26 15:51
SELECT ANY_VALUE(COALESCE(DATE_FORMAT(submit_time, '%Y%m'), '2021汇总')) AS submit_month, COUNT(submit_time) AS month_q_cnt, ROUND((COUNT(*)/MAX(day(LAST_DAY(submit_time)))), 3) FROM practice_record WHERE YEAR(submit_time)='2021' GROUP BY DATE_FORMAT(submit_time, '%Y%m') WITH ROLLUP; ANY_VALUE没有实际意义,是为了规避full_group_by约束 计算当月日期前面加MAX有两个意义,其一是为了规避full_group_by约束,二是因为题目要求最后2021汇总要除31,所以一堆30和31中用MAX可以在最后一行把31选出来,且因为分组中全都是一样的30或31所以没有影响。
16 回复 分享
发布于 2022-06-06 06:03
day(LAST_DAY())改成avg(day(LAST_DAY()))
15 回复 分享
发布于 2022-03-03 19:48
1、改成 [ ROUND(COUNT(*)/DAY(LAST_DAY(MAX(submit_time))),3) AS avg_day_q_cnt ]就不会报错了; 2、此处之所以用聚合函数MAX()将submit_time包一下(事实上,MIN\AVG\MAX都可以),是因为已经按月份进行分组了[ GROUP BY DATE_FORMAT(submit_time, '%Y%m') ]; 3、从一个角度理解,如果SQL语句中使用了GROUP BY 语句,则SELECT中只能使用常量、聚合函数或GROUP BY中用到的字段; 4、从另一个角度理解,例如,将全班50个人按性别分成两组,你可以问这两个组的性别都是什么(SELECT中使用GROUP BY用到的字段),你可以问这两个组中的总人数是多少(SELECT中使用聚合函数),你不能问第一个组的那个女生叫什么(因为GROUP BY后已经由元素的一阶状态上升为组的二阶状态了)
10 回复 分享
发布于 2022-11-01 20:07 北京
全是错的就逆天
5 回复 分享
发布于 2022-10-12 21:21 湖北
除以31这数字怎么来的
点赞 回复 分享
发布于 2022-09-07 12:29 四川
就是同样的代码当时提交有时候对有时候会报这个错,然后去找了牛客客服。。。最后就变成现在这样子只会报错了
点赞 回复 分享
发布于 2022-05-24 11:13
全都报错。。。
3 回复 分享
发布于 2022-05-09 21:44
还有!第六行and改成where
2 回复 分享
发布于 2023-11-01 17:54 北京
count(question_id) / day(last_day(max(submit_time))),中间加一个max
2 回复 分享
发布于 2022-09-22 10:20 福建
请问,with rollup,对分组后的各组记录进行求和,求和的是group by之后的第一个字段,那么为什么month_q_cnt也会得到求和计算呢?
1 回复 分享
发布于 2023-02-16 17:03 辽宁
select * from ( SELECT t1.a1 as submit_month ,t1.b1 as month_q_cnt , round(t1.b1/t2.c2 ,3) as avg_day_q_cnt FROM ( SELECT date_format( submit_time, '%Y%m' ) AS a1, count( DISTINCT uid, submit_time ) AS b1 FROM practice_record GROUP BY date_format( submit_time, '%Y%m' ) ) t1 LEFT JOIN ( SELECT DISTINCT date_format( submit_time, '%Y%m' ) AS a2, DAY ( LAST_DAY( submit_time ) ) AS c2 FROM practice_record ) t2 ON t1.a1 = t2.a2 union SELECT '2021汇总' as submit_month,count(id ), round(count(id )/31,3) FROM practice_record where date_format( submit_time, '%Y' )='2021' )q where substring( q.submit_month,1,4)='2021' order by q.submit_month
1 回复 分享
发布于 2022-09-09 14:37 浙江
因为submit_month最后一个是“2021汇总”,简单的依据date_format(submit_time,"%Y%m")分组是行不通的。下面的方法可行: select coalesce(t.sm,'2021汇总') submit_month, month_q_cnt, avg_day_q_cnt from (select date_format(submit_time,"%Y%m") sm, count(*) as month_q_cnt, round(count(*) / max(day(last_day(submit_time))),3) as avg_day_q_cnt from practice_record where date_format(submit_time,"%Y") = 2021 and score is not null group by date_format(submit_time,"%Y%m") with rollup ) t
1 回复 分享
发布于 2022-09-02 19:28 湖南
拿你最后一个代码怼进去报错
1 回复 分享
发布于 2022-05-09 13:47
将last_day 换成max
1 回复 分享
发布于 2022-04-06 14:53
聚合之后不能用day last_day,定位不到的。
点赞 回复 分享
发布于 2025-01-03 16:15 浙江
好像是group by先改变了表结构 再在select里引用原数据就会报错
点赞 回复 分享
发布于 2024-12-26 16:16 浙江
2021汇总返回的是None?
点赞 回复 分享
发布于 2024-06-24 21:56 天津
写的sql在我自己的MySQL数据库就可以完美执行,到网页端就报错。。。。。
点赞 回复 分享
发布于 2023-07-05 13:58 浙江

相关推荐

评论
222
37
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务