史上最细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 湖北
点赞 回复 分享
发布于 07-08 23:09 四川
mark收藏
点赞 回复 分享
发布于 07-08 07:01 江西

相关推荐

鼠鼠实习的地方是一个小小厂,让我去的时候offer都没发,面试也是线下面的。实习第一天上午拉代码本地跑完之后,下午就让我改sql。第二天跟鼠鼠说了一个需求,需求也没有说清楚,接口文档之类的都没有,就口头说了一声。第三天写昨天的功能。第四天开发一个新接口,要求也没说,我完全都在自己写,提交之后改了两回sql,然后就寄了😅。下班回家的时候,跟我一起实习的那个大哥知道之后跟我说,其实导师第四天下午就在看别人的简历了😓,下午下班的时候,把我叫到会议室,大概意思就是说我态度不端正,然后后面还扯了什么加班之类的,连改的机会都不给我直接就让我不用来了,估计是找到比我好的了。其实鼠鼠也挺委屈的,因为是第一次实习,想快点做出成绩,回头想想,确实太急功近利了,着急做出成绩导致代码有bug,还有就是导师需求都说不清,我只能一直问他(鼠鼠也只是想把功能做好),可能让他有点烦了吧,没想到第一次实习会是这样,真应了鼠鼠那句话,自诩心比天高,可叹命比纸薄。鼠鼠我这一路也挺曲折的,第一次面试就遇到了kpi(演都不演的那种),第一次实习就出现了这种状况。现在已经在回家的路上,准备回去沉淀一个暑假,到时候直接投中大厂了,现在也想开了,鼠鼠学历还行(末2软件工程),没必要为了实习而实习。鼠鼠的大致情况是javase,ssm,juc,jvm,mysql,redis,springcloud,springai,rabbitmq。八股文把小林coding背了几遍(上面那些技术栈相关的),算法大概刷了200道,感觉还得沉淀一下,牛客的友友们,有什么建议吗?希望各位义父能给鼠鼠点建议。
SoudX:找个好点的厂,我旁边的正职就是你学长,无实习经历校招进来的,你这才27届,多投一投
点赞 评论 收藏
分享
评论
8
142
分享

创作者周榜

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