写点什么

常见的 SQL 面试题:经典 50 例

  • 2021 年 11 月 11 日
  • 本文字数:8144 字

    阅读完需:约 27 分钟

点击上方?好好学 java?,选择?星标?公众号


重磅资讯,干货,第一时间送达


今日推荐:推荐 19 个 github 超牛逼项目!个人原创 100W +访问量博客:点击前往,查看更多


_作者:_sh_c_2450957609


blog.csdn.net/u010565545/article/details/100785261


SQL 基础知识整理




  • select 查询结果,如:?[学号,平均成绩:组函数avg(成绩)]

  • from 从哪张表中查找数据,如:[涉及到成绩:成绩表score]

  • where 查询条件,如:[b.课程号='0003' and b.成绩>80]

  • group by 分组,如:[每个学生的平均:按学号分组](oracle,SQL server 中出现在 select?子句后的非分组函数,必须出现在 group by 子句后出现),MySQL 中可以不用

  • having 对分组结果指定条件,如:[大于60分]

  • order by 对查询结果排序,如:[增序: 成绩? ASC / 降序: 成绩 DESC];

  • limit?使用 limt 子句返回 topN(对应这个问题返回的成绩前两名),如:[ limit? 2 ==>从0索引开始读取2个]limit==>从 0 索引开始 [0,N-1]


select?*?from?table?limit?2,1;????????????????


--?含义是跳过 2 条取出 1 条数据,limit 后面是从第 2 条开始读,读取 1 条信息,即读取第 3 条数据


select?*?from?table?limit?2?offset?1;?????


--?含义是从第 1 条(不包括)数据开始取出 2 条数据,limit 后面跟的是 2 条数据,offset 后面是从第 1 条开始读取,即读取第 2,3 条


组函数: 去重 distinct()??统计总数 sum()? ?计算个数 count()? 平均数 avg()? 最大值 max() 最小数 min()


多表连接: 内连接(省略默认 inner) join?...on..左连接 left join?tableName as b?on a.key ==b.key 右连接 right join? 连接 union(无重复(过滤去重))和 union all(有重复[不过滤去重])


  • union 并集



  • union all(有重复)




oracle(SQL server)数据库


  • intersect 交集

  • minus(except) 相减(差集)


oracle

一、数据库对象:表(table) ?视图(view) ?序列(sequence) ?索引(index) ?同义词(synonym)

1. 视图: 存储起来的 select 语句

create?view?emp_vw


as


select?employee_id,?last_name,?salary


from?employees


where?department_id?=?90;


select?*?from?emp_vw;


可以对简单视图进行 DML 操作


update?emp_vw


set?last_name?=?'HelloKitty'


where?employee_id?=?100;


select?*?from?employees


where?employee_id?=?100;


1). 复杂视图


create?view?emp_vw2


as


select?department_id,?avg(salary)?avg_sal


from?employees


group?by?department_id;


select?*?from?emp_vw2;


复杂视图不能进行 DML 操作


update?emp_vw2


set?avg_sal?=?10000


where?department_id?=?100;

2. 序列:用于生成一组有规律的数值。(通常用于为主键设置值)

create?sequence?emp_seq1


start?with?1


increment?by?1


maxvalue?10000


minvalue?1


cycle


nocache;


select?emp_seq1.currval?from?dual;


select?emp_seq1.nextval?from?dual;


问题:裂缝,原因:


  • 当多个表共用同一个序列时。

  • rollback

  • 发生异常


create?table?emp1(


id?number(10),


name?varchar2(30)


);


insert?into?emp1


values(emp_seq1.nextval,?'张三');


select?*?from?emp1;

3. 索引:提高查询效率

自动创建:Oracle 会为具有唯一约束(唯一约束,主键约束)的列,自动创建索引


create?table?emp2(


id?number(10)?primary?key,


name?varchar2(30)


)


手动创建


create?index?emp_idx


on?emp2(name);


create?index?emp_idx2


on?emp2(id,?name);

4. 同义词

create?synonym?d1?for?departments;


select?*?from?d1;

5. 表:

DDL :数据定义语言 create table .../ drop table ... / rename ... to..../ truncate table.../alter table ...


DML : 数据操纵语言


insert?into?...?values?...


update?...?set?...?where?...


delete?from?...?where?...


【重要】


  • select ... 组函数(MIN()/MAX()/SUM()/AVG()/COUNT())

  • from ...join ... on ... 左外连接:left join ... on ... 右外连接: right join ... on ...

  • where ...

  • group by ... (oracle,SQL server 中出现在 select?子句后的非分组函数,必须出现在 group by 子句后)

  • having ... 用于过滤 组函数

  • order by ... asc 升序, desc 降序

  • limit (0,4) 限制 N 条数据 如: topN 数据


  • union 并集



  • union all(有重复)



  • intersect 交集



  • minus 相减



DCL : 数据控制语言 ?commit : 提交 / rollback : 回滚 / 授权 grant...to... ?/revoke



索引





何时创建索引:






一、


select?employee_id,?last_name,?salary,?department_id


from?employees


where?department_id?in?(70,?80)


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


?-->?70:1??80:34


  • union 并集

  • union all(有重复部分)

  • intersect 交集

  • minus 相减


select?employee_id,?last_name,?salary,?department_id


from?employees


where?department_id?in?(80,?90)??-->?90:4??80:34


问题:查询工资大于 149 号员工工资的员工的信息


select?*?


from?employees


where?salary?>?(


select?salary


from?employees


where?employee_id?=?149


)


问题:查询与 141 号或 174 号员工的 manager_id 和 department_id 相同的其他员工的 employee_id, manager_id, department_id


select?employee_id,?manager_id,?department_id


from?employees


where?manager_id?in?(


select?manager_id


from?employees


where?employee_id?in(141,?174)


)?and?department_id?in?(


select?department_id


from?employees


where?employee_id?in(141,?174)


)?and?employee_id?not?in?(141,?174);


select?employee_id,?manager_id,?department_id


from?employees


where?(manager_id,?department_id)?in?(


select?manager_id,?department_id


from?employees


where?employee_id?in?(141,?174)


)?and?employee_id?not?in(141,?174);


  1. from 子句中使用子查询


select?max(avg(salary))


from?employees


group?by?department_id;


select?max(avg_sal)


from?(


select?avg(salary)?avg_sal


from?employees


group?by?department_id


)?e


  • 问题:返回比本部门平均工资高的员工的 last_name, department_id, salary 及平均工资


select?last_name,?department_id,?salary,?(select?avg(salary)?from?employees?where?department_id?=?e1.department_id)


from?employees?e1


where?salary?>?(


select?avg(salary)


from?employees?e2


where?e1.department_id?=?e2.department_id


)


select?last_name,?e1.department_id,?salary,?avg_sal


from?employees?e1,?(


select?department_id,?avg(salary)?avg_sal


from?employees


group?by?department_id


)?e2


where?e1.department_id?=?e2.department_id


and?e1.salary?>?e2.avg_sal;


case...when ... then... when ... then ... else ... end


  • 查询:若部门为 10 查看工资的 1.1 倍,部门号为 20 工资的 1.2 倍,其余 1.3 倍


SELECT


employee_id,


last_name,


salary,


CASE


department_id?


WHEN?10?THEN


salary?*?1.1???????????????????????????????????????????????????????????


WHEN?20?THEN


salary??1.2??ELSE?salary??1.3???????????????????????????????????????????????????????????


END?"new_salary"?


FROM


employees;


SELECT


employee_id,


last_name,


salary,


decode(?department_id,?10,?salary??1.1,?20,?salary??1.2,??salary?*?1.3?)?"new_salary"?


FROM


employees;


  • 问题:显式员工的 employee_id,last_name 和 location。其中,若员工 department_id 与 location_id 为 1800 的 department_id 相同,则 location 为’Canada’,其余则为’USA’。


select?employee_id,?last_name,?case?department_id?when?(


select?department_id


from?departments


where?location_id?=?1800


)?then?'Canada'?else?'USA'?end?"location"


from?employees;


  • 问题:查询员工的 employee_id,last_name,要求按照员工的 department_name 排序


select?employee_id,?last_name


from?employees?e1


order?by?(


select?department_name


from?departments?d1


where?e1.department_id?=?d1.department_id


)


SQL 优化:能使用 EXISTS 就不要使用 IN


  • 问题:查询公司管理者的 employee_id,last_name,job_id,department_id 信息


select?employee_id,?last_name,?job_id,?department_id


from?employees


where?employee_id?in?(


select?manager_id


from?employees


)


select?employee_id,?last_name,?job_id,?department_id


from?employees?e1


where?exists?(


select?'x'


from?employees?e2


where?e1.employee_id?=?e2.manager_id


)?


  • 问题:查询 departments 表中,不存在于 employees 表中的部门的 department_id 和 department_name


select?department_id,?department_name


from?departments?d1


where?not?exists?(


select?'x'


from?employees?e1


where?e1.department_id?=?d1.department_id


)


  • 更改 108 员工的信息: 使其工资变为所在部门中的最高工资, job 变为公司中平均工资最低的 job


update?employees?e1


set?salary?=?(


select?max(salary)


from?employees?e2


where?e1.department_id?=?e2.department_id


),?job_id?=?(


select?job_id


from?employees


group?by?job_id


having?avg(salary)?=?(


select?min(avg(salary))


from?employees


group?by?job_id


)


)


where?employee_id?=?108;


  • 删除 108 号员工所在部门中工资最低的那个员工.


delete?from?employees?e1


where?salary?=?(


select?min(salary)


from?employees


where?department_id?=?(


select?department_id


from?employees


where?employee_id?=?108


)


)


select?*?from?employees?where?employee_id?=?108;


select?*?from?employees?where?department_id?=?100


order?by?salary;


rollback;


常见的 SQL 面试题:经典 50 题




已知有如下 4 张表:


  • 学生表:student(学号,学生姓名,出生年月,性别)

  • 成绩表:score(学号,课程号,成绩)

  • 课程表:course(课程号,课程名称,教师号)

  • 教师表:teacher(教师号,教师姓名)


根据以上信息按照下面要求写出对应的 SQL 语句。(搜索公众号 Java 知音,回复“2021”,送你一份 Java 面试题宝典)


ps:这些题考察 SQL 的编写能力,对于这类型的题目,需要你先把 4 张表之间的关联关系搞清楚了,最好的办法是自己在草稿纸上画出关联图,然后再编写对应的 SQL 语句就比较容易了。下图是我画的这 4 张表的关系图,可以看出它们之间是通过哪些外键关联起来的:


一、创建数据库和表

为了演示题目的运行过程,我们先按下面语句在客户端 navicat 中创建数据库和表。


如何你还不懂什么是数据库,什么是客户端 navicat,可以先学习这个:


1.创建表

1)创建学生表(student)

按下图在客户端 navicat 里创建学生表。推荐:250期面试题汇总



学生表的“学号”列设置为主键约束,下图是每一列设置的数据类型和约束



创建完表,点击“保存”


2)创建成绩表(score)

同样的步骤,创建"成绩表“。“课程表的“学号”和“课程号”一起设置为主键约束(联合主键),“成绩”这一列设置为数值类型(float,浮点数值)


3)创建课程表(course)

课程表的“课程号”设置为主键约束


4)教师表(teacher)

教师表的“教师号”列设置为主键约束,教师姓名这一列设置约束为“null”(红框的地方不勾选),表示这一列允许包含空值(null)。推荐:250期面试题汇总



向表中添加数据



1)向学生表里添加数据


添加数据的 sql


insert?into?student(学号,姓名,出生日期,性别)?


values('0001'?,?'猴子'?,?'1989-01-01'?,?'男');


insert?into?student(学号,姓名,出生日期,性别)?


values('0002'?,?'猴子'?,?'1990-12-21'?,?'女');


insert?into?student(学号,姓名,出生日期,性别)?


values('0003'?,?'马云'?,?'1991-12-21'?,?'男');


insert?into?student(学号,姓名,出生日期,性别)?


values('0004'?,?'王思聪'?,?'1990-05-20'?,?'男');


在客户端 navicat 里的操作





2)成绩表(score)


添加数据的 sql


insert?into?score(学号,课程号,成绩)?


values('0001'?,?'0001'?,?80);


insert?into?score(学号,课程号,成绩)?


values('0001'?,?'0002'?,?90);


insert?into?score(学号,课程号,成绩)?


values('0001'?,?'0003'?,?99);


insert?into?score(学号,课程号,成绩)?


values('0002'?,?'0002'?,?60);


insert?into?score(学号,课程号,成绩)?


values('0002'?,?'0003'?,?80);


insert?into?score(学号,课程号,成绩)?


values('0003'?,?'0001'?,?80);


insert?into?score(学号,课程号,成绩)?


values('0003'?,?'0002'?,?80);


insert?into?score(学号,课程号,成绩)?


values('0003'?,?'0003'?,?80);


客户端 navicat 里的操作



3)课程表


添加数据的 sql


insert?into?course(课程号,课程名称,教师号)


values('0001'?,?'语文'?,?'0002');


insert?into?course(课程号,课程名称,教师号)


values('0002'?,?'数学'?,?'0001');


insert?into?course(课程号,课程名称,教师号)


values('0003'?,?'英语'?,?'0003');


客户端 navicat 里的操作



4)教师表里添加数据


添加数据的 sql


--?教师表:添加数据


insert?into?teacher(教师号,教师姓名)?


values('0001'?,?'孟扎扎');


insert?into?teacher(教师号,教师姓名)?


values('0002'?,?'马化腾');


--?这里的教师姓名是空值(null)


insert?into?teacher(教师号,教师姓名)?


values('0003'?,?null);


--?这里的教师姓名是空字符串('')


insert?into?teacher(教师号,教师姓名)?


values('0004'?,?'');


客户端 navicat 里操作



添加结果



三、50 道面试题




为了方便学习,我将 50 道面试题进行了分类



查询姓“猴”的学生名单



查询姓“孟”老师的个数


select?count(教师号)


from?teacher


where?教师姓名?like?'孟 %';

2.汇总统计分组分析


面试题:查询课程编号为“0002”的总成绩


--分析思路


--select?查询结果?[总成绩:汇总函数 sum]


--from?从哪张表中查找数据[成绩表 score]


--where?查询条件?[课程号是 0002]


select?sum(成绩)


from?score


where?课程号?=?'0002';


查询选了课程的学生人数


--这个题目翻译成大白话就是:查询有多少人选了课程


--select?学号,成绩表里学号有重复值需要去掉


--from?从课程表查找 score;


select?count(distinct?学号)?as?学生人数?


from?score;



查询各科成绩最高和最低的分, 以如下的形式显示:课程号,最高分,最低分


/*


分析思路


select 查询结果?[课程 ID:是课程号的别名,最高分:max(成绩) ,最低分:min(成绩)]


from?从哪张表中查找数据?[成绩表 score]


where?查询条件?[没有]


group by 分组?[各科成绩:也就是每门课程的成绩,需要按课程号分组];


*/


select?课程号,max(成绩)?as?最高分,min(成绩)?as?最低分


from?score


group?by?课程号;


查询每门课程被选修的学生数


/*


分析思路


select 查询结果?[课程号,选修该课程的学生数:汇总函数 count]


from?从哪张表中查找数据?[成绩表 score]


where?查询条件?[没有]


group by 分组?[每门课程:按课程号分组];


*/


select?课程号,?count(学号)


from?score


group?by?课程号;


查询男生、女生人数


/*


分析思路


select 查询结果?[性别,对应性别的人数:汇总函数 count]


from?从哪张表中查找数据?[性别在学生表中,所以查找的是学生表 student]


where?查询条件?[没有]


group by 分组?[男生、女生人数:按性别分组]


having?对分组结果指定条件?[没有]


order?by?对查询结果排序[没有];


*/


select?性别,count(*)


from?student


group?by?性别;



查询平均成绩大于 60 分学生的学号和平均成绩


/*?


题目翻译成大白话:


平均成绩:展开来说就是计算每个学生的平均成绩


这里涉及到“每个”就是要分组了


平均成绩大于 60 分,就是对分组结果指定条件


分析思路


select 查询结果?[学号,平均成绩:汇总函数 avg(成绩)]


from?从哪张表中查找数据?[成绩在成绩表中,所以查找的是成绩表 score]


where?查询条件?[没有]


group by 分组?[平均成绩:先按学号分组,再计算平均成绩]


having?对分组结果指定条件?[平均成绩大于 60 分]


*/


select?学号,?avg(成绩)


from?score


group?by?学号


having?avg(成绩)>60;


查询至少选修两门课程的学生学号


/*?


翻译成大白话:


第 1 步,需要先计算出每个学生选修的课程数据,需要按学号分组


第 2 步,至少选修两门课程:也就是每个学生选修课程数目>=2,对分组结果指定条件


分析思路


select 查询结果?[学号,每个学生选修课程数目:汇总函数 count]


from 从哪张表中查找数据?[课程的学生学号:课程表 score]


where 查询条件?[至少选修两门课程:需要先计算出每个学生选修了多少门课,需要用分组,所以这里没有 where 子句]


group by 分组?[每个学生选修课程数目:按课程号分组,然后用汇总函数 count 计算出选修了多少门课]


having 对分组结果指定条件?[至少选修两门课程:每个学生选修课程数目>=2]


*/


select?学号,?count(课程号)?as?选修课程数目


from?score


group?by?学号


having?count(课程号)>=2;


查询同名同性学生名单并统计同名人数


/*?


翻译成大白话,问题解析:


1)查找出姓名相同的学生有谁,每个姓名相同学生的人数


查询结果:姓名,人数


条件:怎么算姓名相同?按姓名分组后人数大于等于 2,因为同名的人数大于等于 2


分析思路


select 查询结果?[姓名,人数:汇总函数 count(*)]


from?从哪张表中查找数据?[学生表 student]


where?查询条件?[没有]


group by 分组?[姓名相同:按姓名分组]


having 对分组结果指定条件?[姓名相同:count(*)>=2]


order?by?对查询结果排序[没有];


*/


select?姓名,count(*)?as?人数


from?student


group?by?姓名


having?count(*)>=2;


查询不及格的课程并按课程号从大到小排列


/*?


分析思路


select?查询结果?[课程号]


from?从哪张表中查找数据?[成绩表 score]


where 查询条件?[不及格:成绩?<60]


group?by?分组?[没有]


having?对分组结果指定条件?[没有]


order by 对查询结果排序[课程号从大到小排列:降序 desc];


*/


select?课程号


from?score?


where?成绩<60


order?by?课程号?desc;


查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列


/*?


分析思路


select 查询结果?[课程号,平均成绩:汇总函数 avg(成绩)]


from?从哪张表中查找数据?[成绩表 score]


where?查询条件?[没有]


group by 分组?[每门课程:按课程号分组]


having?对分组结果指定条件?[没有]


order?by?对查询结果排序[按平均成绩升序排序:asc,平均成绩相同时,按课程号降序排列:desc];


*/


select?课程号,?avg(成绩)?as?平均成绩


from?score


group?by?课程号


order?by?平均成绩?asc,课程号?desc;


检索课程编号为“0004”且分数小于 60 的学生学号,结果按按分数降序排列


/*?


分析思路


select?查询结果?[]


from?从哪张表中查找数据?[成绩表 score]


where?查询条件?[课程编号为“04”且分数小于 60]


group?by?分组?[没有]


having?对分组结果指定条件?[]


order?by?对查询结果排序[查询结果按按分数降序排列];


*/


select?学号


from?score


where?课程号='04'?and?成绩?<60


order?by?成绩?desc;


统计每门课程的学生选修人数(超过 2 人的课程才统计)


要求输出课程号和选修人数,查询结果按人数降序排序,若人数相同,按课程号升序排序


/*?


分析思路


select?查询结果?[要求输出课程号和选修人数]


from?从哪张表中查找数据?[]


where?查询条件?[]


group by 分组?[每门课程:按课程号分组]


having 对分组结果指定条件?[学生选修人数(超过 2 人的课程才统计):每门课程学生人数>2]


order?by?对查询结果排序[查询结果按人数降序排序,若人数相同,按课程号升序排序];


*/


select?课程号,?count(学号)?as?'选修人数'


from?score


group?by?课程号


having?count(学号)>2


order?by?count(学号)?desc,课程号?asc;


查询两门以上不及格课程的同学的学号及其平均成绩


/*


分析思路


先分解题目:


1)[两门以上][不及格课程]限制条件


2)[同学的学号及其平均成绩],也就是每个学生的平均成绩,显示学号,平均成绩


分析过程:


第 1 步:得到每个学生的平均成绩,显示学号,平均成绩


第 2 步:再加上限制条件:


1)不及格课程


2)两门以上[不及格课程]:课程数目>2


/*?


第 1 步:得到每个学生的平均成绩,显示学号,平均成绩


select 查询结果?[学号,平均成绩:汇总函数 avg(成绩)]


from 从哪张表中查找数据?[涉及到成绩:成绩表 score]


where?查询条件?[没有]


group by 分组?[每个学生的平均:按学号分组]


having?对分组结果指定条件?[没有]


order?by?对查询结果排序[没有];


*/


select?学号,?avg(成绩)?as?平均成绩


from?score


group?by?学号;


/*?


第 2 步:再加上限制条件:


1)不及格课程


2)两门以上[不及格课程]


select 查询结果?[学号,平均成绩:汇总函数 avg(成绩)]


from 从哪张表中查找数据?[涉及到成绩:成绩表 score]


where 查询条件?[限制条件:不及格课程,平均成绩<60]


group by 分组?[每个学生的平均:按学号分组]


having 对分组结果指定条件?[限制条件:课程数目>2,汇总函数 count(课程号)>2]


order?by?对查询结果排序[没有];


*/


select?学号,?avg(成绩)?as?平均成绩


from?score


where?成绩?<60


group?by?学号


having?count(课程号)>=2;

评论

发布
暂无评论
常见的SQL面试题:经典50例