前言 MySQL 是目前最流行的开源关系型数据库之一,广泛应用于 Web 开发、数据分析等领域。本文将从零开始,带你掌握 MySQL 最核心的 增删查改(CRUD) 操作。
什么是 CRUD?
操作
SQL 关键字
含义
C reate
INSERT
插入(新增)数据
R ead
SELECT
查询(读取)数据
U pdate
UPDATE
更新(修改)数据
D elete
DELETE
删除数据
环境准备 在开始之前,确保你已经安装了 MySQL 并能够登录:
成功登录后,你会看到 mysql> 提示符,表示可以输入 SQL 语句了。
一、数据库操作 1.1 查看所有数据库
输出示例:
1 2 3 4 5 6 7 8 +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+
1.2 创建数据库 1 2 3 4 CREATE DATABASE my_blog DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
参数说明:
utf8mb4:完整 UTF-8 编码,支持 emoji 表情 😊
utf8mb4_unicode_ci:排序规则,ci 表示大小写不敏感
1.3 选择数据库
1.4 查看当前使用的数据库
1.5 删除数据库(慎用!)
⚠️ 警告 :删除数据库是不可逆操作,执行前务必确认!
二、数据表操作 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 查看当前数据库下所有表
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' );
3.4 忽略重复(INSERT IGNORE) 当遇到唯一键冲突时跳过而不报错:
1 2 3 INSERT IGNORE INTO users (username, email, password, nickname)VALUES ('zhangsan' , 'zhangsan@example.com' , 'new_pass' , '张三三' );
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);
四、查询数据(SELECT)⭐ SELECT 是 SQL 中最常用也最强大的语句。让我们一步步掌握它。
4.1 查询所有列
💡 实际开发中尽量避免 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' ;SELECT * FROM users WHERE nickname LIKE '%张%' ; SELECT * FROM users WHERE status = 1 AND nickname != '' ;SELECT * FROM users WHERE username = 'zhangsan' OR username = 'lisi' ;SELECT * FROM users WHERE id IN (1 , 2 , 3 );SELECT * FROM users WHERE id BETWEEN 2 AND 5 ;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 SELECT * FROM users ORDER BY id ASC ;SELECT * FROM users ORDER BY id DESC ;SELECT * FROM users ORDER BY status DESC , created_at ASC ;
4.6 LIMIT — 分页查询 1 2 3 4 5 6 7 8 SELECT * FROM users LIMIT 3 ;SELECT * FROM users LIMIT 2 , 3 ; SELECT * FROM users LIMIT 3 OFFSET 2 ;
分页公式: 第 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 SELECT COUNT (* ) AS '文章总数' FROM posts;SELECT COUNT (* ) AS '已发布文章数' FROM posts WHERE status = 1 ;SELECT SUM (views) AS '总阅读量' FROM posts;SELECT AVG (views) AS '平均阅读量' FROM posts;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 postsGROUP 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 SELECT user_id, COUNT (* ) AS '文章数' FROM postsWHERE status = 1 GROUP BY user_idHAVING COUNT (* ) >= 2 ORDER BY 文章数 DESC ;
💡 WHERE vs HAVING :WHERE 在分组之前 过滤行,HAVING 在分组之后 过滤组。
4.11 JOIN — 多表联查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 SELECT p.id, p.title, u.username, u.nickname, p.views, p.created_at FROM posts AS pINNER JOIN users AS u ON p.user_id = u.id;SELECT u.id, u.username, COUNT (p.id) AS '文章数' FROM users AS uLEFT JOIN posts AS p ON u.id = p.user_idGROUP 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, viewsFROM postsWHERE views > (SELECT AVG (views) FROM posts);SELECT usernameFROM usersWHERE id IN (SELECT DISTINCT user_id FROM posts);SELECT title, user_id, created_atFROM posts AS p1WHERE 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 != '' ;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 ); SELECT FLOOR (3.14 ); SELECT RAND(); SELECT title, CASE WHEN views >= 1000 THEN '热门' WHEN views >= 500 THEN '普通' ELSE '冷门' END AS '热度等级' FROM posts;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 usersSET nickname = '李四四' , bio = '高级前端工程师,React 爱好者' , avatar = 'https://cdn.example.com/avatars/lisi.jpg' WHERE username = 'lisi' ;
5.3 基于原值更新 1 2 3 4 5 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 UPDATE postsSET status = 0 WHERE views < 500 ;UPDATE usersSET status = 1 WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY );
5.5 安全更新模式(推荐开启) 1 2 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 TRUNCATE TABLE posts;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 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 SELECT id, title, LEFT (content, 100 ) AS '摘要' FROM postsWHERE title LIKE '%MySQL%' OR content LIKE '%MySQL%' AND status = 1 ORDER BY created_at DESC LIMIT 10 ; SELECT title, viewsFROM postsWHERE status = 1 ORDER BY views DESC LIMIT 5 ; SELECT DATE (created_at) AS '日期' , COUNT (* ) AS '发文数' FROM postsWHERE status = 1 GROUP BY DATE (created_at)ORDER BY 日期 DESC ;SELECT u.username, u.nickname, p.title, p.views, p.created_at FROM users uINNER JOIN posts p ON u.id = p.user_idINNER 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; SELECT DATE_FORMAT(created_at, '%Y-%m' ) AS '月份' , COUNT (* ) AS '文章数' FROM postsWHERE status = 1 GROUP BY DATE_FORMAT(created_at, '%Y-%m' )ORDER BY 月份 DESC ;
八、最佳实践建议
永远使用 WHERE 条件 执行 UPDATE 和 DELETE,先 SELECT 验证再操作
在生产环境开启 SQL_SAFE_UPDATES ,避免误操作
使用软删除 代替物理删除,保留数据可追溯
查询时指定列名 ,避免 SELECT *
为经常查询的列建立索引 (WHERE、JOIN、ORDER BY 涉及的列)
定期备份数据库 ,使用 mysqldump 工具
密码永远存储哈希值 ,不要明文存储
九、常用 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 吧!💪