SQL进阶day9————聚合与分组

news2025/1/20 1:42:34

 

目录

1聚合函数

1.1SQL类别高难度试卷得分的截断平均值

1.2统计作答次数

1.3 得分不小于平均分的最低分

2 分组查询

2.1平均活跃天数和月活人数

2.2 月总刷题数和日均刷题数

2.3未完成试卷数大于1的有效用户

1聚合函数

1.1SQL类别高难度试卷得分的截断平均值

我的错误代码:截断平均值是有专门的函数吗?

select tag,difficulty,avg(score) clip_avg_score
from examination_info ei join exam_record
using(id)
group by tag
where tag = 'SQL' and difficulty='hard'
and score not in (max(score),min(score))

我的思路改正:用 (全部值 - 最大值 - 最小值) / (总数-2) ,但是缺点就是,如果最大值和最小值有多个,这个方法就很难筛选出来

SELECT ei.tag,ei.difficulty,
       ROUND((SUM(er.score)-MIN(er.score)-MAX(er.score)) / (COUNT(er.score)-2),1) AS clip_avg_score
FROM examination_info ei join exam_record er
on ei.exam_id = er.exam_id
where ei.tag = "SQL"
AND ei.difficulty = "hard";

标准正确代码:

使用in子句将最大值和最小值排除掉,再求平均值

  • 懒人写法,可以用with...as句式将要多次使用的表只写1次即可(WITH AS 语法是MySQL中的一种临时结果集,它可以在SELECT、INSERT、UPDATE或DELETE语句中使用。通过使用WITH AS语句,可以将一个查询的结果存储在一个临时表中,然后在后续的查询中引用这个临时表。这样可以简化复杂的查询,提高代码的可读性和可维护性。但是不知道哪个MySQL版本开始支持with...as句式的,我的本地电脑里面是Navicat 15 for MySQL,不支持
  • union把max和min的结果集中在一行当中,这样形成一列多行的效果,不用多写一次代码
# t1筛选出SQL高难度的数据
WITH t1 as(
    SELECT er.*,ei.tag,ei.difficulty
    FROM exam_record er INNER JOIN
    examination_info ei
    ON er.exam_id = ei.exam_id
    WHERE tag = "SQL" and difficulty = "hard"
)

# 在t1的基础上计算均值
SELECT tag,difficulty,round(avg(score),1)
FROM t1

# 用in子句将最大值和最小值排除掉,再求平均值 not in
WHERE score not in (
    SELECT max(score)
    FROM t1
    UNION
    SELECT min(score)
    FROM t1
)

Q:为什么这里where换成and也不报错,因为前面有on?那么where和on有啥区别呢,可以只有一个吗?

A:

(1)where和having是在临时表生产之后,对临时表中的数据进行过滤用的。

如SQL语句:select * form tab1 left join tab2 on (tab1.size = tab2.size) where tab2.name=’AAA’

(2) on是在生成中临时表之前就去作用的,它会在数据源那里就把不符合要求的数据给过滤掉,即是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据所以on运行的速度最快。

如SQL语句:select * form tab1 left join tab2 on (tab1.size = tab2.size and tab2.name=’AAA’)

(3)在两个表联接时才用on的,所以在一个表的时候,就剩下where跟having比较了。在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,但是where可以使用rushmore技术,而having就不能,在速度上后者要慢。

(4)  如果要涉及到计算的字段,where的作用时间是在计算之前就完成的,而having就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。   

(5) 在多表联接查询时,on比where更早起作用。系统首先由on根据各个表之间的联接条件,把多个表合成一个临时表后,再由where进行过滤,然后再计算,计算完后再由having进行过滤。

1.2统计作答次数

我的报错代码:求已完成的试卷数时应该要分组一下,exam_id

select count(er.id) total_pv,
count(er.submit_time) complete_pv,
count(t2.exam_id) complete_exam_cnt
from exam_record er,(select count(exam_id) from exam_record 
group by exam_id) t2

正确代码1:

主要在于已完成的试卷数的统计,因为这个带有条件,且需要统计聚合结果,可以使用 聚合函数与case when 结合count中是可以加条件的

select 
count(*)  total_pv,
count(score)  complete_pv,
count(distinct case when score is null then null else exam_id end)  complete_exam_cnt
from exam_record

复习case when

(1)case expr when v1 then r1 [when v2 then r2] ...[else rn] end

       例如:case 2 when 1 then 'one' when 2 then 'two' else 'more' end 返回two

       case后面的值为2,与第二条分支语句when后面的值相等相等,因此返回two

(2)case when v1 then r1 [when v2 then r2]...[else rn] end

       例如:case when 1<0 then 'T' else 'F' end返回F

       1<0的结果为false,因此函数返回值为else后面的F

正确代码2:

select count(*) as total_pv,
count(score) as complete_pv,
count(distinct exam_id,score IS NOT NULL or null) as complete_exam_cnt
# 是逗号,连接不是and连接
from exam_record

在select和count后面都可以加条件的,但是要明白内核:

count(distinct exam_id,score IS NOT NULL or null) as complete_exam_cnt (正确)

不能是

count(distinct exam_id and score IS NOT NULL or null) as complete_exam_cnt (错误,结果永远为2, 这个题只是碰巧结果为2,改一个数据就不对了)

1 用and:

(1)一般在where后筛选过滤,还是得到的满足条件的score

(2)如果在select后直接加条件判断:这里的score is not null 是判断

  • 符合条件的返回 true ,即为1
  • 不符合的返回 false ,即为0 

(3) 加上exam_id,进行and逻辑运算

  • exam_id 本身为值,可以理解为真 在 and 逻辑下,所以上一步的1,0并不会变化,后面加上or NULL,否则会把0也计算上。

(4) 在上一步的基础上去重,则只会剩下1和0

  • 经过and运算之后,只剩下一列数据,多行1和0
  • distinct 去重后,就只剩下两行数据 1 和 0

(5)所以这时候再进行count计算,结果恒为2 (两行数据)

 2 正确答案的执行逻辑:

(1)用,连接(从之前的逻辑判断,变为多列组合)

(2)这时候distinct 去重后,就不是只剩下两行数据 1 和 0,而是会把score为null也会考虑进去。

(3)结果应该是3,如果没有or NULL,就是5行了(null为0会被计数)

1.3 得分不小于平均分的最低分

 

我的代码:where后面的条件错了,但是思路大概这样。

select score min_score_over_avg 
from exam_record er join examination_info ei
on er.id = ei.id
group by exam_id
where score>=avg(score) and ei.tag = 'SQL'
order by score asc
limit 1

修改我的代码:

select er.score min_score_over_avg 
from exam_record er 
left join examination_info ei
on er.exam_id = ei.exam_id # 不是按照id连接
where  ei.tag = 'SQL' 
and score>= (SELECT avg(er.score) from exam_record er
left join examination_info ei
on er.exam_id=ei.exam_id
where ei.tag='SQL')
order by score asc
limit 1

(1)表连接是按照exam_id ,不是按照id连接 

(2)score>=某个值,这里不能直接score>=avg(score),而是应该通过表查询返回得到avg(score),然后在进行比较。

改进我的代码:

这里有表查询的部分重复了两次,可以用with...as句式将要多次使用的表命名,这样可以只写一次,多次调用。

此外,order by score asc  limit 1  可以换为min函数。

with t as
(SELECT score from exam_record er
left join examination_info ei
on er.exam_id=ei.exam_id
where ei.tag='SQL')

select min(score) min_score_over_avg 
from t 
where score>= 
(SELECT avg(t.score) from t)

2 分组查询

2.1平均活跃天数和月活人数

我的代码:此处活跃指有交卷行为,用户平均月活跃天数avg_active_days啥意思?

with t as
(select * 
from exam_record
where year(start_time)=2021)

select month(start_time) 'month',
count(submit_time) mau
from t
group by month(submit_time)

正确代码:

select DATE_FORMAT(start_time,"%Y%m") as month,
round(count(distinct uid,date_format(start_time,"%Y%m%d"))/count(distinct uid),2) as avg_active_days,
count(distinct uid) as mau
from exam_record
where submit_time is not NULL
and YEAR(submit_time) =2021
group by month;

(1)202107是用date_format函数:DATE_FORMAT(start_time,"%Y%m") as month

(2)主要难的一点是天数的计算。

到底是count(distinct uid,date_format(start_time,"%Y%m%d"))

还是count(start_time)作为分子呢

关键是理解题目的意思是:天数。

假设一个uid 比如1001在2021-07-06这一天有二个记录,如果是count(start_time)那么就是天数是2,但是如果是count(distinct uid,date_format(start_time,"%Y%m%d"))天数就是1了

复盘探索:

(1)先找出2021年,活跃的用户ID和时间(具体到哪天)

(2)如果不考虑uid,直接按照活跃时间去重,那么不同用户在同一天活跃记录会被去重到只剩下1条,

(3)同理,如果只安装用户ID去重,那么同一用户在不同天的记录也会被去重到只有1条。这里查询的实际是月活跃的用户有哪些。

(4) 所以要去重的目的是,同一个用户,在同一天,重复提交活跃多次的记录。(因为这里是按天算,同一天同一个用户只算一次。)

(5)用户平均月活跃天数=月活跃天数 /月活跃用户

:count(distinct uid,date_format(start_time,"%Y%m%d"))/count(distinct uid)

月活跃天数:

月活跃用户: 

2.2 月总刷题数和日均刷题数

我的代码:分组好像报错,后面那个求总数我也不知道咋整

分组报错问题:MySQL提供了any_value()函数来抑制ONLY_FULL_GROUP_BY值被拒绝

select 
date_format(submit_time,'%y%m') submit_month,
count(score) month_q_cnt,
count(score)/day(month(submit_time)) avg_day_q_cnt
from practice_record
group by date_format(submit_time,'%y%m%d') 
having year(submit_time)=2021

(1)当月天数求错了,我是想先求出当前月,再求出当月天:这样操作结果是不对的。

    

应该用last_day函数求出最后一天,然后用day函数求出这个日期的天数。

复习【日期时间函数】

●   year(date)——获取年的函数

●   month(date)——获取月的函数

●   day(date)——获取日的函数

●   date_add(date,interval expr type)——对指定起始时间进行加操作

●   date_sub(date,interval expr type)——对指定起始时间进行减操作

●   datediff(date1,date2)——计算两个日期之间间隔的天数

●   date_format(date,format)——将日期和时间格式化

代码改正:

select 
date_format(submit_time,'%y%m') submit_month,
any_value(count(score)) month_q_cnt,
any_value(round(count(score)/day(last_day(submit_time)),3)) avg_day_q_cnt
from practice_record
where year(submit_time)='2021'
# where date_format(submit_time,'%y')='2021'
group by submit_month

该年的总体情况,可以用union all来连接,完整代码:

select date_format(submit_time,'%Y%m') submit_month,
any_value(count(question_id)) month_q_cnt,
any_value(round(count(question_id)/day(LAST_DAY(submit_time)),3)) avg_day_q_cnt 
from practice_record
where date_format(submit_time,'%Y')='2021'
group by submit_month
union all
select '2021汇总' as submit_month,
count(question_id) month_q_cnt,
round(count(id)/31,3) avg_day_q_cnt
from practice_record
where date_format(submit_time,'%Y')='2021'
order by submit_month;

复习:

1、区别1:取结果的交集

1)union: 对两个结果集进行并集操作, 不包括重复行,相当于distinct, 同时进行默认规则的排序;

2)union all: 对两个结果集进行并集操作, 包括重复行, 即所有的结果全部显示, 不管是不是重复;

2、区别2:获取结果后的操作

1)union: 会对获取的结果进行排序操作

2)union all: 不会对获取的结果进行排序操作

3、总结

union all只是合并查询结果,并不会进行去重和排序操作,在没有去重的前提下,使用union all的执行效率要比union高。

2.3未完成试卷数大于1的有效用户

我的代码:罗里吧嗦答案还不对。。

with t as
(select uid,er.exam_id,start_time,submit_time,tag
from exam_record er , examination_info ei
where er.exam_id=ei.exam_id
and date_format(start_time,'%Y')='2021')

select uid,
(select count(submit_time) from t
where submit_time is NULL) incomplete_cnt,
(select count(submit_time) from t
where submit_time is not NULL) complete_cnt
from t
where (select count(submit_time) from t
where submit_time is NULL)<5 

and (select count(submit_time) from t
where submit_time is not NULL)>1
order by incomplete_cnt

我的代码改正:

select uid,
sum(case when submit_time is NULL then 1 else 0 end ) incomplete_cnt,
sum(case when submit_time is NULL then 0 else 1 end ) complete_cnt
from exam_record er join examination_info ei
on er.exam_id=ei.exam_id
where date_format(start_time,'%Y')='2021'
group by uid
having incomplete_cnt >1 and incomplete_cnt<5 and complete_cnt>1
order by incomplete_cnt

接下来是detail,作答过的试卷tag集合,是提交日期:类型;一直重复显示

我的完整代码:

select uid,
sum(case when submit_time is NULL then 1 else 0 end ) incomplete_cnt,
sum(case when submit_time is NULL then 0 else 1 end ) complete_cnt,
group_concat(DISTINCT concat_ws(':',date_format(start_time,"%Y-%m-%d"),tag) order by start_time Separator ';') detail

from exam_record er join examination_info ei
on er.exam_id=ei.exam_id
where date_format(start_time,'%Y')='2021'
group by uid
having incomplete_cnt >1 and incomplete_cnt<5 and complete_cnt>1
order by incomplete_cnt desc

注意:select后面的属性,不管计算了多长,每个之间都要有逗号!!! 

大佬代码:

SELECT uid,
SUM(CASE WHEN submit_time IS NULL THEN 1 ELSE 0 END) "incomplete_cnt",
SUM(CASE WHEN submit_time IS NULL THEN 0 ELSE 1 END) "complete_cnt",
group_concat(distinct concat_ws(':',date(start_time),tag) 
order by start_time separator ';') as detail
FROM exam_record er INNER JOIN
examination_info ei 
ON er.exam_id = ei.exam_id
WHERE year(start_time) = 2021
GROUP BY uid
HAVING complete_cnt >= 1 AND incomplete_cnt > 1 AND
incomplete_cnt < 5
ORDER BY incomplete_cnt desc

其中

(1)用sum和case when函数来求完成和未完成的试卷数

(2)detail的实现是用concat_ws或者concat函数将submit_time和tag连接并且同时distinct:

函数group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator'分隔符'])

concat()函数

  • 功能:将多个字符串连接成一个字符串。

  • 语法:concat(str1, str2,…)

  • 返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。

concat_ws()函数

  • 功能:和concat()一样,将多个字符串连接成一个字符串,但是可以一次性指定分隔符(concat_ws就是concat with separator)
  • 语法:concat_ws(separator, str1, str2, …)
  • 说明:第一个参数指定分隔符。需要注意的是分隔符不能为null,如果为null,则返回结果为null。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1790168.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云动态摘要 2024-06-05

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 [1元/年起]618大促-对象存储分会场 腾讯云 2024-06-03 对象存储限时破价秒杀&#xff0c;标准存储新老同享历史低价&#xff0c;新客首单低至1元&#xff0c;爆款资源包低于2折购 云服务器…

安全测试用例及解析(Word原件,直接套用检测)

5 信息安全性测试用例 5.1 安全功能测试 5.1.1 标识和鉴别 5.1.2 访问控制 5.1.3 安全审计 5.1.4 数据完整性 5.1.5 数据保密性 5.1.6 软件容错 5.1.7 会话管理 5.1.8 安全漏洞 5.1.9 外部接口 5.1.10 抗抵赖 5.1.11 资源控制 5.2 应用安全漏洞扫描 5.2.1 应用安全漏洞扫描 5.3…

王道408数据结构CH2_线性表

概述 2 线性表 2.1 基本操作 2.2 顺序表示 线性表的元素从1开始&#xff0c;数组元素下标从0开始 2.2.1 结构体定义 #define Maxsize 50typedef struct{ElemType data[Maxsize];int length; }SqList;#define Initsize 100typedef struct{ElemType *data;int Maxsize ,length;…

基于EasyX的贪吃蛇小游戏 - C语言

游戏基本功能演示&#xff1a; 1.主菜单界面 2.自定难度界面 在这里可以自行设定游戏的难度&#xff0c;包括蛇的移动速度&#xff0c;初始节数&#xff0c;以及默认模式&#xff0c;参考线&#xff08;网格&#xff09;。这些设定的数据都会在右上角的游戏属性栏中实时显示。…

十、结果处理器

这一章和上一章参数处理器类似 首先是在XML解析的时候&#xff0c;顺便解析resultMap和resultType&#xff0c;一般更多的可能用的是resultType&#xff0c;为了实现统一&#xff0c;使用 resultType 的情况下&#xff0c;Mybatis也会创建一个resultMap实体类映射。 使用的时…

云服务器安装宝塔Linux面板全流程,新手教程!

云服务器如何宝塔Linux面板&#xff1f;阿小云以阿里云服务器为例安装宝塔Linux面板全流程&#xff0c;非常简单&#xff1a; 使用阿里云服务器安装宝塔面板教程&#xff0c;阿里云服务器网以CentOS操作系统为例&#xff0c;安装宝塔Linux面板&#xff0c;先远程连接到云服务器…

化栈为队00

题目链接 化栈为队 题目描述 注意点 只能使用标准的栈操作假设所有操作都是有效的 解答思路 使用两个栈模拟队列&#xff0c;第一个栈stk1是按正常栈顺序存储元素&#xff0c;第一个栈stk2是按队列顺序存储元素&#xff0c;初始入栈都是将元素添加到stk1中&#xff0c;当需…

【漯河市人才交流中心_登录安全分析报告-Ajax泄漏滑动距离导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

有哪些好用的ai工具,可以提升科研、学习、办公等效率?

最近&#xff0c;Sora的诞生为AI再添了一把火。 据介绍&#xff0c;这款“文生视频”的Sora可以直接输出长达60秒的视频&#xff0c;并且包含高度细致的背景、复杂的多角度镜头&#xff0c;以及富有情感的多个角色。 不仅能准确呈现细节&#xff0c;还能理解物体在物理世界中…

纷享销客BI典型场景案例解析

本章以具体案例来说明纷享销客一体化BI智能分析平台为企业在实际使用过程中带来的价值。 1)场景一&#xff1a;销售经理想要在周会上关注各销售人员的客户及订单情况&#xff0c;并在每周一上午9点可以把上周的整体情况周期性的将报表推送给相关销售人员。 具体图表展示样式及…

开关电源基本原理1

目录 内容概述 关于电感 认识电感 电感充电 电感储能 电感充电 电感参数 电感放电 利用电感升压 电感电流波形 伏秒法则 电流纹波率 电感电流三种导电模式 电流纹波率与频率的关系 电流纹波率与电感值的关系 电感值与电感体积 电路纹波率r的最优值 电感值与电…

【面经】亚信科技面试问题合集

下述内容经搜寻广大平台的面试经历&#xff0c;整理汇合得出&#xff0c;答案来自chatgpt&#xff0c;加黑的地方意味着出现多次。 1.自我介绍 2.介绍项目功能 3.和equals的区别。八大基本类型&#xff08;byte,char,int ,long,double,float,boolean,short) 是用于比较两个…

纷享销客BI智能分析平台常见问题QA

Q1在驾驶舱中查看图表时&#xff0c;图表间有什么动态交互吗? A&#xff1a;驾驶舱支持图表本身下钻&#xff0c;图表间联动&#xff0c;并且支持图表下钻的同时联动&#xff0c;可以基于驾驶舱的这个功能&#xff0c;实现图表间的动态交互。 Q2基于客户主题创建的统计图&…

短视频系列内容生产技能提升 沈阳短视频剪辑培训

优势&#xff1a;一、短视频系列化内容的优势 ①可持续性强 某一条视频效果很好(几十万点赞)时&#xff0c;按照相同格式继续输出非常容易成功: √不需要设计脚本&#xff1b; √不需要重新定制。 √稳定性强&#xff0c; ②节约时间成本和制作成本 举例对标账号&#xf…

Python | mkvirtualenv命令改变虚拟环境存储位置

文章目录 1、问题引入2、解决方式 1、问题引入 使用mkvirtualenv 命令创建虚拟环境时&#xff0c;默认创建位置在C:\Users你的计算机名目录下&#xff0c;采用下面的方式可以修改虚拟环境存储位置&#xff0c;默认创建位置是Python内置写好的&#xff0c;默认是这样的。 2、解…

Java项目:95 springboot班级回忆录的设计与实现

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本管理系统有管理员和用户。 本海滨学院班级回忆录管理员功能有个人中心&#xff0c;用户信息管理&#xff0c;班委信息管理&#xff0c;班级信息管理…

揭秘2024最新版会声会影旗舰版本功能,下载即享专业编辑

在如今这个数字化时代&#xff0c;视频编辑已经成为了许多人生活中不可或缺的一部分。无论是专业的影视制作人员&#xff0c;还是普通的短视频爱好者&#xff0c;都希望能够找到一款功能强大、操作简便的视频编辑软件。而今天&#xff0c;我要为大家介绍的这款产品——会声会影…

60秒,手把手教会你!做抖音小店怎么上架商品?

哈喽~我是电商月月 很多新手朋友做抖店&#xff0c;兴致冲冲选好商品结果傻眼了&#xff01;不知道怎么上架操作啊&#xff01; 别着急&#xff0c;今天月月就给大家讲一讲抖音小店是怎么上架商品的&#xff0c;其中有两点&#xff0c;一定要特别注意&#xff01;【有违规的规…

Vue.js 动画与过渡效果实战

title: Vue.js 动画与过渡效果实战 date: 2024/6/4 updated: 2024/6/4 description: 这篇文章介绍了如何在网页设计中使用过渡动画和组件效果&#xff0c;以及如何利用模式和列表展示信息。还提到了使用钩子实现组件间通信的方法。 categories: 前端开发 tags: 过渡动画组件…

【力扣】不相交的线

一、题目描述 二、题目解析 根据上图及题目给出的示例&#xff0c;我们不难发现&#xff0c;我们其实要找的就是两个数组中的最长公共子序列的长度。 因此&#xff0c;本题我们就可以直接转化为求两个数组中的最长公共子序列的长度。 对于 最长公共子序列问题&#xff0c;可…