文章目录
备注:牛客网的题是按MySQL的
单表查询
1、选择某个字段最大值所在的记录
eg:查找入职最晚员工的所有信息(牛客题号:SQL1)
分析:通过入职时间对整个表降序排列,位于第一个即入职时间最大(最晚)的员工
实现:
select *
from employees
where hire_date = (select max(hire_date)
from employees)
2、选择某个特定字段所在的记录
eg:查找入职员工时间排名倒数第三的员工所有信息(牛客题号:SQL2)
分析:设想了一种思路(还未实现):首先选出最晚入职的三个员工,在选择其中入职时间最小的,但只通过了一组测试用例
select *
from employees
where hire_date = (select min(hire_date)
from employees order by hire_date desc limit 3);
错误原因: 子查询中不能使用order by
可使用limit子句通过:
select *
from employees
order by hire_date desc limit 2,1;
//或者写为offset的形式
// order by hire_date limit 2 offset 1;
查看某列的取值范围
SQL3 查询结果去重:https://www.nowcoder.com/practice/82ebd89f12cf48efba0fecb392e193dd?tpId=199&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
可以使用distinct子句或者group by子句
--1、使用distinct子句
select distinct university from user_profile
2、使用group by子句
select university from user_profile group by university
在分组结果中增加过滤条件(having子句)
SQL19 分组过滤练习题https://www.nowcoder.com/practice/ddbcedcd9600403296038ee44a172f2d?tpId=199&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
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 avg(question_cnt) < 5 or avg(answer_cnt) < 20
在聚合查询结果中增加排序
select
university,
avg(question_cnt) as avg_question_cnt
from user_profile
group by university
order by avg(question_cnt)
字符串截取 substring_index函数
按某分隔符截取或按位置截取
select
substring_index(substring_index(profile,',',-2),',',1) as age,
count(*) as number
from user_submit
group by age
多表查询
使用on或where子句基本语法
- eg:查找各个部门当前领导当前薪水详情以及其对应部门编号dept_no
分析: 从建表语句及样例输出可以看出salaries表所有字段都是在结果里的,加上另一个表dept_manager中的dept_no字段即可
select salaries.*,dept_manager.dept_no
from salaries inner join dept_manager
on salaries.emp_no = dept_manager.emp_no
//on换成where也可以
//where salaries.emp_no = dept_manager.emp_no
order by emp_no
select e.last_name,e.first_name,d.dept_no
from employees e,dept_emp d
where e.emp_no = d.emp_no
on与and连用注意
SQL24 统计每个用户的平均刷题数
ON子句里条件的作用范围是生成的临时表内,如果后边还加and子句条件去限制,返回的结果就会和join方式、and子句条件涉及的列有关了。注意临时表里的数据到底是什么
--on、and条件有问题导致出现university里有空的
select university, difficult_level, round(count(qp.question_id)/count(distinct qp.device_id),4) as avg_answer_cnt
from user_profile u right join question_practice_detail qp
on u.device_id = qp.device_id
and u.university = '山东大学'
inner join question_detail qd
on qp.question_id = qd.question_id
group by qd.difficult_level,university
--通过的sql
select university, difficult_level, round(count(qp.question_id)/count(distinct qp.device_id),4) as avg_answer_cnt
from user_profile u right join question_practice_detail qp
on u.device_id = qp.device_id
inner join question_detail qd
on qp.question_id = qd.question_id
where u.university = '山东大学'
group by qd.difficult_level,university
可以参考博客:MySQL中 left join on 后的 and 条件与 where 中条件的区别
union,union all :去重与否
union all对连接的两表不进行去重
case when子句
select device_id,
gender,
case when age >= 25 then '25岁及以上'
when age >= 20 and age < 25 then '20-24岁'--此处直接写成age>=20也可以,已经类似分段了
when age < 20 then '20岁以下'
else '其他'
end age_cut
from user_profile
select
case when age < 25 or age is null THEN '25岁以下'
when age >= 25 then '25岁及以上'
end age_cut,count(*) as 'number'
from user_profile
group by age_cut
或者用if也可以,(已经暗含了age为null的算在25岁以下)
select
if(age>=25,"25岁及以上","25岁以下") as age_cut,
count(*) as number
from user_profile
group by age_cut
特定日期的数据
select day(date) as day, count(*) as question_cnt
from question_practice_detail
where month(date) = 8 and year(date) = 2021
group by 1
本题要注意的地方:
- 怎么获取是第几天
- 限定日期范围:可以使用like ‘2021-08%’、substring(date,1,7) = ‘2021-08’,regexp ‘2021-08’
关联子查询
子查询里使用到了外层查询的列
select * from table_name t
where column1 > ( select avg(column) from table_name
where column_name = t.columnn_name)
标量子查询
select 和 from中间的就是标量子查询
练习在线网站推荐
- 力扣https://www.lintcode.com/learn
- 牛客https://www.nowcoder.com/exam/oj?page=1&tab=SQL%E7%AF%87&topicId=199
力扣的教程比较细一点,但看不到其他人的代码(但是牛客网可以,不知道是不是力扣我的账号权限不够),参与感有点弱。
查看官方参考文档
MySQL官方文档
进入MySQL文档中心:https://dev.mysql.com/doc/
直接点击参考手册进入即可,然后在搜索框里查要看的函数