前言

MySQL 是目前最流行的开源关系型数据库之一,广泛应用于 Web 开发、数据分析等领域。本文将从零开始,带你掌握 MySQL 最核心的 增删查改(CRUD) 操作。

什么是 CRUD?

操作 SQL 关键字 含义
Create INSERT 插入(新增)数据
Read SELECT 查询(读取)数据
Update UPDATE 更新(修改)数据
Delete DELETE 删除数据

环境准备

在开始之前,确保你已经安装了 MySQL 并能够登录:

1
2
# 登录 MySQL(输入密码后回车)
mysql -u root -p

成功登录后,你会看到 mysql> 提示符,表示可以输入 SQL 语句了。

一、数据库操作

1.1 查看所有数据库

1
SHOW DATABASES;

输出示例:

1
2
3
4
5
6
7
8
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+

1.2 创建数据库

1
2
3
4
-- 创建一个名为 my_blog 的数据库,使用 UTF-8 编码
CREATE DATABASE my_blog
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_unicode_ci;

参数说明:

  • utf8mb4:完整 UTF-8 编码,支持 emoji 表情 😊
  • utf8mb4_unicode_ci:排序规则,ci 表示大小写不敏感

1.3 选择数据库

1
USE my_blog;

1.4 查看当前使用的数据库

1
SELECT DATABASE();

1.5 删除数据库(慎用!)

1
DROP DATABASE my_blog;

⚠️ 警告:删除数据库是不可逆操作,执行前务必确认!


二、数据表操作

2.1 创建表(CREATE TABLE)

我们以一个博客系统为例,创建一个用户表:

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID,自增主键',
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名,不可重复',
email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱',
password VARCHAR(255) NOT NULL COMMENT '密码(实际应存储哈希值)',
nickname VARCHAR(50) DEFAULT '' COMMENT '昵称,默认为空',
avatar VARCHAR(255) DEFAULT '' COMMENT '头像URL',
bio TEXT COMMENT '个人简介',
status TINYINT DEFAULT 1 COMMENT '状态:1=正常,0=禁用',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

常用数据类型速查:

类型 说明 示例
INT 整数 age INT
BIGINT 大整数 id BIGINT
VARCHAR(n) 可变长度字符串,最多 n 个字符 name VARCHAR(100)
CHAR(n) 固定长度字符串 code CHAR(6)
TEXT 长文本(最大 65535 字符) content TEXT
LONGTEXT 超长文本 body LONGTEXT
DATE 日期(YYYY-MM-DD) birthday DATE
DATETIME 日期时间 created_at DATETIME
DECIMAL(m,n) 精确小数(m 位总长,n 位小数) price DECIMAL(10,2)
TINYINT 小整数(0~255),常用于状态 status TINYINT
BOOLEAN 布尔值(实际是 TINYINT(1)) is_deleted BOOLEAN

2.2 查看当前数据库下所有表

1
SHOW TABLES;

2.3 查看表结构

1
2
3
4
5
-- 查看字段详情
DESC users;

-- 查看建表语句(包含注释等完整信息)
SHOW CREATE TABLE users;

DESC users 输出示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+------------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+-------------------+-----------------------------+
| id | int | NO | PRI | NULL | auto_increment |
| username | varchar(50) | NO | UNI | NULL | |
| email | varchar(100) | NO | UNI | NULL | |
| password | varchar(255) | NO | | NULL | |
| nickname | varchar(50) | YES | | | |
| avatar | varchar(255) | YES | | | |
| bio | text | YES | | NULL | |
| status | tinyint | YES | | 1 | |
| created_at | datetime | YES | | CURRENT_TIMESTAMP | |
| updated_at | datetime | YES | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+------------+--------------+------+-----+-------------------+-----------------------------+

2.4 修改表结构(ALTER TABLE)

1
2
3
4
5
6
7
8
9
10
11
-- 添加新列
ALTER TABLE users ADD COLUMN phone VARCHAR(20) COMMENT '手机号' AFTER email;

-- 修改列定义
ALTER TABLE users MODIFY COLUMN nickname VARCHAR(50) NOT NULL DEFAULT '匿名用户';

-- 重命名列
ALTER TABLE users CHANGE COLUMN bio introduction TEXT COMMENT '个人介绍';

-- 删除列(慎用!)
ALTER TABLE users DROP COLUMN phone;

2.5 删除表(慎用!)

1
DROP TABLE IF EXISTS users;

三、插入数据(INSERT)

3.1 插入单条记录

1
2
INSERT INTO users (username, email, password, nickname, bio)
VALUES ('zhangsan', 'zhangsan@example.com', 'hashed_password_123', '张三', '一名热爱编程的全栈工程师');

3.2 插入多条记录

1
2
3
4
5
6
INSERT INTO users (username, email, password, nickname, bio) VALUES
('lisi', 'lisi@example.com', 'pass_lisi', '李四', '前端开发工程师'),
('wangwu', 'wangwu@example.com', 'pass_wangwu', '王五', '后端开发工程师'),
('zhaoliu', 'zhaoliu@example.com', 'pass_zhaoliu', '赵六', 'DevOps 工程师'),
('sunqi', 'sunqi@example.com', 'pass_sunqi', '孙七', '数据分析师'),
('zhouba', 'zhouba@example.com', 'pass_zhouba', '周八', '产品经理');

3.3 插入部分字段(其余使用默认值)

1
2
3
INSERT INTO users (username, email, password)
VALUES ('wujiu', 'wujiu@example.com', 'pass_wujiu');
-- nickname 将使用默认值 '',status 使用默认值 1

3.4 忽略重复(INSERT IGNORE)

当遇到唯一键冲突时跳过而不报错:

1
2
3
INSERT IGNORE INTO users (username, email, password, nickname)
VALUES ('zhangsan', 'zhangsan@example.com', 'new_pass', '张三三');
-- 因为 username 和 email 已存在,此条被跳过

3.5 存在则更新(ON DUPLICATE KEY UPDATE)

1
2
3
4
5
6
INSERT INTO users (username, email, password, nickname)
VALUES ('zhangsan', 'zhangsan@example.com', 'new_hashed_password', '张三疯')
ON DUPLICATE KEY UPDATE
nickname = VALUES(nickname),
password = VALUES(password);
-- 如果 username 或 email 已存在,则更新 nickname 和 password

四、查询数据(SELECT)⭐

SELECT 是 SQL 中最常用也最强大的语句。让我们一步步掌握它。

4.1 查询所有列

1
SELECT * FROM users;

💡 实际开发中尽量避免 SELECT *,应明确指定需要的列以提高性能。

4.2 查询指定列

1
SELECT id, username, nickname, created_at FROM users;

结果示例:

1
2
3
4
5
6
7
8
9
10
11
+----+----------+----------+---------------------+
| id | username | nickname | created_at |
+----+----------+----------+---------------------+
| 1 | zhangsan | 张三 | 2026-05-30 14:00:00 |
| 2 | lisi | 李四 | 2026-05-30 14:00:00 |
| 3 | wangwu | 王五 | 2026-05-30 14:00:00 |
| 4 | zhaoliu | 赵六 | 2026-05-30 14:00:00 |
| 5 | sunqi | 孙七 | 2026-05-30 14:00:00 |
| 6 | zhouba | 周八 | 2026-05-30 14:00:00 |
| 7 | wujiu | | 2026-05-30 14:00:00 |
+----+----------+----------+---------------------+

4.3 使用别名(AS)

1
2
3
4
5
6
SELECT
id AS '用户ID',
username AS '用户名',
nickname AS '昵称',
created_at AS '注册时间'
FROM users;

4.4 WHERE — 条件筛选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 精确匹配
SELECT * FROM users WHERE username = 'zhangsan';

-- 模糊匹配(LIKE)
SELECT * FROM users WHERE nickname LIKE '%张%'; -- 昵称包含"张"

-- 多条件 AND
SELECT * FROM users WHERE status = 1 AND nickname != '';

-- 多条件 OR
SELECT * FROM users WHERE username = 'zhangsan' OR username = 'lisi';

-- IN 条件
SELECT * FROM users WHERE id IN (1, 2, 3);

-- BETWEEN 范围
SELECT * FROM users WHERE id BETWEEN 2 AND 5;

-- IS NULL / IS NOT NULL
SELECT * FROM users WHERE bio IS NOT NULL;

-- 比较运算符
SELECT * FROM users WHERE id > 3;
SELECT * FROM users WHERE created_at >= '2026-01-01';

LIKE 通配符说明:

通配符 含义 示例
% 匹配任意数量字符(包括 0 个) '%张%' 包含”张”
_ 匹配单个字符 '张_' “张”后面跟一个字符

4.5 ORDER BY — 排序

1
2
3
4
5
6
7
8
9
-- 升序(ASC,默认)
SELECT * FROM users ORDER BY id ASC;

-- 降序(DESC)
SELECT * FROM users ORDER BY id DESC;

-- 多列排序
SELECT * FROM users ORDER BY status DESC, created_at ASC;
-- 先按 status 降序,再按 created_at 升序

4.6 LIMIT — 分页查询

1
2
3
4
5
6
7
8
-- 查询前 3 条
SELECT * FROM users LIMIT 3;

-- 跳过前 2 条后取 3 条(分页)
SELECT * FROM users LIMIT 2, 3; -- 第 3~5 条

-- 另一种分页写法(更易读)
SELECT * FROM users LIMIT 3 OFFSET 2; -- 跳过 2 条,取 3 条

分页公式: 第 N 页 = LIMIT (N-1) × pageSize, pageSize

4.7 DISTINCT — 去重

1
SELECT DISTINCT status FROM users;

4.8 聚合函数

先创建一张文章表,方便演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 创建文章表
CREATE TABLE posts (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL COMMENT '作者ID',
title VARCHAR(200) NOT NULL COMMENT '标题',
content LONGTEXT COMMENT '正文',
views INT DEFAULT 0 COMMENT '阅读量',
status TINYINT DEFAULT 1 COMMENT '1=已发布 0=草稿',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章表';

-- 插入一些测试数据
INSERT INTO posts (user_id, title, content, views, status) VALUES
(1, 'MySQL入门指南', 'MySQL是...', 1560, 1),
(2, 'JavaScript异步编程', 'JavaScript异步...', 892, 1),
(1, 'Linux常用命令', 'Linux是...', 2340, 1),
(3, 'Python数据分析入门', 'Python在数据...', 478, 1),
(2, 'CSS Grid布局详解', 'CSS Grid是...', 1200, 1),
(1, 'Git版本控制入门', 'Git是...', 320, 0),
(4, 'Docker容器化部署', 'Docker是...', 1100, 1);
1
2
3
4
5
6
7
8
9
10
11
12
-- COUNT:统计总数
SELECT COUNT(*) AS '文章总数' FROM posts;
SELECT COUNT(*) AS '已发布文章数' FROM posts WHERE status = 1;

-- SUM:求和
SELECT SUM(views) AS '总阅读量' FROM posts;

-- AVG:平均值
SELECT AVG(views) AS '平均阅读量' FROM posts;

-- MAX / MIN:最大/最小值
SELECT MAX(views) AS '最高阅读量', MIN(views) AS '最低阅读量' FROM posts;

4.9 GROUP BY — 分组统计

1
2
3
4
5
6
7
8
-- 统计每个用户的文章数和总阅读量
SELECT
user_id,
COUNT(*) AS '文章数',
SUM(views) AS '总阅读量',
AVG(views) AS '平均阅读量'
FROM posts
GROUP BY user_id;

结果示例:

1
2
3
4
5
6
7
8
+---------+--------+----------+------------+
| user_id | 文章数 | 总阅读量 | 平均阅读量 |
+---------+--------+----------+------------+
| 1 | 3 | 4220 | 1406.6667 |
| 2 | 2 | 2092 | 1046.0000 |
| 3 | 1 | 478 | 478.0000 |
| 4 | 1 | 1100 | 1100.0000 |
+---------+--------+----------+------------+

4.10 HAVING — 对分组结果过滤

1
2
3
4
5
6
7
8
9
-- 找出发布文章数 >= 2 的用户
SELECT
user_id,
COUNT(*) AS '文章数'
FROM posts
WHERE status = 1 -- WHERE 过滤原始行
GROUP BY user_id
HAVING COUNT(*) >= 2 -- HAVING 过滤分组结果
ORDER BY 文章数 DESC;

💡 WHERE vs HAVINGWHERE 在分组之前过滤行,HAVING 在分组之后过滤组。

4.11 JOIN — 多表联查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- INNER JOIN:只返回匹配的记录(交集)
SELECT
p.id,
p.title,
u.username,
u.nickname,
p.views,
p.created_at
FROM posts AS p
INNER JOIN users AS u ON p.user_id = u.id;

-- LEFT JOIN:返回左表所有记录,右表无匹配则填 NULL
SELECT
u.id,
u.username,
COUNT(p.id) AS '文章数'
FROM users AS u
LEFT JOIN posts AS p ON u.id = p.user_id
GROUP BY u.id;

LEFT JOIN 结果示例:

1
2
3
4
5
6
7
8
9
10
11
+----+----------+--------+
| id | username | 文章数 |
+----+----------+--------+
| 1 | zhangsan | 3 |
| 2 | lisi | 2 |
| 3 | wangwu | 1 |
| 4 | zhaoliu | 1 |
| 5 | sunqi | 0 | ← LEFT JOIN 保证出现,文章数为 0
| 6 | zhouba | 0 |
| 7 | wujiu | 0 |
+----+----------+--------+

JOIN 类型图解:

JOIN 类型 说明
INNER JOIN 两表都匹配的记录(交集)
LEFT JOIN 左表全部记录 + 右表匹配
RIGHT JOIN 右表全部记录 + 左表匹配
FULL JOIN 两表全部记录(MySQL 不直接支持,用 UNION 模拟)

4.12 子查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- 查询阅读量大于平均阅读量的文章
SELECT title, views
FROM posts
WHERE views > (SELECT AVG(views) FROM posts);

-- 查询发表过文章的用户(用 IN)
SELECT username
FROM users
WHERE id IN (SELECT DISTINCT user_id FROM posts);

-- 查询每个用户最新文章(相关子查询)
SELECT title, user_id, created_at
FROM posts AS p1
WHERE created_at = (
SELECT MAX(created_at)
FROM posts AS p2
WHERE p2.user_id = p1.user_id
);

4.13 UNION — 合并查询结果

1
2
3
4
5
6
7
8
9
-- 合并两个查询结果(自动去重)
SELECT username AS name FROM users WHERE id <= 3
UNION
SELECT nickname AS name FROM users WHERE nickname != '';

-- UNION ALL:不去重,性能更好
SELECT username AS name FROM users WHERE id <= 3
UNION ALL
SELECT nickname AS name FROM users WHERE nickname != '';

4.14 常用查询函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-- 字符串函数
SELECT CONCAT(username, ' (', nickname, ')') AS '用户标识' FROM users;
SELECT LENGTH(nickname) AS '昵称长度' FROM users;
SELECT UPPER(username) FROM users;
SELECT SUBSTRING(bio, 1, 20) AS '简介摘要' FROM users;

-- 日期函数
SELECT NOW() AS '当前时间';
SELECT DATE(created_at) AS '日期' FROM users;
SELECT DATEDIFF(NOW(), created_at) AS '注册天数' FROM users;
SELECT YEAR(created_at) AS '年', MONTH(created_at) AS '月' FROM users;

-- 数学函数
SELECT ROUND(AVG(views), 2) FROM posts;
SELECT CEIL(3.14); -- 向上取整 → 4
SELECT FLOOR(3.14); -- 向下取整 → 3
SELECT RAND(); -- 随机数 0~1

-- 条件函数
SELECT
title,
CASE
WHEN views >= 1000 THEN '热门'
WHEN views >= 500 THEN '普通'
ELSE '冷门'
END AS '热度等级'
FROM posts;

-- IFNULL:空值替换
SELECT username, IFNULL(nickname, '未设置昵称') AS '显示名' FROM users;

五、更新数据(UPDATE)

⚠️ 非常重要:务必带上 WHERE 条件!否则会更新整张表!

5.1 更新单列

1
2
-- 修改某用户的昵称
UPDATE users SET nickname = '张三三' WHERE username = 'zhangsan';

5.2 更新多列

1
2
3
4
5
6
UPDATE users
SET
nickname = '李四四',
bio = '高级前端工程师,React 爱好者',
avatar = 'https://cdn.example.com/avatars/lisi.jpg'
WHERE username = 'lisi';

5.3 基于原值更新

1
2
3
4
5
-- 文章阅读量 +1
UPDATE posts SET views = views + 1 WHERE id = 1;

-- 文章阅读量增加指定数值
UPDATE posts SET views = views + 100 WHERE user_id = 1;

5.4 条件更新

1
2
3
4
5
6
7
8
9
-- 将阅读量低于 500 的文章设为草稿
UPDATE posts
SET status = 0
WHERE views < 500;

-- 更新最近一周创建的记录
UPDATE users
SET status = 1
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY);

5.5 安全更新模式(推荐开启)

1
2
-- 开启安全更新模式(防止无 WHERE 条件的 UPDATE/DELETE)
SET SQL_SAFE_UPDATES = 1;

开启后,不带 WHERE 条件或 WHERE 条件不使用索引的 UPDATE/DELETE 会报错。


六、删除数据(DELETE)

⚠️ 再次强调:务必带上 WHERE 条件!

6.1 条件删除

1
2
3
4
5
-- 删除指定用户
DELETE FROM users WHERE username = 'wujiu';

-- 删除满足条件的多条记录
DELETE FROM posts WHERE status = 0 AND created_at < '2025-01-01';

6.2 清空表(TRUNCATE)

1
2
3
4
5
-- 清空文章表所有数据(不可回滚,自增 ID 重置)
TRUNCATE TABLE posts;

-- DELETE 也可以清空表,但逐行删除,可回滚,自增 ID 不重置
DELETE FROM posts;
对比 DELETE TRUNCATE
速度 慢(逐行删除) 快(直接删除数据页)
自增 ID 保留原值 重置为 1
事务回滚 ✅ 支持 ❌ 不支持
WHERE 条件 ✅ 支持 ❌ 不支持

6.3 软删除(推荐)

生产环境中通常使用软删除而不是物理删除:

1
2
3
4
5
6
7
8
9
-- 添加软删除标记字段
ALTER TABLE users ADD COLUMN is_deleted TINYINT DEFAULT 0 COMMENT '0=正常 1=已删除';
ALTER TABLE users ADD COLUMN deleted_at DATETIME DEFAULT NULL COMMENT '删除时间';

-- "删除"操作变成 UPDATE
UPDATE users SET is_deleted = 1, deleted_at = NOW() WHERE id = 5;

-- 查询时过滤已删除记录
SELECT * FROM users WHERE is_deleted = 0;

七、实战场景综合示例

场景:博客后台的常见查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
-- 1. 搜索文章标题或内容
SELECT id, title, LEFT(content, 100) AS '摘要'
FROM posts
WHERE title LIKE '%MySQL%' OR content LIKE '%MySQL%'
AND status = 1
ORDER BY created_at DESC
LIMIT 10;

-- 2. 热门文章 Top 5
SELECT title, views
FROM posts
WHERE status = 1
ORDER BY views DESC
LIMIT 5;

-- 3. 按日期统计发文量
SELECT DATE(created_at) AS '日期', COUNT(*) AS '发文数'
FROM posts
WHERE status = 1
GROUP BY DATE(created_at)
ORDER BY 日期 DESC;

-- 4. 查询每位作者的最新文章
SELECT
u.username,
u.nickname,
p.title,
p.views,
p.created_at
FROM users u
INNER JOIN posts p ON u.id = p.user_id
INNER JOIN (
SELECT user_id, MAX(created_at) AS latest
FROM posts
WHERE status = 1
GROUP BY user_id
) latest_post ON p.user_id = latest_post.user_id AND p.created_at = latest_post.latest;

-- 5. 文章归档(按年月)
SELECT
DATE_FORMAT(created_at, '%Y-%m') AS '月份',
COUNT(*) AS '文章数'
FROM posts
WHERE status = 1
GROUP BY DATE_FORMAT(created_at, '%Y-%m')
ORDER BY 月份 DESC;

八、最佳实践建议

  1. 永远使用 WHERE 条件执行 UPDATE 和 DELETE,先 SELECT 验证再操作
  2. 在生产环境开启 SQL_SAFE_UPDATES,避免误操作
  3. 使用软删除代替物理删除,保留数据可追溯
  4. 查询时指定列名,避免 SELECT *
  5. 为经常查询的列建立索引(WHERE、JOIN、ORDER BY 涉及的列)
  6. 定期备份数据库,使用 mysqldump 工具
  7. 密码永远存储哈希值,不要明文存储

九、常用 MySQL 命令速查表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-- 数据库操作
CREATE DATABASE db_name; -- 创建数据库
DROP DATABASE db_name; -- 删除数据库
USE db_name; -- 切换数据库
SHOW DATABASES; -- 查看所有数据库

-- 表操作
CREATE TABLE t (...); -- 建表
DESC t; -- 查看表结构
SHOW CREATE TABLE t; -- 查看建表语句
ALTER TABLE t ADD COLUMN ...; -- 添加列
ALTER TABLE t MODIFY ...; -- 修改列
ALTER TABLE t DROP COLUMN ...;-- 删除列
DROP TABLE t; -- 删除表

-- 数据操作
INSERT INTO t (col1, col2) VALUES (v1, v2);
SELECT col1, col2 FROM t WHERE condition ORDER BY col LIMIT n;
UPDATE t SET col1 = v1 WHERE condition;
DELETE FROM t WHERE condition;

-- 常用函数
COUNT(), SUM(), AVG(), MAX(), MIN()
CONCAT(), SUBSTRING(), UPPER(), LOWER()
NOW(), CURDATE(), DATE_FORMAT(), DATEDIFF()
IFNULL(), COALESCE()

结语

本文涵盖了 MySQL 最核心的 增删查改(CRUD) 操作,从创建数据库和表,到基本的 INSERT、SELECT、UPDATE、DELETE,再到多表联查、子查询、聚合统计等进阶用法。

掌握这些基础后,你已经能够应对日常开发中 80% 以上的数据库操作场景。接下来建议深入学习:

  • 索引优化:提升查询性能
  • 事务与锁:保证数据一致性
  • 视图与存储过程:简化复杂操作
  • 数据库设计范式:设计合理的表结构

实践是最好的学习方式——现在就打开你的 MySQL 终端,试试这些 SQL 吧!💪