mysql练习题,由浅入深的 MySQL 练习题

首页 2025-10-09 13:37:59


这里为你准备了一系列由浅入深的 MySQL 练习题。它们涵盖了从基础查询到高级应用的多个方面,非常适合用来练习和巩固你的 SQL 技能。

准备工作:创建练习用的数据库和表

在开始之前,请先执行以下 SQL 脚本,创建一个名为 school 的数据库和三张表:students (学生), courses (课程), 和 scores (成绩)。
sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS school;
USE school;

-- 创建学生表
CREATE TABLE students (
    student_id INT PRIMARY KEY AUTO_INCREMENT,
    student_name VARCHAR(50) NOT NULL,
    gender ENUM('男', '女') NOT NULL,
    age INT,
    city VARCHAR(100)
);

-- 创建课程表
CREATE TABLE courses (
    course_id INT PRIMARY KEY AUTO_INCREMENT,
    course_name VARCHAR(100) NOT NULL,
    teacher_name VARCHAR(50)
);

-- 创建成绩表
CREATE TABLE scores (
    score_id INT PRIMARY KEY AUTO_INCREMENT,
    student_id INT NOT NULL,
    course_id INT NOT NULL,
    score DECIMAL(5, 2),
    -- 设置外键关联
    FOREIGN KEY (student_id) REFERENCES students(student_id),
    FOREIGN KEY (course_id) REFERENCES courses(course_id)
);

-- 插入学生数据
INSERT INTO students (student_name, gender, age, city) VALUES
('张三', '男', 20, '北京'),
('李四', '男', 22, '上海'),
('王五', '女', 21, '广州'),
('赵六', '男', 20, '北京'),
('钱七', '女', 22, '深圳'),
('孙八', '男', 23, '上海');

-- 插入课程数据
INSERT INTO courses (course_name, teacher_name) VALUES
('高等数学', '李教授'),
('线性代数', '王教授'),
('计算机基础', '张老师'),
('数据库原理', '刘老师');

-- 插入成绩数据
INSERT INTO scores (student_id, course_id, score) VALUES
(1, 1, 88.5),
(1, 3, 92.0),
(1, 4, 89.0),
(2, 1, 76.0),
(2, 2, 82.5),
(2, 4, 95.0),
(3, 1, 91.0),
(3, 2, 78.0),
(3, 3, 85.5),
(4, 1, 60.0),
(4, 3, 72.0),
(4, 4, 68.0),
(5, 2, 89.5),
(5, 3, 94.0),
(5, 4, 90.0),
(6, 1, 95.0),
(6, 2, 92.0),
(6, 3, 88.0);
 

练习题

第一部分:基础查询 (SELECT)

  1. 查询所有学生的姓名和年龄。
  2. 查询所有课程的名称和授课教师。
  3. 查询所有在北京的学生。
  4. 查询年龄大于 21 岁的学生。
  5. 查询所有姓 “张” 的学生。 (提示:使用 LIKE 和 %)
  6. 查询成绩在 80 到 90 分之间的所有记录。 (提示:使用 BETWEEN ... AND ...)
  7. 查询所有课程的名称,并去除重复的课程名。 (提示:使用 DISTINCT)

第二部分:排序和限制 (ORDER BY, LIMIT)

  1. 查询所有学生的姓名和年龄,并按年龄从大到小排序。
  2. 查询所有学生的姓名和城市,并按城市升序、姓名降序排序。
  3. 查询成绩最高的 3 条记录。

第三部分:聚合函数和分组 (GROUP BY, HAVING)

  1. 计算学生总人数。 (提示:使用 COUNT())
  2. 计算 “高等数学” 这门课的平均成绩、最高分和最低分。 (提示:使用 AVG()MAX()MIN())
  3. 查询每个学生的总分和平均分。 (提示:按 student_id 分组)
  4. 查询总分大于 250 分的学生。 (提示:使用 HAVING 子句)
  5. 查询有 3 个或 3 个以上学生选修的课程及其学生人数。

第四部分:多表连接 (JOIN)

  1. 查询每个学生的姓名及其选修的课程名称。 (提示:连接 studentsscorescourses 三张表)
  2. 查询 “张三” 同学的所有成绩记录,包括课程名和分数。
  3. 查询所有学生的姓名以及他们 “数据库原理” 这门课的成绩。如果学生没有选修这门课,成绩显示为 NULL。 (提示:使用 LEFT JOIN)
  4. 查询没有任何成绩记录的学生。 (提示:可以使用 LEFT JOIN 后判断成绩为 NULL,或使用 NOT IN)
  5. 查询每门课程的课程名和选课人数。

第五部分:子查询和高级应用

  1. 查询 “高等数学” 成绩最高的学生姓名和分数。 (提示:可以使用子查询先找出最高分)
  2. 查询所有成绩都高于 80 分的学生姓名。 (提示:可以用 NOT EXISTS 或 GROUP BY ... HAVING MIN(score) > 80)
  3. 查询与 “张三” 同龄的学生。
  4. 查询选修了 “数据库原理” 但没有选修 “计算机基础” 的学生。 (提示:使用 NOT IN 或 NOT EXISTS)
  5. 查询每门课程的前两名学生及其成绩。 (这是一个经典的 Top-N 问题,有一定难度,可以使用窗口函数或关联子查询)

答案与解析

注意: 强烈建议你先自己尝试解答,然后再对照答案。
<details><summary>点击展开查看答案</summary>

第一部分:基础查询 (SELECT)

  1. SELECT student_name, age FROM students;
  2. SELECT course_name, teacher_name FROM courses;
  3. SELECT * FROM students WHERE city = '北京';
  4. SELECT * FROM students WHERE age > 21;
  5. SELECT * FROM students WHERE student_name LIKE '张%';
  6. SELECT * FROM scores WHERE score BETWEEN 80 AND 90;
  7. SELECT DISTINCT course_name FROM courses;

第二部分:排序和限制

  1. SELECT student_name, age FROM students ORDER BY age DESC;
  2. SELECT student_name, city FROM students ORDER BY city ASC, student_name DESC;
  3. SELECT * FROM scores ORDER BY score DESC LIMIT 3;

第三部分:聚合函数和分组

  1. SELECT COUNT(*) AS total_students FROM students;
  2. SELECT AVG(score) AS avg_score, MAX(score) AS max_score, MIN(score) AS min_score FROM scores WHERE course_id = (SELECT course_id FROM courses WHERE course_name = '高等数学');
  3. SELECT s.student_id, s.student_name, SUM(sc.score) AS total_score, AVG(sc.score) AS avg_score FROM students s JOIN scores sc ON s.student_id = sc.student_id GROUP BY s.student_id, s.student_name;
  4. SELECT s.student_id, s.student_name, SUM(sc.score) AS total_score FROM students s JOIN scores sc ON s.student_id = sc.student_id GROUP BY s.student_id, s.student_name HAVING SUM(sc.score) > 250;
  5. SELECT c.course_id, c.course_name, COUNT(sc.student_id) AS student_count FROM courses c JOIN scores sc ON c.course_id = sc.course_id GROUP BY c.course_id, c.course_name HAVING COUNT(sc.student_id) >= 3;

第四部分:多表连接

  1. SELECT s.student_name, c.course_name FROM students s JOIN scores sc ON s.student_id = sc.student_id JOIN courses c ON sc.course_id = c.course_id;
  2. SELECT s.student_name, c.course_name, sc.score FROM students s JOIN scores sc ON s.student_id = sc.student_id JOIN courses c ON sc.course_id = c.course_id WHERE s.student_name = '张三';
  3. SELECT s.student_name, c.course_name, sc.score FROM students s LEFT JOIN scores sc ON s.student_id = sc.student_id AND sc.course_id = (SELECT course_id FROM courses WHERE course_name = '数据库原理') LEFT JOIN courses c ON sc.course_id = c.course_id;
  4. SELECT s.student_name FROM students s LEFT JOIN scores sc ON s.student_id = sc.student_id WHERE sc.score_id IS NULL;
  5. SELECT c.course_name, COUNT(sc.student_id) AS student_count FROM courses c LEFT JOIN scores sc ON c.course_id = sc.course_id GROUP BY c.course_id, c.course_name;

第五部分:子查询和高级应用

  1. SELECT s.student_name, sc.score FROM students s JOIN scores sc ON s.student_id = sc.student_id WHERE sc.course_id = (SELECT course_id FROM courses WHERE course_name = '高等数学') AND sc.score = (SELECT MAX(score) FROM scores WHERE course_id = (SELECT course_id FROM courses WHERE course_name = '高等数学'));
  2. SELECT s.student_name FROM students s WHERE NOT EXISTS (SELECT 1 FROM scores sc WHERE sc.student_id = s.student_id AND sc.score <= 80);
  3. SELECT student_name FROM students WHERE age = (SELECT age FROM students WHERE student_name = '张三') AND student_name != '张三';
  4. SELECT s.student_name FROM students s WHERE s.student_id IN (SELECT student_id FROM scores WHERE course_id = (SELECT course_id FROM courses WHERE course_name = '数据库原理')) AND s.student_id NOT IN (SELECT student_id FROM scores WHERE course_id = (SELECT course_id FROM courses WHERE course_name = '计算机基础'));
  5. 使用窗口函数 (MySQL 8.0+) (推荐):
    sql
    SELECT student_name, course_name, score
    FROM (
        SELECT
            s.student_name,
            c.course_name,
            sc.score,
            ROW_NUMBER() OVER(PARTITION BY sc.course_id ORDER BY sc.score DESC) as rn
        FROM scores sc
        JOIN students s ON sc.student_id = s.student_id
        JOIN courses c ON sc.course_id = c.course_id
    ) t
    WHERE rn <= 2
    ORDER BY course_name, score DESC;
    
     
     
</details>
祝你练习顺利!这些题目覆盖了大部分常用的 SQL 场景,掌握它们将对你的数据库操作能力有很大提升。
 
 

nat123映射怎么用?超详细步骤,外网访问内网轻松搞定
nat123域名怎么用?两种方式轻松搞定
nat123怎么用?简单几步实现内网穿透
内网穿透工具对比:nat123、花生壳与轻量新选择
远程访问内网很简单:用对工具,一“箭”穿透
ngrok下载完全指南:从入门到获取客户端
内网远程桌面软件:穿透局域网边界的数字窗口
从外网远程访问内网服务器的完整方案
Windows Server 2008端口转发完全教程:netsh命令添加/查看/删除/重置
为什么三层交换机转发比Linux服务器快?转发表硬件加速的秘密