学习自测与解析:MySQL 系列第三期与第四期
本笔记为第三期(DML 与单表查询)和第四期(多表查询与外键)的配套自测题解析。共十题,每题包含:题目回顾、考查知识点、详细解答与分析。
题目一:INSERT 语句的多种形式
题目 :请写出下列三种 INSERT 操作的 SQL 语句(假设表 stu 已存在,字段为 id(自增主键)、name、age、gender):
- 插入一条完整记录(id 指定为 10,name='张三', age=20, gender='M')。
- 插入两条记录,只提供 name 和 age,gender 使用默认值(默认为 'M')。
- 从另一张表
tmp_stu中复制所有年龄大于 18 岁的学生信息到stu表中(字段完全匹配)。
考查知识点
- INSERT 插入单条/多条记录(第三期 §1.1)
- 指定字段与默认值
- INSERT ... SELECT 复制数据
详细解答
sql
-- 1. 插入完整记录
INSERT INTO stu (id, name, age, gender) VALUES (10, '张三', 20, 'M');
-- 或按表顺序(如果字段完全匹配)
INSERT INTO stu VALUES (10, '张三', 20, 'M', DEFAULT); -- 假设还有 is_del 等字段
-- 2. 插入两条记录,使用默认值
INSERT INTO stu (name, age) VALUES ('李四', 22), ('王五', 19);
-- 3. 从另一张表复制数据
INSERT INTO stu (name, age, gender)
SELECT name, age, gender FROM tmp_stu WHERE age > 18;
题目二:UPDATE 的安全更新模式
题目 :MySQL 中的安全更新模式(--safe-updates)有什么作用?当启用该模式后,以下哪些 UPDATE 语句会被拒绝?为什么?
- A.
UPDATE stu SET age = 25; - B.
UPDATE stu SET age = 25 WHERE name = '张三';(name 字段无索引) - C.
UPDATE stu SET age = 25 WHERE id = 10;(id 是主键)
考查知识点
- 安全更新模式的作用与限制(第三期 §1.2)
- 索引列在 WHERE 条件中的必要性
详细解答
安全更新模式的作用:防止因忘记添加 WHERE 条件而误更新或删除全表数据。它要求 UPDATE 和 DELETE 语句的 WHERE 条件必须使用索引列(或加上 LIMIT 限制)。
- 语句 A :无条件更新全表 → 被拒绝。
- 语句 B :WHERE 条件使用了
name字段,但该字段没有索引 → 被拒绝。 - 语句 C :WHERE 条件使用了主键
id(主键自动有索引) → 允许执行。
启用方式 :命令行
mysql -U或在配置文件中添加safe-updates。
题目三:逻辑删除与物理删除的区别
题目:在生产环境中为什么通常推荐使用"逻辑删除"而不是"物理删除"?请给出实现逻辑删除的 SQL 示例,并说明查询时如何过滤掉已删除的数据。
考查知识点
- 逻辑删除与物理删除的概念(第三期 §1.3)
- 实际业务场景的数据保留策略
详细解答
区别:
- 物理删除 :使用
DELETE语句,数据从磁盘中移除,不可恢复(除非从备份中还原)。 - 逻辑删除 :使用
UPDATE语句,将某标记字段(如is_del)设为 1,数据仍保留在表中,只是被标记为"已删除"。
推荐理由:
- 数据可恢复:误删除时可以快速将标记改回 0。
- 保留历史记录:便于审计和追溯。
- 避免级联影响:保留外键关联的完整性。
实现示例:
sql
-- 添加删除标记字段
ALTER TABLE stu ADD is_del BOOLEAN DEFAULT FALSE;
-- 逻辑删除 id=11 的记录
UPDATE stu SET is_del = 1 WHERE id = 11;
-- 查询时过滤未删除的数据
SELECT * FROM stu WHERE is_del = 0;
题目四:聚合函数与 GROUP BY 的使用
题目 :现有订单表 orders(字段:order_id, customer_id, amount, order_date)。请写出 SQL 语句完成以下查询:
- 统计总订单数、总金额、平均金额、最大金额、最小金额。
- 按客户(customer_id)分组,统计每个客户的订单数量及总金额,并只显示订单数量大于等于 2 的客户。
考查知识点
- 聚合函数 COUNT, SUM, AVG, MAX, MIN(第三期 §2.3)
- GROUP BY 分组与 HAVING 过滤
详细解答
sql
-- 1. 全表统计
SELECT
COUNT(*) AS 总订单数,
SUM(amount) AS 总金额,
AVG(amount) AS 平均金额,
MAX(amount) AS 最大金额,
MIN(amount) AS 最小金额
FROM orders;
-- 2. 分组统计并过滤
SELECT
customer_id,
COUNT(*) AS 订单数量,
SUM(amount) AS 总金额
FROM orders
GROUP BY customer_id
HAVING COUNT(*) >= 2;
注意 :
HAVING用于分组后过滤,WHERE用于分组前过滤。
题目五:多表查询中的 NULL 处理
题目 :在左外连接中,如果右表没有匹配的行,右表的字段会显示为 NULL。如果需要筛选出"没有匹配"的行(例如,查询没有选课的学生),应该如何写 WHERE 条件?请以学生表 student 和选课表 sc 为例,写出 SQL。
考查知识点
- 左外连接产生的 NULL 值(第四期 §2.3)
- IS NULL 条件的应用
详细解答
查询没有选课的学生:学生左连接选课表,匹配不上的选课表字段为 NULL。筛选这些 NULL 即可。
sql
SELECT s.*
FROM student s
LEFT JOIN sc ON s.stu_id = sc.stu_id
WHERE sc.course_id IS NULL;
原理 :如果学生有选课记录,
sc.course_id非空;如果没有选课,sc.course_id为 NULL。因此用IS NULL找出未选课学生。
题目六:内连接与外连接的区别
题目:解释 INNER JOIN、LEFT JOIN 和 RIGHT JOIN 的区别。以下查询结果有何不同?
- 查询 A:
SELECT * FROM A INNER JOIN B ON A.id = B.a_id; - 查询 B:
SELECT * FROM A LEFT JOIN B ON A.id = B.a_id;
假设 A 表有 3 行(id=1,2,3),B 表有 2 行(a_id=1, a_id=1),请分别写出结果的行数(非具体数据)。
考查知识点
- 内连接、左外连接的定义与结果集范围(第四期 §2.2~2.4)
- 连接的行数估算
详细解答
区别:
INNER JOIN:只返回两表连接条件匹配的行。如果 A 的一行在 B 中匹配到多行,结果会重复该 A 行。LEFT JOIN:返回左表(A)的所有行,右表(B)匹配不上的填充 NULL。A 中的每一行至少出现一次,即使没有匹配。RIGHT JOIN:与 LEFT 相反,返回右表的所有行。
本例数据 :
A 表:id=1,2,3
B 表:a_id=1, a_id=1(两条记录,都指向 A.id=1)
- 查询 A(INNER JOIN):A.id=1 在 B 中有 2 条匹配,所以结果包含 2 行(A.id=1 重复出现两次);A.id=2 和 3 无匹配,不出现。总行数 = 2。
- 查询 B(LEFT JOIN):A.id=1 匹配 2 行 → 2 行;A.id=2 无匹配 → 1 行(B 部分为 NULL);A.id=3 无匹配 → 1 行。总行数 = 4。
题目七:自连接的应用场景
题目 :有一张员工表 emp,包含字段 emp_id(员工ID)、name(姓名)、manager_id(上级的员工ID,若为 NULL 表示无上级)。请写出 SQL 查询每个员工的姓名及其上级的姓名(没有上级的上级姓名显示为 NULL)。
考查知识点
- 自连接(SELF JOIN)的用法(第四期 §2.6)
- 左连接保留所有员工
详细解答
sql
SELECT
e.name AS 员工姓名,
m.name AS 上级姓名
FROM emp e
LEFT JOIN emp m ON e.manager_id = m.emp_id;
使用
LEFT JOIN确保没有上级的员工(manager_id 为 NULL)也被包含在结果中,且上级姓名为 NULL。
题目八:UNION 与 UNION ALL 的区别
题目 :UNION 和 UNION ALL 有何区别?在什么情况下应优先使用 UNION ALL?请举例说明。
考查知识点
- 联合查询的去重行为(第四期 §2.7)
- 性能考量
详细解答
区别:
UNION:对合并后的结果集进行去重 (类似SELECT DISTINCT),需要排序和比较,性能较低。UNION ALL:直接合并所有结果集,不去重,性能更高。
优先使用 UNION ALL 的场景:
- 确认两个子查询的结果集不会有重复行时(如按不同维度统计,或子查询条件互斥)。
- 即使有重复,但业务上允许或不需要去重时。
示例 :查询"胜率高于 70% 的英雄"和"胜率低于 45% 的英雄",这两个集合不可能有交集,应使用 UNION ALL。
sql
SELECT name, 'high' AS type FROM heroes WHERE win_rate > 70
UNION ALL
SELECT name, 'low' AS type FROM heroes WHERE win_rate < 45;
题目九:外键约束的级联操作
题目 :在 MySQL 中,创建外键时可以指定 ON DELETE CASCADE 和 ON DELETE SET NULL。请解释这两种模式的含义,并各举一个适合使用的业务场景。
考查知识点
- 外键约束模式(第四期 §3.3)
- 级联删除与置空的适用场景
详细解答
ON DELETE CASCADE(级联删除) :当主表中的记录被删除时,自动删除所有引用该记录的从表记录。
场景:订单与订单明细。删除订单时,订单明细应同时删除,否则会遗留孤儿明细数据。ON DELETE SET NULL(删除置空) :当主表记录被删除时,将从表中的外键字段设为 NULL(该字段必须允许 NULL)。
场景:部门与员工。删除部门后,希望员工记录保留,但部门字段设为 NULL,表示员工当前无归属部门。
示例 SQL:
sql
-- 级联删除
CREATE TABLE order_detail (
...,
FOREIGN KEY (order_id) REFERENCES orders(order_id) ON DELETE CASCADE
);
-- 删除置空
CREATE TABLE employee (
...,
dept_id INT NULL,
FOREIGN KEY (dept_id) REFERENCES department(dept_id) ON DELETE SET NULL
);
题目十:综合多表查询实战
题目 :基于第四期的王者荣耀数据库(表:wanjia、yingxiong、zhanji),请写出 SQL 查询"每个玩家的昵称、使用的英雄名、该英雄的胜率、以及该英雄皮肤的平均价格(假设皮肤表 pifu 通过 yingxiong_id 关联)"。要求包含所有至少有一条战绩记录的玩家,并按胜率降序排列。
考查知识点
- 多表连接(INNER JOIN + 子查询或聚合)
- 关联字段的层级(wanjia → zhanji → yingxiong → pifu)
- ORDER BY 排序
详细解答
sql
SELECT
w.wanjia_nicheng AS 玩家昵称,
y.yingxiong_ming AS 英雄名,
z.shenglv AS 胜率,
COALESCE(AVG(p.jiage), 0) AS 皮肤平均价格 -- 没有皮肤的显示 0
FROM wanjia w
INNER JOIN zhanji z ON w.wanjia_id = z.wanjia_id
INNER JOIN yingxiong y ON z.yingxiong_id = y.yingxiong_id
LEFT JOIN pifu p ON y.yingxiong_id = p.yingxiong_id
GROUP BY w.wanjia_nicheng, y.yingxiong_ming, z.shenglv
ORDER BY z.shenglv DESC;
说明 :使用
LEFT JOIN pifu确保即使英雄没有皮肤(如新英雄)也能显示 NULL 并被COALESCE转换为 0。GROUP BY按玩家+英雄分组,因为一个玩家可能多次使用同一英雄(实际zhanji表中一个玩家一个英雄只有一条记录,此处分组不影响,但规范写法需要列出所有非聚合字段)。
附:知识点对应总表
| 题号 | 主要考查知识点(对应笔记章节) |
|---|---|
| 1 | 第三期 §1.1 INSERT 插入数据(多种形式) |
| 2 | 第三期 §1.2 UPDATE 安全更新模式 |
| 3 | 第三期 §1.3 逻辑删除 vs 物理删除 |
| 4 | 第三期 §2.3 聚合函数与 GROUP BY / HAVING |
| 5 | 第四期 §2.3 左外连接与 NULL 过滤 |
| 6 | 第四期 §2.2~2.4 内连接与外连接的区别 |
| 7 | 第四期 §2.6 自连接 |
| 8 | 第四期 §2.7 UNION 与 UNION ALL |
| 9 | 第四期 §3.3 外键级联操作 |
| 10 | 第四期 §四 综合多表查询实战 |
学习建议:对于答错的题目,请回看第三期或第四期对应章节,并动手在 MySQL 环境中执行代码。熟练掌握多表查询是进阶 MySQL 高可用架构的基础。