入门sql语句-牛客刷题

Posted Python_听夏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了入门sql语句-牛客刷题相关的知识,希望对你有一定的参考价值。

基础查询

  1. 查询表所有列:
select * from user_profile;
  1. 查询表指定列数据:
select age from user_profile;
  1. 查询指定列并去重:
select 
	DISTINCT university 
from 
	user_profile;
	
select university
from user_profile 
group by university;
  1. 查询年龄数据并修改命名、输出前2条数据;
select age as new_age 
from user_profile 
limit 2;

条件查询

  1. 查询后排序
    升序:
select device_id,age 
from user_profile 
order by age;

降序:

select device_id,age 
from user_profile 
order by age desc;

查询后多列升序排序:

select device_id,gpa,age 
from user_profile 
order by gpa,age;

查询后多列降序排序;

select device_id,gpa,age 
from user_profile 
order by gpa desc,age desc;
  1. 查询除了某大学的用户信息,过滤空值
select 
	device_id, university 
from 
	user_profile 
where 
	university != '复旦大学';
#   not like '复旦大学';
#   not in ('复旦大学');
  1. 高级操作符混合
    and,or
select 
	device_id,gender,age,university,gpa 
from 
	user_profile 
where 
	gpa>3.5 and university ='山东大学' 
	or 
	gpa>3.8 and university='复旦大学';
  1. in,not in
select 
	device_id,gender,age,university,gpa 
from 
	user_profile 
where 
	university in ('复旦大学','北京大学','山东大学');
  1. 模糊查询
    查看学校名称中含北京的用户
    ——这道题主要考察的是模糊查询 字段名 like ‘匹配内容’

_ : 下划线 代表匹配任意一个字符;
% :百分号 代表匹配0个或多个字符;
[]: 中括号 代表匹配其中的任意一个字符;
[^]: ^尖冒号 代表 非,取反的意思;不匹配中的任意一个字符。

select 
	device_id,age,university
from 
	user_profile 
where 
	university like '%北京%';

tips:面试常问的一个问题:你了解哪些数据库优化技术?
SQL语句优化也属于数据库优化一部分,而like模糊查询会引起全表扫描,速度比较慢,应该尽量避免使用like关键字进行模糊查询。

select 
	device_id,age,university
from 
	user_profile 
where 
	university regexp '北京';

LIKE 和 REGEXP之间的重要差别
LIKE 匹配整个列,如果被匹配的文本在列值中出现,LIKE 将不会找到它,相应的行也不会被返回(除非使用通配符)。
而 REGEXP 在列值内进行匹配,如果被匹配的文本在列值中出现,REGEXP 将会找到它,相应的行将被返回,并且 REGEXP 能匹配整个列值(与 LIKE> 相同的作用)

高级查询

  1. 查复旦大学学生gpa最大值
# 自己排序截取
select gpa 
from user_profile 
where university = '复旦大学' 
order by gpa desc limit 1;
# 函数
select max(gpa) 
from user_profile 
where university = '复旦大学' 
  1. 计算总数和平均值(四舍五入)
select 
	count(gender) as male_num,
	round(avg(gpa),1) as avg_gpa 
from user_profile 
where gender='male';
  1. 分组计算
select
    gender, university,
    count(device_id) as user_num,
    round(avg(active_days_within_30),1) as avg_active_day,
    round(avg(question_cnt),1) as avg_question_cnt
from user_profile
group by
    gender,university;
  1. 分组过滤

题意:取出平均发贴数低于5的学校或平均回帖数小于20的学校(小数点后保留3位)

select
    university,
    round(avg(question_cnt), 3) as  avg_question_cnt,
    round(avg(answer_cnt), 3) as avg_answer_cnt	
from
    user_profile
group by
    university
having    # 聚合函数结果作为筛选条件时,不能用where,而是用having语法
    avg(question_cnt) < 5
    or avg(answer_cnt) < 20
  1. 分组排序

题意:不同大学的用户平均发帖情况,并按照平均发帖情况进行升序排列

select
    university,
    avg(question_cnt) as  avg_question_cnt
from
    user_profile
group by
    university
order by    
    avg(question_cnt)

☆☆☆ 多表查询

题意:所有来自浙江大学的用户题目回答明细情况

  1. 子查询(嵌套查询、内部查询)
    一个查询语句嵌套在另一个查询语句内的查询。

第一种:创建一张临时表用,获取浙江大学device_id对用户题目回答明细进行过滤。

select 
    device_id,
    question_id,
    result
from
    question_practice_detail
where device_id in   
	(
	select device_id 
	from user_profile 
	where university ='浙江大学'
	)
  1. 连接查询

第二种:先将两张表关联在一起,然后再筛选出浙江大学的明细数据

select
    q.device_id,
    q.question_id,
    q.result
from
    question_practice_detail q
    left join user_profile u on q.device_id = u.device_id
where
    university = '浙江大学'
  1. 连接查询——统计每个学校的答过题的用户的平均答题数

参考解题思路

  • 按每个学校统计——分组,group by
  • 用户平均答题数计算:同一用户多次登录答题,需要对用户进行去重处理
  • 两张表的连接处理
select
    u.university,
    count(q.question_id) / count(distinct q.device_id) as avg_answer_cnt
from
    question_practice_detail as q
    left join user_profile as u on q.device_id = u.device_id
group by
    u.university;
  1. 连接查询——统计每个学校各难度的用户平均刷题数(三张表)
  • 分组查询 group by
  • 计算用户平均答题量 count(question_id)/count(disinct device_id)
  • 表连接 三张表
select 
    university,
    difficult_level,
    count(q.question_id)/count(distinct q.device_id) as avg_answer_cnt
from user_profile u 
    join question_practice_detail q on q.device_id = u.device_id 
    join question_detail d on q.question_id = d.question_id
group by university, difficult_level
  1. 组合查询——查找山东大学或者性别为男生的信息
  • 限定条件:学校为山东大学或者性别为男性的用户:university=‘山东大学’, gender=‘male’;
  • 分别查看&结果不去重 :直接使用or不行,直接用union也不行,要用union all ,分别去查满足条件1的和满足条件2的,然后合在一起不去重
select
    device_id,
    gender,
    age,
    gpa
from
    user_profile
where
    university = '山东大学'
union all  # 不去重查询方式,两个条件分别查找并都展示
select
    device_id,
    gender,
    age,
    gpa
from
    user_profile
where
    gender = 'male'

常用函数

  1. 条件函数
  • 计算25岁及以上 和25岁以下 的用户数量

if语句使用:if(条件,条件真的值1,条件假的值2)

# if语句使用
select 
    if(age>=25, '25岁及以上','25岁以下') as age_cut,
    count(distinct device_id) as number
from user_profile
group by age_cut
# case 语句格式
select 
	case
		when age>=25 then '25岁及以上'
		else '25岁以下'
	end as age_cut,
    count(distinct device_id) as number
from user_profile
group by age_cut
  • 查看不同年龄段用户信息
# if语句格式
select
    device_id,
    gender,
    if (
    	age >= 25, '25岁及以上', if (age >= 20 and age <= 24, '20-24岁', '其他')
    ) as age_cut
from
    user_profile
# case 语句格式
# 	when... then... 
# 	else... 
# end as...
select
    device_id,
    gender,
    case
        when age>=25 then '25岁及以上'
        when age>=20 and age <=24 then '20-24岁'
        else '其他'
    end as 'age_cut'
from user_profile
  1. 日期函数
  • 计算用户2021年8月每天的练题数量
# 使用日期函数
select
    day (date) as ourday,
    count(question_id) as question_cnt
from
    question_practice_detail
where
    month (date) = 8 and year (date) = 2021
group by ourday
# 使用正则表达式
select
    day (date) as ourday,
    count(question_id) as question_cnt
from
    question_practice_detail
where 
    date regexp '2021-08'
group by ourday
  • 计算用户的平均次日留存率
    次日:涉及到前后两天,此处通过两个表来进行连接(自连接);
    次日留存率:有前一天记录的日期统计量/所有记录的日期统计量
select
	count(q2.device_id)/count(q1.device_id)
from 
	(select distinct device_id,date from question_practice_detail) as q1
	left join
	(select distinct device_id,date from question_practice_detail) as q2
	on q2.device_id = q1.device_id and q2.date= date_add(q1.date, interval 1 day)
# 还可以用函数 datediff(q1.date,q2.date)=1
  1. 文本函数

substring_index(str,分隔符,序号)
序号为正数,表示从左往右 截取目标分隔符之前的字符串;1, 2, 3...
序号为负数,表示从右往左 截取目标分隔符之后的字符串;-1, 2, -3...

# 复习 if 和case 逻辑语句
# 复习 like 模糊查询
# 复习 regexp 正则匹配
###############################################
select 
    if(profile regexp 'female','female','male') as 'gender',
    count(device_id) as number
from user_submit
group by gender
###############################################
select 
    if(profile like '%female','female','male') as 'gender',
    count(device_id) as number
from user_submit
group by gender
###############################################
select 
    case 
        when profile regexp 'female' then 'female'
        when profile regexp 'male' then 'male'
    end as 'gender',
    count(device_id) as number
from user_submit
group by gender

# 新学习:字符串提取函数substring_index
select
    substring_index (profile, ',', -1) as gender,
    count(device_id) as number
from user_submit
group by gender
  • 截取年龄
select
    substring_index(substring_index(profile,',',-2),',',1) as age,
    count(device_id) as number
from user_submit
group by age
  1. 窗口函数
    row_number() over() 解析
    基本功能:分组和排序功能
    语法格式: row_number() over(partition by 分组列 order by 排序列)
  • 找出每个学校分数最低的学生
# 方式一:通过子查询语句和连接语句
select
    u2.device_id,
    u1.university,
    u1.gpa
from
    (
        select
            university,
            min(gpa) gpa
        from
            user_profile
        group by
            university
    ) as u1
    left join user_profile u2 on u1.university = u2.university
    and u1.gpa = u2.gpa
order by
    u1.university
    
# 方式二:通过窗口函数
select
    device_id,
    university,
    gpa
from (
    select     
        device_id,
        university,
        gpa,
        row_number() over(
            partition by university order by gpa
        ) as rank
    from user_profile
    ) as u_rk
where u_rk.rank =1

综合练习

select
    q2.difficult_level,
    sum(if (q1.result = 'right', 1, 0)) / count(result) as correct_rate  # 主要看这一步统计方式
from question_practice_detail q1 
    left join user_profile u on q1.device_id=u.device_id  # 注意此处连接的顺序
    left join question_detail q2 on q2.question_id = q1.question_id 
where
    university = '浙江大学'
group by
    difficult_level
order by
    correct_rate

SQL小练习---牛客刷题

 

有一个薪水表,salaries简况如下:

 

建表语句如下:

复制代码

1

2

3

4

5

6

CREATE TABLE `salaries` (

`emp_no` int(11) NOT NULL,

`salary` int(11) NOT NULL,

`from_date` date NOT NULL,

`to_date` date NOT NULL,

PRIMARY KEY (`emp_no`,`from_date`));


请你查找薪水记录超过15次的员工号emp_no以及其对应的记录次数t,以上例子输出如下:

练习答案

SELECT emp_no, COUNT(emp_no) AS t 
FROM salaries 
GROUP BY emp_no 
HAVING t > 15

思考题 为什么使用 group by 后就会减少一次count 数?

以上是关于入门sql语句-牛客刷题的主要内容,如果未能解决你的问题,请参考以下文章

牛客刷题--SQL篇SQL9查找除复旦大学的用户信息&&SQL10用where过滤空值练习

牛客刷题-SQL进阶挑战大总结(细节狂魔)

牛客刷题总结——Python入门01:输入输出字符串类型转换

牛客刷题打卡

牛客刷题打卡

牛客刷题打卡