MySQL 学习练习(配套 01 入门资料)

MySQL 学习练习(配套 01 入门资料)

目标:每学完一章就动手练,巩固肌肉记忆。所有练习基于同一个示例库 shop_demo

建议:先自己写 SQL,再看文末参考答案,对比差异。

难度标记:★ 基础 ★★ 进阶 ★★★ 综合

复制代码
编程资源
https://pan.quark.cn/s/7f7c83756948
更多资源
https://pan.quark.cn/s/bda57957c548

准备工作:初始化示例库

把下面整段在 MySQL 里执行一次,得到练习用的 shop_demo 库(含 users / products / orders / order_items 四张表与数据)。

sql 复制代码
DROP DATABASE IF EXISTS shop_demo;
CREATE DATABASE shop_demo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE shop_demo;

CREATE TABLE users (
    id         INT PRIMARY KEY AUTO_INCREMENT,
    username   VARCHAR(50) NOT NULL,
    city       VARCHAR(50),
    age        TINYINT UNSIGNED,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE products (
    id     INT PRIMARY KEY AUTO_INCREMENT,
    name   VARCHAR(100) NOT NULL,
    price  DECIMAL(10,2) NOT NULL,
    stock  INT NOT NULL DEFAULT 0,
    category VARCHAR(50)
);

CREATE TABLE orders (
    id        INT PRIMARY KEY AUTO_INCREMENT,
    user_id   INT NOT NULL,
    amount    DECIMAL(10,2) NOT NULL,
    status    VARCHAR(20) DEFAULT 'pending',
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

CREATE TABLE order_items (
    id         INT PRIMARY KEY AUTO_INCREMENT,
    order_id   INT NOT NULL,
    product_id INT NOT NULL,
    qty        INT NOT NULL,
    price      DECIMAL(10,2) NOT NULL,
    FOREIGN KEY (order_id) REFERENCES orders(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);

INSERT INTO users (username, city, age) VALUES
 ('alice','Beijing',28), ('bob','Shanghai',34), ('carol','Beijing',22),
 ('dave','Shenzhen',41), ('erin','Shanghai',19), ('frank','Beijing',30);

INSERT INTO products (name, price, stock, category) VALUES
 ('Keyboard',199.00,120,'electronics'), ('Mouse',89.50,200,'electronics'),
 ('Notebook',12.00,500,'stationery'), ('Monitor',1299.00,40,'electronics'),
 ('Pen',5.50,1000,'stationery');

INSERT INTO orders (user_id, amount, status) VALUES
 (1,288.50,'paid'), (2,1299.00,'paid'), (1,12.00,'pending'),
 (3,89.50,'paid'), (4,1407.50,'shipped'), (5,199.00,'pending');

INSERT INTO order_items (order_id, product_id, qty, price) VALUES
 (1,1,1,199.00), (1,2,1,89.50),
 (2,4,1,1299.00),
 (3,3,1,12.00),
 (4,2,1,89.50),
 (5,4,1,1299.00), (5,1,1,199.00) /* 注意:order 5 amount 写的是 199,刻意为之,见练习19 */,
 (6,1,1,199.00);

第 3 章 建库建表 ★

练习 1 :创建一个库 test_db,字符集 utf8mb4

练习 2 :在 shop_demo 中新建表 categories(id, name),并给 products 加上外键 category_id 指向它。

练习 3 :给 users 增加列 phone VARCHAR(20),再删除它。


第 5 章 CRUD ★

练习 4 :插入一名用户 gary,城市 Chengdu,年龄 27。

练习 5 :把 bob 的年龄改成 35。

练习 6 :删除用户 frank(注意外键:先处理其订单或临时禁用外键检查)。

练习 7 :查询 products 所有商品,只显示 nameprice


第 6 章 条件查询 ★★

练习 8 :查询年龄 ≥ 30 的用户。

练习 9 :查询城市在 BeijingShanghai 的用户。

练习 10 :查询用户名以 a 开头的用户(LIKE)。

练习 11:查询没有填城市(city 为 NULL)的用户。


第 7 章 排序与分页 ★★

练习 12 :按年龄降序查询用户,取前 3 名。

练习 13:按每页 2 条,查询第 2 页用户(按 id 排序)。


第 8 章 聚合与分组 ★★

练习 14 :统计各城市的用户数量。

练习 15 :统计各城市平均年龄大于 25 的城市及其平均年龄。

练习 16 :计算 productselectronics 类商品的总库存与平均价格。


第 9 章 多表连接 ★★★

练习 17 :列出每笔订单的订单号、下单用户名、金额(orders JOIN users)。

练习 18 :列出每个用户名及其订单数(含 0 单的用户,用 LEFT JOIN + COUNT)。

练习 19 :找出 orders.amount 与实际 order_items 明细金额不一致 的订单(数据质量校验,提示:用子查询或 JOIN + GROUP BY 汇总明细再比较)。

练习 20 :查询买了 Monitor(显示器)的用户名。


第 11 章 索引 ★★

练习 21 :为 orders.user_id 建普通索引,再查看索引列表。

练习 22 :为 users(city, age) 建联合索引,思考哪些查询能命中(最左前缀)。


第 14 章 事务 ★★★

练习 23 :模拟转账------从 users 角度设计一个「积分账户表 wallet(user_id, balance)」,用事务完成 A 给 B 转 100 分,并提交;再演示中途 ROLLBACK 的效果。

练习 24 :故意在事务中写一条会报错的 SQL(如插入重复主键),观察 ROLLBACK 后数据是否回退。


进阶综合 ★★★

练习 25 :统计「已支付(paid)订单」中,每个用户的累计消费金额,按金额降序。

练习 26 :找出销量(order_items.qty 总和)最高的前 3 个商品及其销量。

练习 27 :用 CASE 给用户打标签:age<25「青年」、25--40「中年」、>40「资深」,并统计各标签人数。


参考答案

练习 1

sql 复制代码
CREATE DATABASE test_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

练习 2

sql 复制代码
CREATE TABLE categories (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50));
ALTER TABLE products ADD COLUMN category_id INT;
ALTER TABLE products ADD CONSTRAINT fk_cat
  FOREIGN KEY (category_id) REFERENCES categories(id);

练习 3

sql 复制代码
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
ALTER TABLE users DROP COLUMN phone;

练习 4

sql 复制代码
INSERT INTO users (username, city, age) VALUES ('gary','Chengdu',27);

练习 5

sql 复制代码
UPDATE users SET age = 35 WHERE username = 'bob';

练习 6(先删子表引用,再删父表)

sql 复制代码
DELETE FROM orders WHERE user_id = (SELECT id FROM users WHERE username='frank');
DELETE FROM users WHERE username = 'frank';
-- 或临时:SET FOREIGN_KEY_CHECKS=0; ... SET FOREIGN_KEY_CHECKS=1;

练习 7

sql 复制代码
SELECT name, price FROM products;

练习 8

sql 复制代码
SELECT * FROM users WHERE age >= 30;

练习 9

sql 复制代码
SELECT * FROM users WHERE city IN ('Beijing','Shanghai');

练习 10

sql 复制代码
SELECT * FROM users WHERE username LIKE 'a%';

练习 11

sql 复制代码
SELECT * FROM users WHERE city IS NULL;

练习 12

sql 复制代码
SELECT * FROM users ORDER BY age DESC LIMIT 3;

练习 13

sql 复制代码
SELECT * FROM users ORDER BY id LIMIT 2, 2;  -- 偏移2,取2条 = 第2页

练习 14

sql 复制代码
SELECT city, COUNT(*) AS cnt FROM users GROUP BY city;

练习 15

sql 复制代码
SELECT city, AVG(age) AS avg_age
FROM users GROUP BY city HAVING AVG(age) > 25;

练习 16

sql 复制代码
SELECT SUM(stock) AS total_stock, AVG(price) AS avg_price
FROM products WHERE category = 'electronics';

练习 17

sql 复制代码
SELECT o.id AS order_no, u.username, o.amount
FROM orders o
JOIN users u ON o.user_id = u.id;

练习 18

sql 复制代码
SELECT u.username, COUNT(o.id) AS order_cnt
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username;

练习 19(汇总明细比对)

sql 复制代码
SELECT o.id, o.amount, SUM(oi.qty * oi.price) AS detail_sum
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
GROUP BY o.id, o.amount
HAVING o.amount <> SUM(oi.qty * oi.price);
-- 预期命中 order_id = 5(amount 199 vs 明细 1498)

练习 20

sql 复制代码
SELECT DISTINCT u.username
FROM users u
JOIN orders o ON u.id = o.user_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE p.name = 'Monitor';

练习 21

sql 复制代码
CREATE INDEX idx_user_id ON orders(user_id);
SHOW INDEX FROM orders;

练习 22

sql 复制代码
CREATE INDEX idx_city_age ON users(city, age);
-- 命中:(city) 或 (city, age);不命中:仅 (age)

练习 23

sql 复制代码
CREATE TABLE wallet (user_id INT PRIMARY KEY, balance INT NOT NULL DEFAULT 0);
INSERT INTO wallet VALUES (1, 500), (2, 300);
START TRANSACTION;
UPDATE wallet SET balance = balance - 100 WHERE user_id = 1;
UPDATE wallet SET balance = balance + 100 WHERE user_id = 2;
COMMIT;
-- 中途若执行 ROLLBACK; 则两条 UPDATE 都撤销

练习 24

sql 复制代码
START TRANSACTION;
INSERT INTO users (id, username) VALUES (1, 'dup'); -- 假设 id=1 已存在 → 报错
ROLLBACK; -- 即使前面有成功的语句也会一起回退

练习 25

sql 复制代码
SELECT u.username, SUM(o.amount) AS total
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'paid'
GROUP BY u.id, u.username
ORDER BY total DESC;

练习 26

sql 复制代码
SELECT p.name, SUM(oi.qty) AS sales
FROM order_items oi
JOIN products p ON oi.product_id = p.id
GROUP BY p.id, p.name
ORDER BY sales DESC
LIMIT 3;

练习 27

sql 复制代码
SELECT
  CASE WHEN age < 25 THEN '青年'
       WHEN age <= 40 THEN '中年'
       ELSE '资深' END AS tag,
  COUNT(*) AS cnt
FROM users
GROUP BY tag;

自测清单

  • 能独立写出建库、建表、插数据的完整脚本
  • 清楚 WHEREHAVING 的区别
  • 能画出 INNER / LEFT / RIGHT JOIN 的结果差异
  • 理解 UPDATE/DELETE 漏写 WHERE 的后果
  • 能说出索引「最左前缀」是什么
  • 能手写一段转账事务

全部打勾 → 进入 03-精通学习资料.md

复制代码
编程资源
https://pan.quark.cn/s/7f7c83756948
更多资源
https://pan.quark.cn/s/bda57957c548
相关推荐
梦雨生生2 小时前
java开发工具(学习第一天)
java·开发语言·学习
数据库小学妹2 小时前
数据库等保三级和四级有什么区别?从访问控制到备份恢复的完整对比
数据库·安全·数据库安全·三级等保·等保合规·四级等保
看浪的路人3 小时前
第3讲:手写第一个 MCP Server(Python SDK)
jvm·数据库·oracle
大眼、不聚光4 小时前
5.mysql--主从同步安装部署
数据库·mysql
Yan_chen6664 小时前
SQL-LABS_Less18-20实战攻略
数据库·sql·web安全·网络安全
oradh4 小时前
Oracle RAC OCR维护操作总结
数据库·oracle·ocr·rac ocr维护·ocr维护·vote disk
snow@li5 小时前
HikariCP:高性能数据库连接池全景深入梳理
java·数据库
一个天蝎座的程序猿6 小时前
传统数据库迁金仓KES,空值问题差点让财务报表翻车
数据库
wWYy.6 小时前
Mysql:索引下推
数据库·mysql