MySQL 基础课程:从安装到实战
实验环境 :ecs-ff10-0001 | Ubuntu 24.04.4 LTS | MySQL 8.0.46 | 华为云 FlexusX 8vCPU/16GiB
实操时间 :2026-06-20
难度:⭐⭐☆☆☆(初学者友好)
目录
- [数据库概念与 MySQL 安装](#数据库概念与 MySQL 安装)
- 创建数据库并插入数据
- [SQL 的约束](#SQL 的约束)
- 挑战:搭建简易成绩管理系统
- [SELECT 语句详解](#SELECT 语句详解)
- 数据库及表的修改和删除
- 其它基本操作:索引、视图、导入导出、备份恢复
一、数据库概念与 MySQL 安装
1.1 数据库的基本概念
数据库(Database)是按照一定的数据结构来组织、存储和管理数据的仓库。它是现代软件系统的核心基础设施。
┌─────────────────────────────────────────────────────────┐
│ 数据库体系结构 │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ 应用程序 │────▶│ 数据库驱动 │ │
│ └─────────────┘ └──────┬──────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ DBMS 层 │ │
│ │ MySQL 8.0 │ │
│ └──────┬──────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ 数据库1 │ │ 数据库2 │ │ 数据库N │ │
│ │(school)│ │(shop) │ │ ... │ │
│ └───┬────┘ └────────┘ └────────┘ │
│ │ │
│ ┌──────┼──────┐ │
│ ▼ ▼ ▼ │
│ 表1 表2 表N │
│(student)(course)(score) │
└─────────────────────────────────────────────────────────┘
数据库分类
| 类型 | 代表产品 | 特点 | 适用场景 |
|---|---|---|---|
| 关系型数据库 (RDBMS) | MySQL、PostgreSQL、Oracle | 表结构、SQL、事务 ACID | 业务系统、金融 |
| 文档型 | MongoDB | JSON 文档、灵活模式 | 内容管理、日志 |
| 键值型 | Redis | 极速、内存存储 | 缓存、会话 |
| 时序型 | TDengine、InfluxDB | 时间戳索引、压缩 | IoT、监控 |
| 图数据库 | Neo4j | 节点和边 | 社交网络、推荐 |
核心术语
| 术语 | 英文 | 说明 |
|---|---|---|
| 数据库 | Database | 数据的容器,包含多张表 |
| 表 | Table | 二维结构,行和列组成 |
| 行/记录 | Row / Record | 表中的一条数据 |
| 列/字段 | Column / Field | 数据的属性 |
| 主键 | Primary Key | 唯一标识每行记录 |
| 外键 | Foreign Key | 引用另一表的主键,建立关联 |
| 索引 | Index | 加速查询的数据结构 |
| 视图 | View | 虚拟表,封装查询逻辑 |
| 事务 | Transaction | 一组原子操作,要么全成功要么全回滚 |
1.2 MySQL 简介
MySQL 是全球最流行的开源关系型数据库,具备以下特点:
- 开源免费:Community Edition 完全免费
- 高性能:支持亿级数据量,成熟的查询优化器
- 跨平台:Linux / Windows / macOS 全支持
- 生态完善:与 Java、Python、PHP、Node.js 无缝集成
MySQL 8.0 新特性(vs 5.7)
| 特性 | MySQL 5.7 | MySQL 8.0 |
|---|---|---|
| 默认字符集 | latin1 | utf8mb4 |
| JSON 支持 | 基础 | 增强(JSON_TABLE 等) |
| 窗口函数 | 不支持 | 原生支持(RANK, ROW_NUMBER) |
| CTE | 不支持 | 原生支持(WITH 子句) |
| 角色管理 | 不支持 | 支持 ROLE |
| 密码策略 | 旧版 | caching_sha2_password |
1.3 在 Ubuntu 24.04 上安装 MySQL 8.0
环境信息
服务器: ecs-ff10-0001
IP: 113.44.178.92
OS: Ubuntu 24.04.4 LTS (Noble Numbat)
内核: 6.8.0-106-generic
内存: 14 GiB
磁盘: 40 GB / 35 GB 可用
安装步骤
Step 1:更新软件包列表
bash
apt-get update
Step 2:安装 MySQL Server
bash
DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-server
实际输出:
Setting up mysql-server (8.0.46-0ubuntu0.24.04.2) ...
Processing triggers for man-db (2.12.0-4build2) ...
Processing triggers for libc-bin (2.39-0ubuntu8.7) ...
说明 :Ubuntu 24.04 的 apt 仓库中 MySQL 版本为 8.0.46,无需额外添加 MySQL 官方仓库。
Step 3:验证安装
bash
mysql --version
输出:
mysql Ver 8.0.46-0ubuntu0.24.04.2 for Linux on x86_64 ((Ubuntu))
Step 4:检查服务状态
bash
systemctl status mysql --no-pager
输出:
● mysql.service - MySQL Community Server
Loaded: loaded (/usr/lib/systemd/system/mysql.service; enabled; preset: enabled)
Active: active (running) since Sat 2026-06-20 11:48:00 CST; 10s ago
Process: 7793 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
Main PID: 7802 (mysqld)
Status: "Server is operational"
Tasks: 38 (limit: 18060)
Memory: 363.8M (peak: 378.9M)
CPU: 534ms
CGroup: /system.slice/mysql.service
└─7802 /usr/sbin/mysqld
✅
Active: active (running)说明 MySQL 服务已正常启动。
Step 5:查看默认数据库
bash
mysql -u root -e "SHOW DATABASES;"
输出:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
MySQL 内置数据库说明
| 数据库 | 说明 |
|---|---|
information_schema |
元数据库,存储所有数据库、表、列、索引的元信息(只读) |
mysql |
系统数据库,存储用户账号、权限、时区等配置 |
performance_schema |
性能监控数据库,收集服务器运行时性能数据 |
sys |
基于 performance_schema 的视图集合,便于分析性能 |
常用服务管理命令
bash
# 启动
systemctl start mysql
# 停止
systemctl stop mysql
# 重启
systemctl restart mysql
# 设置开机自启
systemctl enable mysql
# 查看运行状态
systemctl status mysql
二、创建数据库并插入数据
2.1 基本数据类型
MySQL 提供了丰富的数据类型,选择合适的类型既保证数据准确性,也影响存储效率和查询性能。
数值类型
| 类型 | 字节 | 有符号范围 | 无符号范围 | 适用场景 |
|---|---|---|---|---|
TINYINT |
1 | -128 ~ 127 | 0 ~ 255 | 年龄、状态码 |
SMALLINT |
2 | -32768 ~ 32767 | 0 ~ 65535 | 小整数 |
MEDIUMINT |
3 | -8M ~ 8M | 0 ~ 16M | 中等整数 |
INT |
4 | -2.1B ~ 2.1B | 0 ~ 4.2B | ID、数量(常用) |
BIGINT |
8 | -9.2E18 ~ 9.2E18 | 0 ~ 1.8E19 | 超大ID、金额(分) |
FLOAT |
4 | 单精度浮点 | --- | 近似计算(不精确) |
DOUBLE |
8 | 双精度浮点 | --- | 近似计算(不精确) |
DECIMAL(M,D) |
变长 | M 位总长,D 位小数 | --- | 金额、成绩(精确) |
⚠️ 金融场景必须用
DECIMAL,FLOAT/DOUBLE存在浮点误差,不能用于计算金额。
字符串类型
| 类型 | 最大长度 | 特点 | 适用场景 |
|---|---|---|---|
CHAR(N) |
255 字符 | 定长,右补空格,查询快 | 手机号、身份证、状态码 |
VARCHAR(N) |
65535 字节 | 变长,节省空间 | 姓名、邮箱、标题(常用) |
TEXT |
65535 字节 | 不能设默认值,不能加索引(全文除外) | 长文本、备注 |
MEDIUMTEXT |
16MB | 中等长文本 | 文章内容 |
LONGTEXT |
4GB | 超长文本 | 大型文档 |
ENUM('v1','v2') |
--- | 枚举,存储高效 | 性别、状态 |
SET('v1','v2') |
--- | 集合,可多选 | 权限标签 |
日期和时间类型
| 类型 | 格式 | 范围 | 字节 | 说明 |
|---|---|---|---|---|
DATE |
YYYY-MM-DD | 1000-01-01 ~ 9999-12-31 | 3 | 只存日期 |
TIME |
HH:MM:SS | -838:59:59 ~ 838:59:59 | 3 | 只存时间 |
DATETIME |
YYYY-MM-DD HH:MM:SS | 1000-01-01 ~ 9999-12-31 | 8 | 完整时间,不随时区变化 |
TIMESTAMP |
YYYY-MM-DD HH:MM:SS | 1970-01-01 ~ 2038-01-19 | 4 | 随时区变化,有 2038 问题 |
YEAR |
YYYY | 1901 ~ 2155 | 1 | 只存年份 |
⚠️
DATETIMEvsTIMESTAMP:推荐用DATETIME,无时区问题,且范围更大;TIMESTAMP在 2038 年溢出。
2.2 创建数据库
bash
mysql -u root -e "
CREATE DATABASE IF NOT EXISTS school
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
SHOW DATABASES;
"
输出:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| school |
| sys |
+--------------------+
语法说明
sql
CREATE DATABASE [IF NOT EXISTS] <数据库名>
[DEFAULT CHARACTER SET <字符集>]
[COLLATE <排序规则>];
| 参数 | 说明 |
|---|---|
IF NOT EXISTS |
如果已存在则跳过,避免报错 |
CHARACTER SET utf8mb4 |
字符集,utf8mb4 支持完整 Unicode(包括 emoji) |
COLLATE utf8mb4_unicode_ci |
排序规则,ci = case insensitive(大小写不敏感) |
2.3 创建数据表
sql
USE school;
CREATE TABLE IF NOT EXISTS student (
id INT NOT NULL AUTO_INCREMENT COMMENT '学生ID',
name VARCHAR(50) NOT NULL COMMENT '姓名',
gender ENUM('M','F') NOT NULL COMMENT '性别 M=男 F=女',
age TINYINT UNSIGNED NOT NULL COMMENT '年龄',
score DECIMAL(5,2) DEFAULT 0.00 COMMENT '总成绩',
email VARCHAR(100) UNIQUE COMMENT '邮箱(唯一)',
phone CHAR(11) COMMENT '手机号',
birthdate DATE COMMENT '出生日期',
remark TEXT COMMENT '备注',
create_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生信息表';
执行后查看表结构:
bash
mysql -u root school -e "DESCRIBE student;"
输出:
+-----------+-----------------+------+-----+-------------------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-----------------+------+-----+-------------------+-------------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | | NULL | |
| gender | enum('M','F') | NO | | NULL | |
| age | tinyint unsigned| NO | | NULL | |
| score | decimal(5,2) | YES | | 0.00 | |
| email | varchar(100) | YES | UNI | NULL | |
| phone | char(11) | YES | | NULL | |
| birthdate | date | YES | | NULL | |
| remark | text | YES | | NULL | |
| create_at | datetime | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+-----------+-----------------+------+-----+-------------------+-------------------+
建表语法关键字说明
| 关键字 | 说明 |
|---|---|
NOT NULL |
字段不允许为空 |
AUTO_INCREMENT |
自动递增,通常配合主键使用 |
DEFAULT <值> |
插入时未指定则使用默认值 |
UNIQUE |
字段值在整张表中唯一 |
COMMENT '...' |
字段注释,便于维护 |
PRIMARY KEY (id) |
声明主键,物理上是聚簇索引 |
ENGINE=InnoDB |
存储引擎,InnoDB 支持事务和外键 |
DEFAULT CHARSET=utf8mb4 |
表级字符集 |
2.4 插入数据
单条插入
sql
INSERT INTO student (name, gender, age, score, email, phone, birthdate, remark)
VALUES ('张三', 'M', 20, 88.50, 'zhangsan@edu.cn', '13800000001', '2006-03-15', '班长');
批量插入(推荐,效率更高)
sql
INSERT INTO student (name, gender, age, score, email, phone, birthdate, remark) VALUES
('张三', 'M', 20, 88.50, 'zhangsan@edu.cn', '13800000001', '2006-03-15', '班长'),
('李四', 'F', 19, 92.00, 'lisi@edu.cn', '13800000002', '2007-06-20', '学习委员'),
('王五', 'M', 21, 75.30, 'wangwu@edu.cn', '13800000003', '2005-11-08', NULL),
('赵六', 'F', 20, 96.80, 'zhaoliu@edu.cn', '13800000004', '2006-09-01', '数学竞赛第一名'),
('孙七', 'M', 22, 60.00, 'sunqi@edu.cn', '13800000005', '2004-01-30', '转专业同学'),
('周八', 'F', 19, 85.00, 'zhouba@edu.cn', '13800000006', '2007-07-14', NULL),
('吴九', 'M', 20, 71.20, 'wujiu@edu.cn', '13800000007', '2006-12-25', NULL),
('郑十', 'F', 21, 99.00, 'zhengshi@edu.cn', '13800000008', '2005-05-05', '全年级第一');
执行后查询验证:
+----+--------+--------+-----+-------+-----------------+-------------+------------+--------------------+---------------------+
| id | name | gender | age | score | email | phone | birthdate | remark | create_at |
+----+--------+--------+-----+-------+-----------------+-------------+------------+--------------------+---------------------+
| 1 | 张三 | M | 20 | 88.50 | zhangsan@edu.cn | 13800000001 | 2006-03-15 | 班长 | 2026-06-20 11:48:46 |
| 2 | 李四 | F | 19 | 92.00 | lisi@edu.cn | 13800000002 | 2007-06-20 | 学习委员 | 2026-06-20 11:48:46 |
| 3 | 王五 | M | 21 | 75.30 | wangwu@edu.cn | 13800000003 | 2005-11-08 | NULL | 2026-06-20 11:48:46 |
| 4 | 赵六 | F | 20 | 96.80 | zhaoliu@edu.cn | 13800000004 | 2006-09-01 | 数学竞赛第一名 | 2026-06-20 11:48:46 |
| 5 | 孙七 | M | 22 | 60.00 | sunqi@edu.cn | 13800000005 | 2004-01-30 | 转专业同学 | 2026-06-20 11:48:46 |
| 6 | 周八 | F | 19 | 85.00 | zhouba@edu.cn | 13800000006 | 2007-07-14 | NULL | 2026-06-20 11:48:46 |
| 7 | 吴九 | M | 20 | 71.20 | wujiu@edu.cn | 13800000007 | 2006-12-25 | NULL | 2026-06-20 11:48:46 |
| 8 | 郑十 | F | 21 | 99.00 | zhengshi@edu.cn | 13800000008 | 2005-05-05 | 全年级第一 | 2026-06-20 11:48:46 |
+----+--------+--------+-----+-------+-----------------+-------------+------------+--------------------+---------------------+
三、SQL 的约束
约束(Constraint)是对表中数据的规则限制,保证数据的完整性(Data Integrity)和一致性(Consistency)。
3.1 约束类型总览
| 约束类型 | 关键字 | 作用 |
|---|---|---|
| 主键约束 | PRIMARY KEY |
唯一标识每行,不允许 NULL,自动建索引 |
| 唯一约束 | UNIQUE |
列值在整表唯一,允许 NULL(多个 NULL 视为不同) |
| 非空约束 | NOT NULL |
字段不允许为 NULL |
| 默认值约束 | DEFAULT |
插入时未指定值则使用默认值 |
| 外键约束 | FOREIGN KEY |
引用另一表的主键,保证引用完整性 |
| 检查约束 | CHECK |
MySQL 8.0.16+ 支持,限制字段值的范围 |
| 自动递增 | AUTO_INCREMENT |
整数列自动递增,通常配合主键 |
3.2 约束实操演示
NOT NULL 约束
bash
mysql -u root school -e "
INSERT INTO student (gender, age) VALUES ('M', 18);
"
报错输出(真实服务器):
ERROR 1364 (HY000) at line 3: Field 'name' doesn't have a default value
name字段设置了NOT NULL且无默认值,因此插入时必须提供name的值。
UNIQUE 约束
bash
mysql -u root school -e "
INSERT INTO student (name, gender, age, score, email)
VALUES ('测试', 'M', 18, 80.0, 'zhangsan@edu.cn');
"
报错输出(真实服务器):
ERROR 1062 (23000) at line 5: Duplicate entry 'zhangsan@edu.cn' for key 'student.email'
UNIQUE,zhangsan@edu.cn已存在,不允许重复插入。
FOREIGN KEY 外键约束
bash
mysql -u root school -e "
INSERT INTO score (student_id, course_id, score) VALUES (999, 1, 90.0);
"
报错输出(真实服务器):
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
(`school`.`score`, CONSTRAINT `score_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`))
student_id=999在student表中不存在,外键约束阻止了非法数据插入。
3.3 约束的创建方式
方式 1:建表时定义(推荐)
sql
CREATE TABLE score (
id INT NOT NULL AUTO_INCREMENT,
student_id INT NOT NULL,
course_id INT NOT NULL,
score DECIMAL(5,2) NOT NULL DEFAULT 0.00,
-- 唯一约束:同一学生同一课程只能有一条成绩
UNIQUE KEY uk_stu_course (student_id, course_id),
-- 外键约束
FOREIGN KEY (student_id) REFERENCES student(id),
FOREIGN KEY (course_id) REFERENCES course(id),
PRIMARY KEY (id)
);
方式 2:ALTER TABLE 后加约束
sql
-- 添加非空约束
ALTER TABLE student MODIFY COLUMN name VARCHAR(50) NOT NULL;
-- 添加唯一约束
ALTER TABLE student ADD UNIQUE KEY uk_phone (phone);
-- 添加检查约束(MySQL 8.0.16+)
ALTER TABLE student ADD CONSTRAINT chk_age CHECK (age BETWEEN 0 AND 150);
方式 3:删除约束
sql
-- 删除外键约束
ALTER TABLE score DROP FOREIGN KEY score_ibfk_1;
-- 删除唯一约束
ALTER TABLE student DROP INDEX uk_phone;
-- 删除检查约束
ALTER TABLE student DROP CHECK chk_age;
四、挑战:搭建简易成绩管理系统
4.1 系统设计
成绩管理系统 E-R 图:
┌──────────────┐ ┌──────────────┐
│ student │ │ course │
│─────────────-│ │──────────────│
│ id (PK) │ │ id (PK) │
│ name │ │ name │
│ gender │ │ credit │
│ age │ │ teacher │
│ class_name │ └──────┬───────┘
│ score │ │
│ email │ ┌──────▼───────┐
│ phone │─────────│ score │
│ birthdate │ │──────────────│
└──────────────┘ │ id (PK) │
│ student_id (FK→student.id) │
│ course_id (FK→course.id) │
│ score │
│ exam_date │
└──────────────┘
4.2 建表 SQL
sql
-- 课程表
CREATE TABLE IF NOT EXISTS course (
id INT NOT NULL AUTO_INCREMENT COMMENT '课程ID',
name VARCHAR(100) NOT NULL COMMENT '课程名称',
credit TINYINT NOT NULL DEFAULT 3 COMMENT '学分',
teacher VARCHAR(50) NOT NULL COMMENT '任课老师',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程表';
-- 成绩表(含外键约束)
CREATE TABLE IF NOT EXISTS score (
id INT NOT NULL AUTO_INCREMENT COMMENT '成绩ID',
student_id INT NOT NULL COMMENT '学生ID',
course_id INT NOT NULL COMMENT '课程ID',
score DECIMAL(5,2) NOT NULL DEFAULT 0.00 COMMENT '成绩',
exam_date DATE COMMENT '考试日期',
PRIMARY KEY (id),
UNIQUE KEY uk_stu_course (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES student(id),
FOREIGN KEY (course_id) REFERENCES course(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成绩表';
4.3 插入测试数据
sql
-- 插入课程
INSERT INTO course (name, credit, teacher) VALUES
('高等数学', 4, '刘老师'),
('英语', 3, '陈老师'),
('数据库原理', 3, '张老师'),
('操作系统', 3, '王老师');
-- 插入成绩(8位同学 × 4门课 = 32条记录)
INSERT INTO score (student_id, course_id, score, exam_date) VALUES
(1,1,82.0,'2026-01-10'), (1,2,79.0,'2026-01-11'),
...(32条)
验证:
mysql> SELECT count(*) AS total_scores FROM score;
+--------------+
| total_scores |
+--------------+
| 32 |
+--------------+
五、SELECT 语句详解
SELECT 是 SQL 中最重要的语句,用于从数据库中查询数据。
5.1 基本语法
sql
SELECT [DISTINCT] <列名列表 | *>
FROM <表名>
[WHERE <条件>]
[GROUP BY <分组列>]
[HAVING <分组条件>]
[ORDER BY <排序列> [ASC|DESC]]
[LIMIT <偏移量>, <行数>];
执行顺序(重要!)
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
基础查询:
sql
SELECT id, name, age, score FROM student;
输出:
+----+--------+-----+-------+
| id | name | age | score |
+----+--------+-----+-------+
| 1 | 张三 | 20 | 88.50 |
| 2 | 李四 | 19 | 92.00 |
| 3 | 王五 | 21 | 75.30 |
| 4 | 赵六 | 20 | 96.80 |
| 5 | 孙七 | 22 | 60.00 |
| 6 | 周八 | 19 | 85.00 |
| 7 | 吴九 | 20 | 71.20 |
| 8 | 郑十 | 21 | 99.00 |
+----+--------+-----+-------+
5.2 数学符号条件
| 运算符 | 说明 | 示例 |
|---|---|---|
= |
等于 | WHERE id = 1 |
<> 或 != |
不等于 | WHERE gender != 'M' |
> |
大于 | WHERE score > 90 |
>= |
大于等于 | WHERE score >= 90 |
< |
小于 | WHERE age < 20 |
<= |
小于等于 | WHERE age <= 20 |
BETWEEN a AND b |
范围,含两端 | WHERE age BETWEEN 19 AND 21 |
IS NULL |
为空 | WHERE remark IS NULL |
IS NOT NULL |
不为空 | WHERE remark IS NOT NULL |
sql
SELECT name, score FROM student WHERE score >= 90;
+--------+-------+
| name | score |
+--------+-------+
| 李四 | 92.00 |
| 赵六 | 96.80 |
| 郑十 | 99.00 |
+--------+-------+
5.3 AND / OR / IN
sql
-- AND:同时满足多个条件(年龄 19~20 且成绩 >80)
SELECT name, age, score
FROM student
WHERE age BETWEEN 19 AND 20 AND score > 80;
+--------+-----+-------+
| name | age | score |
+--------+-----+-------+
| 张三 | 20 | 88.50 |
| 李四 | 19 | 92.00 |
| 赵六 | 20 | 96.80 |
| 周八 | 19 | 85.00 |
+--------+-----+-------+
sql
-- IN:值在给定列表中(等价于多个 OR)
SELECT name, score FROM student WHERE score IN (88.50, 92.00, 99.00);
+--------+-------+
| name | score |
+--------+-------+
| 张三 | 88.50 |
| 李四 | 92.00 |
| 郑十 | 99.00 |
+--------+-------+
5.4 通配符 LIKE
| 通配符 | 说明 |
|---|---|
% |
任意个任意字符(包含 0 个) |
_ |
恰好 1 个任意字符 |
sql
-- 查询所有 @edu.cn 邮箱
SELECT name, email FROM student WHERE email LIKE '%@edu.cn';
-- 查询姓张的同学
SELECT name FROM student WHERE name LIKE '张%';
输出(姓张):
+------+
| name |
+------+
| 张三 |
+------+
5.5 排序 ORDER BY
sql
-- 按成绩降序排列
SELECT name, score FROM student ORDER BY score DESC;
+--------+-------+
| name | score |
+--------+-------+
| 郑十 | 99.00 |
| 赵六 | 96.80 |
| 李四 | 92.00 |
| 张三 | 88.50 |
| 周八 | 85.00 |
| 王五 | 75.30 |
| 吴九 | 71.20 |
| 孙七 | 60.00 |
+--------+-------+
多列排序
sql
-- 先按年龄升序,再按成绩降序
SELECT name, age, score
FROM student
ORDER BY age ASC, score DESC;
5.6 SQL 内置函数和计算
聚合函数(Aggregate Functions)
| 函数 | 说明 |
|---|---|
COUNT(*) |
统计行数 |
COUNT(列名) |
统计非 NULL 行数 |
SUM(列名) |
求和 |
AVG(列名) |
平均值 |
MAX(列名) |
最大值 |
MIN(列名) |
最小值 |
sql
SELECT
COUNT(*) AS 总人数,
MAX(score) AS 最高分,
MIN(score) AS 最低分,
ROUND(AVG(score), 2) AS 平均分,
SUM(score) AS 总分
FROM student;
真实输出:
+--------+--------+--------+--------+--------+
| 总人数 | 最高分 | 最低分 | 平均分 | 总分 |
+--------+--------+--------+--------+--------+
| 8 | 99.00 | 60.00 | 83.48 | 667.80 |
+--------+--------+--------+--------+--------+
字符串函数
| 函数 | 说明 | 示例 |
|---|---|---|
UPPER(str) |
转大写 | UPPER('hello') → 'HELLO' |
LOWER(str) |
转小写 | LOWER('WORLD') → 'world' |
LENGTH(str) |
字节长度 | LENGTH('张三') → 6(UTF-8 每汉字 3 字节) |
CHAR_LENGTH(str) |
字符长度 | CHAR_LENGTH('张三') → 2 |
CONCAT(s1,s2,...) |
拼接 | CONCAT('Hello', ' ', 'World') |
SUBSTRING(str,pos,len) |
截取 | SUBSTRING('abcdef',2,3) → 'bcd' |
TRIM(str) |
去首尾空格 | |
REPLACE(str,from,to) |
替换 |
sql
SELECT name, UPPER(email), LENGTH(name) FROM student LIMIT 3;
输出:
+------+-------------------+--------------+
| name | UPPER(email) | LENGTH(name) |
+------+-------------------+--------------+
| 张三 | ZHANGSAN@EDU.CN | 6 |
| 李四 | LISI@EDU.CN | 6 |
| 王五 | WANGWU@EDU.CN | 6 |
+------+-------------------+--------------+
日期函数
| 函数 | 说明 |
|---|---|
NOW() |
当前日期时间 |
CURDATE() |
当前日期 |
CURTIME() |
当前时间 |
YEAR(date) |
提取年份 |
MONTH(date) |
提取月份 |
DAY(date) |
提取日 |
DATEDIFF(d1,d2) |
日期差(天数) |
DATE_FORMAT(date,fmt) |
格式化日期 |
5.7 子查询与连接查询
子查询(Subquery)
子查询是嵌套在另一条 SQL 中的查询。
sql
-- 查询成绩高于平均分的同学
SELECT name, score
FROM student
WHERE score > (SELECT AVG(score) FROM student);
真实输出:
+------+-------+
| name | score |
+------+-------+
| 张三 | 88.50 |
| 李四 | 92.00 |
| 赵六 | 96.80 |
| 周八 | 85.00 |
| 郑十 | 99.00 |
+------+-------+
AVG 为 83.48,高于平均分的有 5 人。
连接查询(JOIN)
| 类型 | 语法 | 说明 |
|---|---|---|
| INNER JOIN | JOIN 或 INNER JOIN |
只返回两表都有匹配的行 |
| LEFT JOIN | LEFT JOIN |
保留左表全部行,右表无匹配填 NULL |
| RIGHT JOIN | RIGHT JOIN |
保留右表全部行,左表无匹配填 NULL |
| CROSS JOIN | CROSS JOIN |
笛卡尔积 |
sql
-- 三表连接:查询每位同学的每门课成绩
SELECT s.name, c.name AS course, sc.score
FROM score sc
JOIN student s ON sc.student_id = s.id
JOIN course c ON sc.course_id = c.id
ORDER BY s.id, c.id;
真实输出(节选):
+------+----------+-------+
| name | course | score |
+------+----------+-------+
| 张三 | 高等数学 | 82.00 |
| 张三 | 英语 | 79.00 |
| 张三 | 数据库原理 | 91.00 |
| 张三 | 操作系统 | 88.00 |
| 李四 | 高等数学 | 95.00 |
| 李四 | 英语 | 90.00 |
...(共 32 行)
+------+----------+-------+
GROUP BY 分组统计
sql
-- 按班级统计平均成绩
SELECT
class_name AS 班级,
COUNT(*) AS 人数,
ROUND(AVG(score), 2) AS 平均分,
MAX(score) AS 最高分
FROM student
GROUP BY class_name
ORDER BY 平均分 DESC;
六、数据库及表的修改和删除
6.1 数据库操作
sql
-- 查看所有数据库
SHOW DATABASES;
-- 切换数据库
USE school;
-- 查看当前数据库
SELECT DATABASE();
-- 删除数据库(⚠️ 高危操作,不可恢复)
DROP DATABASE school_restore;
-- 查看建库语句
SHOW CREATE DATABASE school;
6.2 数据表操作
查看表信息
sql
SHOW TABLES; -- 列出所有表
SHOW FULL TABLES; -- 列出表和视图
DESCRIBE student; -- 查看表结构(简写 DESC)
SHOW CREATE TABLE student; -- 查看建表 SQL
SHOW TABLE STATUS LIKE 'student'\G -- 查看表详细状态
ALTER TABLE 修改表结构
sql
-- 添加列
ALTER TABLE student
ADD COLUMN class_name VARCHAR(20) DEFAULT NULL COMMENT '班级编号' AFTER age;
-- 修改列类型
ALTER TABLE student
MODIFY COLUMN phone VARCHAR(15);
-- 重命名列(MySQL 8.0+)
ALTER TABLE student
RENAME COLUMN class_no TO class_name;
-- 删除列
ALTER TABLE student
DROP COLUMN remark;
-- 重命名表
RENAME TABLE student TO students;
-- 或
ALTER TABLE students RENAME TO student;
-- 添加索引
ALTER TABLE student ADD INDEX idx_name (name);
-- 删除索引
ALTER TABLE student DROP INDEX idx_name;
实操执行结果(添加 class_name 列后的表结构):
+-----------+-----------------+------+
| Field | Type | Null |
+-----------+-----------------+------+
| id | int | NO |
| name | varchar(50) | NO |
| gender | enum('M','F') | NO |
| age | tinyint unsigned| NO |
| class_name| varchar(20) | YES | ← 新增列
| score | decimal(5,2) | YES |
...
6.3 更新数据 UPDATE
sql
-- 基本语法
UPDATE <表名>
SET <列名1>=<值1> [, <列名2>=<值2> ...]
[WHERE <条件>];
⚠️ 没有 WHERE 的 UPDATE 会更新所有行!
sql
-- 更新指定行
UPDATE student SET class_name = '计算机2班' WHERE id IN (1,2,3,4);
UPDATE student SET class_name = '软件1班' WHERE id IN (5,6,7,8);
输出验证:
+----+------+------------+-------+
| id | name | class_name | score |
+----+------+------------+-------+
| 1 | 张三 | 计算机2班 | 88.50 |
| 2 | 李四 | 计算机2班 | 92.00 |
| 3 | 王五 | 计算机2班 | 75.30 |
| 4 | 赵六 | 计算机2班 | 96.80 |
| 5 | 孙七 | 软件1班 | 60.00 |
| 6 | 周八 | 软件1班 | 85.00 |
| 7 | 吴九 | 软件1班 | 71.20 |
| 8 | 郑十 | 软件1班 | 99.00 |
+----+------+------------+-------+
6.4 删除数据 DELETE
sql
-- 基本语法
DELETE FROM <表名> [WHERE <条件>];
⚠️ 没有 WHERE 的 DELETE 会清空整张表!
踩坑:外键约束阻止删除父表数据
错误操作:
bash
mysql -u root school -e "DELETE FROM student WHERE id = 8;"
报错:
ERROR 1451 (23000): Cannot delete or update a parent row:
a foreign key constraint fails
(`school`.`score`, CONSTRAINT `score_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`))
正确做法:先删子表,再删父表
sql
-- 1. 先删除 score 表中对应数据
DELETE FROM score WHERE student_id = 8;
-- 2. 再删除 student 表中的数据
DELETE FROM student WHERE id = 8;
DELETE vs TRUNCATE vs DROP 对比
| 操作 | 说明 | 事务 | 自增重置 | 速度 |
|---|---|---|---|---|
DELETE FROM t WHERE ... |
按条件删除指定行 | ✅ 可回滚 | ❌ 不重置 | 慢(逐行) |
DELETE FROM t |
删除所有行 | ✅ 可回滚 | ❌ 不重置 | 较慢 |
TRUNCATE TABLE t |
清空表(DDL 操作) | ❌ 不可回滚 | ✅ 重置为1 | 快 |
DROP TABLE t |
删除整张表(含结构) | ❌ 不可回滚 | --- | 快 |
七、其它基本操作
7.1 索引(Index)
索引是数据库加速查询的核心机制,本质是一种数据结构(MySQL 默认 B+ 树)。
无索引查询(全表扫描): 有索引查询(B+树检索):
┌──┬──────┬──────┐ B+树叶节点:
│1 │ 张三 │ 88.5 │ ←遍历 ┌───┐ ┌───┐ ┌───┐
│2 │ 李四 │ 92.0 │ ←遍历 │ 1 │→│ 3 │→│ 7 │
│3 │ 王五 │ 75.3 │ ←遍历 └───┘ └───┘ └───┘
... 找到 → 直接返回行
创建索引
sql
-- 普通索引
CREATE INDEX idx_name ON student(name);
-- 复合索引(最左匹配原则)
CREATE INDEX idx_gender_score ON student(gender, score);
-- 唯一索引
CREATE UNIQUE INDEX uk_email ON student(email);
-- 全文索引(用于长文本搜索)
CREATE FULLTEXT INDEX ft_remark ON student(remark);
真实执行后 SHOW INDEX 输出:
+--------+-----------+-----------------+------+-------------+------------+
| Table | Key_name | | Seq | Column_name | Index_type |
+--------+-----------+-----------------+------+-------------+------------+
| student| PRIMARY | | 1 | id | BTREE |
| student| email | | 1 | email | BTREE |
| student| idx_name | | 1 | name | BTREE |
| student| idx_gender_score | | 1 | gender | BTREE |
| student| idx_gender_score | | 2 | score | BTREE |
+--------+-----------+-----------------+------+-------------+------------+
EXPLAIN 查看索引使用
sql
EXPLAIN SELECT * FROM student WHERE name = '张三';
真实输出:
+----+-------------+---------+------+----------+---------+--------+------+----------+-------+
| id | select_type | table | type | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------+----------+---------+--------+------+----------+-------+
| 1 | SIMPLE | student | ref | idx_name | 202 | const | 1 | 100.00 | NULL |
+----+-------------+---------+------+----------+---------+--------+------+----------+-------+
type=ref:使用了非唯一索引,性能良好key=idx_name:实际使用了idx_name索引rows=1:只扫描 1 行,效率极高
type 字段性能对比(从好到差)
const > eq_ref > ref > range > index > ALL(全表扫描,最差)
索引使用原则
- 频繁查询的列应建索引(WHERE、JOIN、ORDER BY 中的列)
- 高基数列效果好(如邮箱),低基数列效果差(如性别)
- 复合索引遵循最左匹配原则 :
(a,b,c)的索引,查询条件必须从a开始 - 避免在索引列上做运算 :
WHERE YEAR(birthdate)=2006会导致索引失效,应改写为范围查询 - 不要建过多索引:索引加速查询,但会减慢写入速度
7.2 视图(View)
视图是基于 SELECT 查询的虚拟表,不存储真实数据,每次查询时动态执行。
优点:
- 简化复杂查询(封装 JOIN、子查询)
- 权限控制(只暴露必要字段)
- 逻辑隔离(应用层无需关心底层表结构变化)
创建视图
sql
CREATE OR REPLACE VIEW v_student_rank AS
SELECT
s.id,
s.name,
s.class_name,
s.score AS total_score,
ROUND(AVG(sc.score), 2) AS avg_single_score,
RANK() OVER (ORDER BY s.score DESC) AS rank_no
FROM student s
LEFT JOIN score sc ON s.id = sc.student_id
GROUP BY s.id, s.name, s.class_name, s.score;
真实输出(SELECT * FROM v_student_rank):
+----+------+------------+-------------+------------------+---------+
| id | name | class_name | total_score | avg_single_score | rank_no |
+----+------+------------+-------------+------------------+---------+
| 8 | 郑十 | 软件1班 | 99.00 | 99.00 | 1 |
| 4 | 赵六 | 计算机2班 | 96.80 | 96.50 | 2 |
| 2 | 李四 | 计算机2班 | 92.00 | 91.25 | 3 |
| 1 | 张三 | 计算机2班 | 88.50 | 85.00 | 4 |
| 6 | 周八 | 软件1班 | 85.00 | 84.25 | 5 |
| 3 | 王五 | 计算机2班 | 75.30 | 71.75 | 6 |
| 7 | 吴九 | 软件1班 | 71.20 | 70.75 | 7 |
| 5 | 孙七 | 软件1班 | 60.00 | 60.25 | 8 |
+----+------+------------+-------------+------------------+---------+
RANK()是 MySQL 8.0 新增的窗口函数,返回当前行的排名(并列则跳号)。
视图管理
sql
-- 查看所有视图
SHOW FULL TABLES WHERE Table_type = 'VIEW';
-- 查看视图定义
SHOW CREATE VIEW v_student_rank;
-- 删除视图
DROP VIEW IF EXISTS v_student_rank;
7.3 导入和导出
导出数据
方式 1:SELECT INTO OUTFILE(导出 CSV)
sql
-- 查看 secure_file_priv 路径(必须写到此目录)
SHOW VARIABLES LIKE 'secure_file_priv';
输出:
+------------------+-----------------------+
| Variable_name | Value |
+------------------+-----------------------+
| secure_file_priv | /var/lib/mysql-files/ |
+------------------+-----------------------+
sql
-- 导出为 CSV
SELECT id, name, gender, age, score, email
FROM student
INTO OUTFILE '/var/lib/mysql-files/student.csv'
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n';
真实输出文件内容:
1,张三,M,20,88.50,zhangsan@edu.cn
2,李四,F,19,92.00,lisi@edu.cn
3,王五,M,21,75.30,wangwu@edu.cn
4,赵六,F,20,96.80,zhaoliu@edu.cn
5,孙七,M,22,60.00,sunqi@edu.cn
6,周八,F,19,85.00,zhouba@edu.cn
7,吴九,M,20,71.20,wujiu@edu.cn
8,郑十,F,21,99.00,zhengshi@edu.cn
方式 2:mysqldump(导出 SQL 脚本)
bash
# 导出单张表
mysqldump -u root school student > /tmp/school_student.sql
# 导出整个数据库
mysqldump -u root --databases school --result-file=/tmp/school_backup.sql
实际文件大小:
-rw-r--r-- 1 root root 8.2K Jun 20 11:51 /tmp/school_backup.sql
169 /tmp/school_backup.sql
导入数据
方式 1:LOAD DATA INFILE(从 CSV 导入)
sql
LOAD DATA INFILE '/var/lib/mysql-files/student.csv'
INTO TABLE student
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
(id, name, gender, age, score, email);
方式 2:mysql 命令行导入 SQL
bash
# 导入到指定数据库
mysql -u root school < /tmp/school_student.sql
7.4 备份和恢复
完整备份方案
bash
# 全库备份
mysqldump -u root \
--all-databases \
--single-transaction \ # InnoDB 热备份,不锁表
--flush-logs \ # 备份前刷新 binlog
--master-data=2 \ # 记录当前 binlog 位置(用于增量恢复)
--result-file=/backup/full_$(date +%Y%m%d_%H%M%S).sql
# 单库备份
mysqldump -u root \
--databases school \
--single-transaction \
--result-file=/tmp/school_backup.sql
恢复演示
bash
# 从备份文件恢复(会先 DROP 再重建数据库)
mysql -u root < /tmp/school_backup.sql
# 恢复到新库(用 sed 替换库名)
sed 's/`school`/`school_restore2`/g' /tmp/school_backup.sql | mysql -u root
验证恢复结果:
mysql> SHOW TABLES;
+--------------------+
| Tables_in_school_restore2 |
+--------------------+
| course |
| score |
| student |
| v_student_rank |
+--------------------+
mysql> SELECT COUNT(*) FROM student;
+----------+
| COUNT(*) |
+----------+
| 8 |
+----------+
✅ 3 张表 + 1 个视图,8 条学生数据,恢复成功。
备份策略建议
生产环境推荐备份策略:
┌─────────────────────────────────────────────┐
│ 周日 00:00 → 全量备份(mysqldump) │
│ 周一~周六 00:00 → 增量备份(binlog) │
│ 每小时 → binlog 归档 │
│ 保留策略:全量 4 周,增量 2 周 │
└─────────────────────────────────────────────┘
附录:MySQL 常用命令速查
数据库操作
sql
CREATE DATABASE db_name; -- 创建数据库
DROP DATABASE db_name; -- 删除数据库
USE db_name; -- 切换数据库
SELECT DATABASE(); -- 查看当前数据库
SHOW DATABASES; -- 列出所有数据库
表操作
sql
SHOW TABLES; -- 列出所有表
DESC table_name; -- 查看表结构
SHOW CREATE TABLE table_name; -- 查看建表 SQL
CREATE TABLE ...; -- 创建表
DROP TABLE IF EXISTS table_name; -- 删除表
TRUNCATE TABLE table_name; -- 清空表
数据操作 (DML)
sql
INSERT INTO t (c1,c2) VALUES (v1,v2); -- 插入
UPDATE t SET c1=v1 WHERE condition; -- 更新(⚠️ 必须加 WHERE)
DELETE FROM t WHERE condition; -- 删除(⚠️ 必须加 WHERE)
SELECT * FROM t WHERE condition ORDER BY c LIMIT 10; -- 查询
用户与权限
sql
-- 创建用户
CREATE USER 'alice'@'%' IDENTIFIED BY 'StrongPass123!';
-- 授权(读写 school 库所有表)
GRANT SELECT, INSERT, UPDATE, DELETE ON school.* TO 'alice'@'%';
-- 授权(只读)
GRANT SELECT ON school.* TO 'readonly'@'%';
-- 查看权限
SHOW GRANTS FOR 'alice'@'%';
-- 撤销权限
REVOKE INSERT, UPDATE ON school.* FROM 'alice'@'%';
-- 刷新权限缓存
FLUSH PRIVILEGES;
-- 查看所有用户
SELECT user, host FROM mysql.user;
踩坑总结
| 问题 | 原因 | 解决方案 |
|---|---|---|
ERROR 1364: Field 'name' doesn't have a default value |
插入时未提供 NOT NULL 字段的值 | 确保所有 NOT NULL 字段都有值或设置 DEFAULT |
ERROR 1062: Duplicate entry 'xxx' for key 'xxx' |
违反 UNIQUE 约束 | 先查询是否存在,或用 INSERT IGNORE / ON DUPLICATE KEY UPDATE |
ERROR 1452: Cannot add or update a child row |
违反外键约束,引用了不存在的父记录 | 先插入父表数据 |
ERROR 1451: Cannot delete or update a parent row |
删除父表时子表有引用 | 先删子表数据,或暂时禁用外键检查 |
ERROR 1290: secure-file-priv option |
OUTFILE 路径不在 secure_file_priv 指定目录 | 写入 /var/lib/mysql-files/ 目录 |
| UPDATE/DELETE 没有 WHERE | 全表更新/删除,数据丢失 | 始终加 WHERE 条件 |
课程总结:本博客基于华为云 FlexusX 服务器(Ubuntu 24.04 + MySQL 8.0.46)全程实操,涵盖了从 MySQL 安装到实际成绩管理系统的搭建,包括数据类型选择、约束设计、SELECT 查询、JOIN 连接、索引优化、视图创建、数据备份恢复等核心知识点。所有输出均为真实服务器执行结果。