史上最细SQL实战系列:sql笔试例题总结篇(建议收藏)

这是我的史上最细SQL实战系列的sql笔试例题总结篇。本文章例题所用知识点可回顾之前发的文章:sql基础知识篇基础知识篇补充本系列文章核心不在于总结Mysql相关的八股(Mysql超全八股可见此文:Mysql超全八股笔记贴),本系列旨在:1.快速掌握sql知识,会写面试时常见的sql题目;2.了解在实际工作中需要注意的超多数据库和表设计相关的知识和坑点。

本系列文章分为3个部分:1基础知识篇;2sql笔试篇;3公司级数据库与表设计相关知识与坑点总结。

另外:

想要学习Java冲实习或冲春招的,我能助你一臂之力,我之前整理了高质量可速成的魔改外卖项目话术和7000字轮子项目话术,还有超全超精品八股大全专栏,怎么写简历,怎么包装实习经历,怎么0基础速成冲春招和实习等等等等精品帖子,大家可以去看看我的精品文章汇总帖子:往期精品帖子汇总

我的八股大全、算法、项目话术全专栏(20w人学习,超千人订阅,牛客最受欢迎最高质量java八股专栏,内容包含: 1.八股大全:多一句没有少一句不行的最精简八股整理,完全可以应付校招社招的八股拷打! 2.速成项目话术:目前有魔改苍穹外卖项目话术(额外扩展了很多技术亮点),能速成拿去面试,后面会更新魔改黑马点评、商城项目等等热门高质量项目话术 3.智力题超详细题解汇总; 4.面试时非技术问题话术整理,绝对震惊面试官一年; 5.算法lc hot100全题系列题解:绝对通俗易懂快速冲刺秋招专栏

---------------------------------------------------------------------

1.建表

总共4张表,包括学生、成绩、科目和教师,建表SQL如下:

-- 学生表

create table student(
	s_id varchar(20) not null,
	s_name varchar(20) not null default '',
	s_birth varchar(20) not null default '',
	s_sex varchar(10) not null default '男',
	primary key(s_id)
);
-- 成绩表

CREATE TABLE score(
	s_id VARCHAR(20),
	c_id  VARCHAR(20),
	s_score INT,
	PRIMARY KEY(s_id,c_id)
);
-- 教师表

CREATE TABLE teacher(
	t_id VARCHAR(20),
	t_name VARCHAR(20) NOT NULL DEFAULT '',
	PRIMARY KEY(t_id)
);
-- 课程表

CREATE TABLE course(
	c_id  VARCHAR(20),
	c_name VARCHAR(20) NOT NULL DEFAULT '',
	t_id VARCHAR(20) NOT NULL,
	PRIMARY KEY(c_id)
);


2.插入数据

-- 插入学生表测试数据
insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
insert into Student values('02' , '钱电' , '1990-12-21' , '男');
insert into Student values('03' , '孙风' , '1990-05-20' , '男');
insert into Student values('04' , '李云' , '1990-08-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吴兰' , '1992-03-01' , '女');
insert into Student values('07' , '郑竹' , '1989-07-01' , '女');
insert into Student values('08' , '王菊' , '1990-01-20' , '女');
-- 课程表测试数据
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
-- 教师表测试数据
insert into teacher values('01' , '张三');
insert into teacher values('02' , '李四');
insert into teacher values('03' , '王五');
-- 成绩表测试数据
insert into Score values('01' , '01' , 80);
insert into Score values('01' , '02' , 90);
insert into Score values('01' , '03' , 99);
insert into Score values('02' , '01' , 70);
insert into Score values('02' , '02' , 60);
insert into Score values('02' , '03' , 80);
insert into Score values('03' , '01' , 80);
insert into Score values('03' , '02' , 80);
insert into Score values('03' , '03' , 80);
insert into Score values('04' , '01' , 50);
insert into Score values('04' , '02' , 30);
insert into Score values('04' , '03' , 20);
insert into Score values('05' , '01' , 76);
insert into Score values('05' , '02' , 87);
insert into Score values('06' , '01' , 31);
insert into Score values('06' , '03' , 34);
insert into Score values('07' , '02' , 89);
insert into Score values('07' , '03' , 98);


3.SQL查询语句练习

1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数

方法1:子连接 
SELECT 
    s.*, 
    s01.s_score AS score_01, 
    s02.s_score AS score_02
FROM 
    student s
JOIN score s01 ON s.s_id = s01.s_id AND s01.c_id = '01'
JOIN score s02 ON s.s_id = s02.s_id AND s02.c_id = '02'
WHERE 
    s01.s_score > s02.s_score;

方法2:子查询
SELECT 
    s.*, 
    (SELECT s_score FROM score WHERE s_id = s.s_id AND c_id = '01') AS score_01,
    (SELECT s_score FROM score WHERE s_id = s.s_id AND c_id = '02') AS score_02
FROM 
    student s
WHERE 
    (SELECT s_score FROM score WHERE s_id = s.s_id AND c_id = '01') > 
    (SELECT s_score FROM score WHERE s_id = s.s_id AND c_id = '02');

方法3:CTE
WITH course_01 AS (
    SELECT s_id, s_score FROM score WHERE c_id = '01'
),
course_02 AS (
    SELECT s_id, s_score FROM score WHERE c_id = '02'
)
SELECT 
    st.*, 
    c01.s_score AS score_01, 
    c02.s_score AS score_02
FROM 
    student st
JOIN course_01 c01 ON st.s_id = c01.s_id
JOIN course_02 c02 ON st.s_id = c02.s_id
WHERE 
    c01.s_score > c02.s_score;

方法一(自连接) 是最推荐的:

  • 执行效率最高,只需要扫描一次 score 表
  • 结构清晰,易于理解和维护
  • 索引优化友好(建议在 score 表上创建复合索引 (s_id, c_id, s_score))

子查询(方法二)

  • 优点:语法简洁,直观表达查询逻辑
  • 缺点:对每个学生执行两次子查询,大数据量下性能较差

CTE(方法三)

  • 优点:逻辑分离,提高可读性,适合复杂查询
  • 缺点:在简单查询中略显冗余

2.查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩

方法1:分组
SELECT 
    s.s_id, 
    s.s_name, 
    AVG(sc.s_score) AS avg_score
FROM 
    student s
JOIN score sc ON s.s_id = sc.s_id
GROUP BY 
    s.s_id, s.s_name
HAVING 
    AVG(sc.s_score) >= 60;
    
记住:当使用聚合函数(如SUM、COUNT等)时,非聚合列必须出现在GROUP BY子句中或通过某种方式被聚合。所以GROUP BY后面还要加个s_name

方法2:子查询
SELECT 
    s.s_id, 
    s.s_name, 
    (SELECT AVG(s_score) FROM score WHERE s_id = s.s_id) AS avg_score
FROM 
    student s
WHERE 
    (SELECT AVG(s_score) FROM score WHERE s_id = s.s_id) >= 60;

方法三:CTE
WITH student_avg AS (
    SELECT 
        s_id, 
        AVG(s_score) AS avg_score
    FROM 
        score
    GROUP BY 
        s_id
)
SELECT 
    s.s_id, 
    s.s_name, 
    sa.avg_score
FROM 
    student s
JOIN student_avg sa ON s.s_id = sa.s_id
WHERE 
    sa.avg_score >= 60;

方法一(GROUP BY 和 HAVING) 是最推荐的:

  • 执行效率最高,直接在分组阶段过滤数据
  • 结构简单,符合 SQL 标准
  • 索引优化友好(建议在 score 表上创建复合索引 (s_id, s_score))

子查询(方法2)

  • 优点:语法简洁,直观表达查询意图
  • 缺点:对每个学生执行一次子查询,大数据量下性能较差

CTE(方法3)

  • 优点:逻辑清晰,先计算平均分再关联学生表
  • 缺点:可能产生临时表,对复杂查询更有优势

3.查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩(包括有成绩的和无成绩的)

方法1:使用 LEFT JOIN + COALESCE 处理 NULL
SELECT 
    s.s_id, 
    s.s_name, 
    COALESCE(AVG(sc.s_score), 0) AS avg_score
FROM 
    student s
LEFT JOIN score sc ON s.s_id = sc.s_id
GROUP BY 
    s.s_id, s.s_name
HAVING 
    COALESCE(AVG(sc.s_score), 0) < 60;

方法二:使用 CASE WHEN 自定义 NULL 处理
SELECT 
    s.s_id, 
    s.s_name, 
    AVG(CASE WHEN sc.s_score IS NULL THEN 0 ELSE sc.s_score END) AS avg_score
FROM 
    student s
LEFT JOIN score sc ON s.s_id = sc.s_id
GROUP BY 
    s.s_id, s.s_name
HAVING 
    AVG(CASE WHEN sc.s_score IS NULL THEN 0 ELSE sc.s_score END) < 60;

  1. 为什么用 LEFT JOIN?普通 JOIN 会过滤掉无成绩的学生,而 LEFT JOIN 确保所有学生被保留,无成绩的学生对应分数为 NULL。
  2. NULL 值处理COALESCE(AVG(sc.s_score), 0):将 NULL 转换为 0(无成绩的学生视为平均分 0)。AVG(CASE WHEN sc.s_score IS NULL THEN 0 ELSE sc.s_score END):手动替换 NULL 为 0 后计算平均分。

4.查询学过"张三"老师授课的同学的信息

方法1:多层join
SELECT DISTINCT 
    s.*
FROM 
    student s
JOIN score sc ON s.s_id = sc.s_id
JOIN course c ON sc.c_id = c.c_id
JOIN teacher t ON c.t_id = t.t_id
WHERE 
    t.t_name = '张三';

方法2:EXISTS
SELECT * 
FROM 
    student s
WHERE 
    EXISTS (
        SELECT *
        FROM score sc
        JOIN course c ON sc.c_id = c.c_id
        JOIN teacher t ON c.t_id = t.t_id
        WHERE 
            s.s_id = sc.s_id 
            AND t.t_name = '张三'
    );

方法一(多层 JOIN) 是最简洁直观的:

  • 直接通过表关联获取结果,执行效率较高。
  • 索引优化建议: 在 teacher(t_name) 上创建索引,加速教师名称查询。在 course(t_id) 和 score(c_id) 上创建复合索引,加速连接。

若数据量较大且可能存在大量不匹配记录,方法二(EXISTS) 性能更优,因为它提前终止不必要的扫描。

5.查询没学过"张三"老师授课的同学的信息

SELECT * 
FROM 
    student s
WHERE 
    NOT EXISTS (
        SELECT 1 
        FROM score sc
        JOIN course c ON sc.c_id = c.c_id
        JOIN teacher t ON c.t_id = t.t_id
        WHERE 
            s.s_id = sc.s_id 
            AND t.t_name = '张三'
    );

6.查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息

方法1:自连接
SELECT s.*
FROM 
    student s
JOIN score sc1 ON s.s_id = sc1.s_id AND sc1.c_id = '01'
JOIN score sc2 

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

内容包含: 1.八股大全:多一句没有少一句不行的最精简八股整理,完全可以应付校招八股拷打! 2.速成项目话术:目前有魔改苍穹外卖项目话术(额外扩展了很多技术亮点),能速成拿去面试,后面会更新魔改黑马点评、商城项目等等热门高质量项目话术 3.智力题超详细题解汇总; 4.面试时非技术问题话术整理,绝对震惊面试官一年; 5.算法lc hot100全题系列题解:绝对通俗易懂。 会慢慢涨价,欢迎订阅!

全部评论
天不生我带篮子,牛客万古如长夜!
3 回复 分享
发布于 07-08 08:37 湖北
求🌸😍
1 回复 分享
发布于 07-07 13:20 湖北
很好,感谢,自动驾驶开始了,看看吗?https://www.nowcoder.com/discuss/1518218
点赞 回复 分享
发布于 今天 00:40 广东
点赞 回复 分享
发布于 07-08 23:09 四川
mark收藏
点赞 回复 分享
发布于 07-08 07:01 江西

相关推荐

下面是我在评论区看到别人评论的技能栏,但是自己实际上也不懂这么多,都是看着黑马那个课程学的,目前学到苍穹外卖结束,技能那栏可以怎么写😫,自己想通过下面的技能去看一下发现要学好多东西,感觉来不及找实习了1.具备扎实的Java基础,熟悉常见容器的底层原理(如ArrayList、HashMap、LinkedList等),熟悉Java并发编程(如线程池、synchronized锁升级、CAS、AQS等),了解JVM的内存结构、垃圾回收机制、类加载机制等;2.熟悉MySQL数据库索引、事务、锁、日志等常用特性,以及SQL的使用和优化;3.熟悉Redis的常见数据类型和应用场景、持久化、过期和淘汰策略、分布式锁等特性,能够解决在高并发下的缓存穿透、雪崩、击穿问题,掌握Redis主从结构、哨兵机制,实践过基于Redisson的分布式限流;4.熟悉使用Spring、Spring&nbsp;MVC、MyBatis、MyBatis-Plus、Spring&nbsp;Boot等开源框架,掌握AOP、IoC、Spring&nbsp;Boot&nbsp;的自动装配原理;5.掌握RabbitMQ的相关应用,如保证消息可靠性的confirm与return机制、延时队列、解决分布式事务问题;6.掌握Linux与Docker的常用命令,如拉取镜像、快速启动单个服务、编写Dockerfile、项目部署;7.了解Nginx,可用Nginx实现反向代理、负载均衡、动静分离、前端网站的部署等;8.熟练使用IDEA、Maven、Git、Postman、JMeter、Swagger等工具进行开发
点赞 评论 收藏
分享
评论
6
127
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务