玩了几天,劳逸结合,继续复习刷题sql
一、条件函数
1.题目:现在运营想要将用户划分为25岁以下和25岁及以上两个年龄段,分别查看这两个年龄段用户数量(age为null 也记为 25岁以下)
user_profile
期望结果:
涉及知识:
需要使用case函数,case函数是一种分支函数,可以根据条件表达式返回多个可能的结果中的一个。可用在人任何允许使用表达式的地方,当不能单独使用一个语句执行。
简单case函数
计算测试表达式,按从上到下的书写顺序将测试表达式的值与每个where子句的简单表达式进行比较。如果某个简单表达式的值与测试表达式的值相等,则返回第一个匹配的when子句,如果所有表达式的值与测试表达式的值都不相等,若指定了else子句,则返回else子句中指定结果的值,若没有指定else子句,则返回NULL
搜索case函数
按上到下的书写顺序计算每个when子句的布尔表达式。返回第一个取值为true的布尔表达式所对应的结果表达式的值。如果没有取值为true的布尔表达式,且当指定了else子句时,返回else子句指定的结果,如果没有指定else子句,则返回null
SELECT CASE WHEN age < 25 OR age IS NULL THEN '25岁以下'
WHEN age >= 25 THEN '25岁及以上'
END age_cut,COUNT(*)number
FROM user_profile
GROUP BY age_cut
select
if (age >= 25, "25岁以上", "25岁以下") AS age_cut,
count(*) as number
from
user_profile
group by
age_cut;
二、日期函数
1.题目:现在运营想要计算出2021年8月每天用户练习题目的数量,请取出相应数据。
question_practice_detail
期望结果:
涉及知识:
由于涉及到时间,可以直接使用day() month() year()函数,由于是计算八月每天练题数,所以需要按照date时间分隔,由于具体指定了月份可以使用where
select
day(date) day,
count(question_id) question_cnt
from
question_practice_detail
where
month(date) = 8
and year(date) = 2021
group by
date
三、文本函数
1.题目:统计每种性别的人数
user_submit
期望结果:
涉及知识:
可以使用substring_index(str,delim,count)
str:要处理的字符串
delim:分隔符
count:计数
count如果为正数,则从左到右,第n个分隔符的左边全部内容。如果count为负数,则从右往左数,第n个分隔符的右边所有内容。
例子:str=www.baidu.com
sunstring_index(str,' . ',1)
结果:www
sunstring_index(str,' . ',-2)
结果:baidu.com
select
substring_index (profile, ',', -1) gender,
count(*) number
from
user_submit
group by
gender
使用substring_index来截取最后一个字段,性别 gender,然后统计gender的数量,最后再根据gender分组
涉及知识:
可以使用like函数进行模糊匹配 %表示占位符,再使用if进行判断,如果profile字段中含有female字段,则为female,否则为male 表示为gender,再用count统计数量。因为需要统计每种性别的人数,所以使用gender来分组。
select
if (profile like '%female', 'female', 'male') gender,
count(*) number
from
user_submit
group by
gender
四、窗口函数
题目:现在运营想要找到每个学校gpa最低的同学来做调研,请你取出每个学校的最低gpa。
期望结果:
首先可以先获取每个学校最低gpa,可以使用min函数和group分组,分别得到每个学校最低的gpa
解法1:由于还需要获取device_id,所以需要再获取其中的值。再用where字段 和(university和gpa)
select
device_id,
university,
gpa
from
user_profile
where
(university, gpa) in (
select
university,
min(gap)
from
user_profile
group by
university
)
order by
university
解法2:
涉及知识:
窗口函数涉及到组内排名需要涉及到sql的高级功能窗口函数。窗口函数也叫OLAP函数
窗口函数的基本语法:
<窗口函数> over (partition by <用于分组的列名>
order by <用于排序的列名>)
窗口函数可以放两种函数:
1. 专用窗口函数:rank,dense_rank,row_number专用窗口函数
2. 聚合函数,sum,avg,max,min等
因为窗口函数是对where或者group by子句处理后的结果进行操作,所以窗口函数原则上只能写在select子句中。
partion by用来对表分组
order by子句是对于分组后的结果进行排序
之前已经有group by的子句分组功能,为什么还需要窗口函数。
group by分组汇总后改变了表的行数,一行一个类别。而partion函数不会减少原表的行数。
其他窗口函数:
rank,dense_rank,row_number区别?
select *,
rank() over (order by 成绩 desc) as ranking,
dense_rank() over (order by 成绩 desc) as dese_rank,
row_number() over (order by 成绩 desc) as row_num
from 班级表
rank函数:为5位、5位、5位、8位,也就是如果有并列名次的行,会占用下一名次的位置。
dense_rank:为5位、5位、5位、6位,如果有并列名次,不占用下一名次位置。
row_num函数:为5位、6位、7位、8位,就是不考虑并列名次的情况。
题解:
首先使用row_num函数进行排序,以学校为分组,然后以学校分组进行排名,再用where筛选需要的名次
select
*,
row_number() over (
partition by
university
order by
gpa
) as rn
from
user_profile
由于题目要求最后需要按照学校排名,所以最后使用oder by,因为是使用最后一名,所以使用cn排名为1的,因为排序默认为升序。
select
device_id,
university,
gpa
from
(
select
*,
row_number() over (
partition by
university
order by
gpa
) as rn
from
user_profile
) as univ_min
where
rn = 1
order by
university;