一、MySQL 管理
启动及关闭 MySQL 服务器
1. Windows 系统下
启动 MySQL 服务器:
1、通过 "服务" 管理工具: 打开"运行"对话框(Win + R),输入 services.msc,找到"MySQL"服务,右击选择"启动"。
2、通过命令提示符: 打开命令提示符(以管理员身份),输入以下命令:
bash
net start mysql
关闭MySQL服务器:
1、**通过 "服务" 管理工具:**同样打开"运行"对话框,输入 services.msc,找到 "MySQL" 服务,右击选择"停止"。
2、通过命令提示符: 打开命令提示符(以管理员身份),输入以下命令:
bash
net stop mysql
2. Linux 系统下
1、启动 MySQL 服务:
使用 systemd命令(适用于大多数现代 Linux 发行版,如 Ubuntu、CentOS 等):
bash
sudo systemctl start mysql
使用 service 命令(在一些较旧的发行版中):
bash
sudo service mysql start
2、关闭 MySQL 服务:
使用 systemd:
bash
sudo systemctl stop mysql
使用 service 命令:
bash
sudo service mysql stop
3、重启 MySQL 服务:
使用 systemd:
bash
sudo systemctl restart mysql
使用 service 命令:
bash
sudo service mysql restart
4、检查 MySQL 服务状态:
使用 systemd命令:
bash
sudo systemctl status mysql
使用 service 命令:
bash
sudo service mysql status
二、数据库和表的基本操作 (DDL - 数据定义语言)
数据定义语言(DDL)用于创建、修改和删除数据库对象(如数据库、表、索引等)。以下是 MySQL 中关于数据库和表的核心 DDL 操作详解:
1. 创建数据库:CREATE DATABASE
功能:创建一个新的数据库。
基本语法
sql
CREATE DATABASE|SCHEMA [IF NOT EXISTS] 数据库名 [CHARACTER SET 字符集] [COLLATE 排序规则];
选项说明
IF NOT EXISTS
:如果数据库不存在才创建(避免重复创建报错)CHARACTER SET
:指定数据库默认字符集(如utf8mb4
支持所有 Unicode 字符,包括 emoji)COLLATE
:指定字符集的排序规则(如utf8mb4_general_ci
不区分大小写)
示例
sql
-- 创建一个新的数据库my_company。
CREATE DATABASE my_company;
-- 创建名为 mydb 的数据库,使用 utf8mb4 字符集
CREATE DATABASE IF NOT EXISTS mydb
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
2. 查看数据库:SHOW DATABASES
功能:查看所有的数据库信息。
基本语法
sql
SHOW {DATABASE|SCHEMAS}[LIKE '模式' WHERE 条件];
- 使用
SELECT DATABASES;
可查看服务器中的所有数据库。 - 使用
SELECT DATABASES LIEK 'db_%';
筛选以db_开头的数据库名称
3. 选择数据库: USE
功能:指定当前操作的数据库(后续操作默认在此数据库中执行),当前数据库在工作会话关闭(即断开与该数据库的连接)或再次使用USE语句指定数据库时,结束工作状态。
基本语法
sql
USE 数据库名;
示例
sql
-- 选择 mydb 作为当前数据库
USE mydb;
提示:使用
SELECT DATABASE();
可查看当前选中的数据库。
4. 创建表:CREATE TABLE
功能:在当前数据库中创建新表,需定义表名、列名、数据类型及约束。
基本语法
sql
CREATE TABLE [IF NOT EXISTS] 表名 (
列名1 数据类型 [约束],
列名2 数据类型 [约束],
...
[表级约束]
) [ENGINE=存储引擎];
常用数据类型
-
字符串:
VARCHAR(长度)
(可变长度)、CHAR(长度)
(固定长度) -
数值:
INT
(整数)、FLOAT
/DOUBLE
(浮点数)、DECIMAL(总位数, 小数位)
(精确小数) -
日期时间:
DATE
(日期)、TIME
(时间)、DATETIME
(日期时间)、TIMESTAMP
(带时区的时间戳) -
布尔:
BOOLEAN
(等价于TINYINT(1)
,1 为真,0 为假)
常用约束
PRIMARY KEY
:主键(唯一标识记录,非空且唯一)NOT NULL
:列值不能为空UNIQUE
:列值唯一(允许为空)DEFAULT
:默认值AUTO_INCREMENT
:自增(通常用于主键,插入时自动生成唯一值)FOREIGN KEY
:外键(关联其他表的主键,保证数据一致性)
示例:创建用户表
sql
CREATE TABLE employees (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
salary DECIMAL(10,2));
sql
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT, -- 自增主键
username VARCHAR(50) NOT NULL UNIQUE, -- 用户名唯一且非空
email VARCHAR(100) NOT NULL UNIQUE, -- 邮箱唯一且非空
age INT DEFAULT NULL, -- 年龄可为空,默认 NULL
created_at DATETIME DEFAULT CURRENT_TIMESTAMP -- 创建时间默认当前时间
) ENGINE=InnoDB; -- 使用 InnoDB 存储引擎(支持事务和外键)
5. 查看表结构:DESC
或 DESCRIBE
功能:显示表的列信息(字段名、数据类型、约束等)。
基本语法
sql
DESC 表名;
-- 或
DESCRIBE 表名;
示例
sql
-- 查看 users 表结构
DESC users;
输出示例:
plaintext
+------------+--------------+------+-----+-------------------+-------------------+
| 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 | |
| age | int | YES | | NULL | |
| created_at | datetime | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+------------+--------------+------+-----+-------------------+-------------------+
6. 修改表结构:ALTER TABLE
功能:修改已存在的表结构(添加 / 删除列、修改数据类型、添加约束等)。
常用操作语法
(1)修改数据库
sql
-- 修改数据库mydb,使用utf8mb4字符集和utf8mb4_general_ci校验规则
ALTER DATABASE mydb
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
(2)添加列
sql
ALTER TABLE 表名 ADD 列名 数据类型 [约束];
示例:给 users 表添加 phone
列
sql
ALTER TABLE users ADD phone VARCHAR(20) UNIQUE;
(3)删除列
sql
ALTER TABLE 表名 DROP COLUMN 列名;
示例:删除 users 表的 age
列
sql
ALTER TABLE users DROP COLUMN age;
(4)修改列的数据类型
sql
ALTER TABLE 表名 MODIFY 列名 新数据类型 [约束];
示例:将 username 长度改为 100
sql
ALTER TABLE users MODIFY username VARCHAR(100) NOT NULL UNIQUE;
(5)修改列名
sql
ALTER TABLE 表名 CHANGE 旧列名 新列名 数据类型 [约束];
示例:将 phone
列改名为 mobile
sql
ALTER TABLE users CHANGE phone mobile VARCHAR(20) UNIQUE;
(6)添加主键约束
sql
ALTER TABLE 表名 ADD PRIMARY KEY (列名);
(7)添加外键约束(关联其他表)
sql
-- 先创建关联表
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
order_no VARCHAR(50) UNIQUE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- 外键说明:orders.user_id 关联 users.id,当 users 中记录被删除时,关联的 orders 记录也会被删除(ON DELETE CASCADE)
7.删除表/数据库:DROP TABLE
/ DROP DATABASE
功能 :永久删除表或数据库(操作不可逆,需谨慎!)。
基本语法
删除表
sql
DROP TABLE [IF EXISTS] 表名;
示例:删除 orders 表
sql
DROP TABLE IF EXISTS orders;
删除数据库
sql
DROP DATABASE|SCHEMA [IF EXISTS] 数据库名;
示例:删除 mydb 数据库
sql
DROP DATABASE IF EXISTS mydb;
警告:删除操作会永久删除所有数据,建议操作前备份!
注意 :
安装MySQL后,系统会自动创建4个名为performance_schema 、mysql、information_schema、sys的系统数据库
总结
DDL 操作是数据库设计和维护的基础,核心包括:
- 数据库的创建(
CREATE DATABASE
)与删除(DROP DATABASE
) - 表的创建(
CREATE TABLE
)、结构修改(ALTER TABLE
)与删除(DROP TABLE
) - 表结构的查看(
DESC
)和数据库的切换(USE
)
使用时需注意:
- 优先使用
IF NOT EXISTS
和IF EXISTS
避免报错 - 外键约束会影响数据操作性能,需根据实际场景选择
- 生产环境中执行
DROP
操作前必须确认并备份数据
练习
基础题(入门级)
-
创建数据库 需求:创建一个名为
school
的数据库,使用utf8mb4
字符集和utf8mb4_general_ci
排序规则,要求如果数据库已存在则不报错。 -
选择与查看数据库 需求:切换到
school
数据库,并验证当前是否已选中该数据库。 -
创建基础表 需求:在
school
数据库中创建一个students
表,包含以下字段:id
:整数,主键,自增name
:字符串(最长 50 字符),非空gender
:字符串(最长 10 字符),允许为空birthdate
:日期类型,允许为空
-
查看表结构 需求:查看
students
表的结构,确认字段名、数据类型和约束是否正确。
进阶题(基础操作综合)
-
修改表结构(添加列需求) :给
students
表添加一个email
字段,要求:- 类型为字符串(最长 100 字符)
- 唯一且非空
-
修改表结构(修改列) 需求:将
students
表中gender
字段的类型修改为CHAR(1)
(只允许存储 ' 男 '/' 女 '/' 未 '),并设置默认值为 ' 未 '。 -
创建带约束的表 需求:在
school
数据库中创建classes
表,包含以下字段:class_id
:整数,主键,自增class_name
:字符串(最长 30 字符),非空且唯一teacher
:字符串(最长 50 字符),允许为空create_time
:日期时间类型,默认值为当前系统时间
复杂题(多表关联与高级修改)
-
创建带外键的表 需求:创建
scores
表,用于记录学生成绩,包含以下字段:score_id
:整数,主键,自增student_id
:整数,非空(关联students
表的id
)subject
:字符串(最长 20 字符),非空score
:小数(总长度 5 位,保留 1 位小数),允许为空(缺考)- 要求添加外键约束:
student_id
关联students.id
,当students
表中某学生记录被删除时,scores
表中该学生的成绩记录也自动删除。
-
批量修改表结构 需求:对
scores
表执行以下修改:- 添加
exam_date
字段(日期类型,默认值为2024-01-01
) - 将
subject
字段的长度修改为 30 字符 - 删除
score
字段的允许为空约束(设置为非空,缺考用 0 表示)
- 添加
-
清理操作(删除) 需求:
-
删除
classes
表(如果存在) -
最终删除
school
数据库(如果存在)
-
答案
基础题(入门级)
sql
-- 创建school数据库
CREATE DATABASE IF NOT EXISTS school
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
-- 选择并验证数据库
USE school;
SELECT DATABASE(); -- 验证当前选中的数据库
-- 创建students表
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
gender VARCHAR(10),
birthdate DATE
);
-- 查看表结构
DESCRIBE students;
-- 或使用
SHOW COLUMNS FROM students;
进阶题(基础操作综合)
sql
-- 添加email字段
ALTER TABLE students
ADD COLUMN email VARCHAR(100) NOT NULL UNIQUE;
-- 修改gender字段
ALTER TABLE students
MODIFY COLUMN gender CHAR(1) DEFAULT '未';
复杂题(多表关联与高级修改)
sql
-- 创建classes表
CREATE TABLE classes (
class_id INT PRIMARY KEY AUTO_INCREMENT,
class_name VARCHAR(30) NOT NULL UNIQUE,
teacher VARCHAR(50),
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 创建scores表(带外键约束)
CREATE TABLE scores (
score_id INT PRIMARY KEY AUTO_INCREMENT,
student_id INT NOT NULL,
subject VARCHAR(20) NOT NULL,
score DECIMAL(5,1),
FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE
);
-- 批量修改scores表结构
ALTER TABLE scores
ADD COLUMN exam_date DATE DEFAULT '2024-01-01',
MODIFY COLUMN subject VARCHAR(30) NOT NULL,
MODIFY COLUMN score DECIMAL(5,1) NOT NULL DEFAULT 0;
-- 清理操作
DROP TABLE IF EXISTS classes;
DROP DATABASE IF EXISTS school;
代码说明:
CREATE DATABASE IF NOT EXISTS
确保数据库存在时不会报错USE
命令用于切换数据库,SELECT DATABASE()
验证当前数据库- 外键约束中
ON DELETE CASCADE
实现级联删除功能 ALTER TABLE
语句可以组合多个修改操作,用逗号分隔- 清理操作使用
DROP
命令,添加IF EXISTS
避免报错
三、数据查询的进阶操作 (DQL - 数据查询语言)
1. 条件过滤:WHERE
WHERE
用于在查询时筛选符合条件的记录,支持多种运算符,是精准提取数据的基础。
- 核心语法 :
SELECT 字段 FROM 表名 WHERE 条件表达式;
- 支持的运算符 :
- 比较运算符:
=
(等于)、!=
(不等于)、>
(大于)、<
(小于)、>=
(大于等于)、<=
(小于等于) - 范围运算符:
BETWEEN...AND...
(在指定范围)、IN(值1,值2...)
(在指定集合)、NOT IN(值1,值2...)
(不在指定集合) - 空值判断:
IS NULL
(为空)、IS NOT NULL
(不为空)
- 比较运算符:
- 示例 :查询
users
表中年龄在 20-30 岁之间、且邮箱不为空的用户
sql
SELECT username, age, email FROM users
WHERE age BETWEEN 20 AND 30
AND email IS NOT NULL;
2. 结果排序:ORDER BY
ORDER BY
用于对查询结果按指定字段排序,可控制升序或降序,让结果更具可读性。
- 核心语法 :
SELECT 字段 FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2...;
- 关键规则 :
- 排序方式:
ASC
(升序,默认,可省略)、DESC
(降序,必须显式声明) - 多字段排序:先按字段 1 排序,字段 1 值相同时,再按字段 2 排序
- 排序方式:
- 示例 :查询
orders
表中所有订单,先按 "订单金额" 降序排,金额相同时按 "下单时间" 升序排
sql
SELECT order_id, user_id, amount, create_time FROM orders
ORDER BY amount DESC, create_time ASC;
3. 结果数量限制: LIMIT
LIMIT
用于限制查询结果的行数,常用于分页查询或获取 "Top N" 数据,仅在 MySQL 中有效(SQL Server 用 TOP
,PostgreSQL 用 LIMIT
)。
- 核心语法 :
- 仅限制行数:
SELECT 字段 FROM 表名 LIMIT 数量;
(获取前 N 条记录) - 分页查询:
SELECT 字段 FROM 表名 LIMIT 起始索引, 每页数量;
(起始索引从 0 开始)
- 仅限制行数:
- 示例 1(Top 5) :查询
products
表中价格最高的前 5 件商品
sql
SELECT product_name, price FROM products
ORDER BY price DESC
LIMIT 5;
- 示例 2(分页) :查询
users
表中第 2 页数据(每页 10 条,起始索引为 10)
sql
SELECT username, age FROM users
LIMIT 10, 10;
4. 模糊查询:LIKE
LIKE
用于匹配字段中包含指定字符的记录,需配合通配符使用,适合 "不确定完整内容" 的查询场景(如搜索功能)。
- 核心语法 :
SELECT 字段 FROM 表名 WHERE 字段 LIKE '通配符表达式';
- 常用通配符 :
%
:匹配任意 0 个或多个字符(包括汉字、数字等)_
:匹配任意 1 个字符(仅 1 个,多一个少一个都不匹配)
- 示例 1(包含指定字符) :查询
users
表中用户名包含 "张" 的用户
sql
SELECT username FROM users
WHERE username LIKE '%张%';
- 示例 2(固定位置匹配) :查询
users
表中手机号以 "138" 开头、且第 4 位为 "0" 的用户(手机号共 11 位)
sql
SELECT username, phone FROM users
WHERE phone LIKE '1380_______';
5. 多表关联查询:JOIN ... ON ...
当需要从多个相关表中提取数据时(如 "订单 + 用户""商品 + 分类"),需用 JOIN
建立表间关联,核心是通过 "关联字段"(通常是外键与主键)匹配记录。
- 常见关联类型:
关联类型 | 作用 | 语法示例 |
---|---|---|
INNER JOIN (内连接) |
只保留两表中 "关联字段匹配" 的记录 | FROM 表A INNER JOIN 表B ON 表A.字段=表B.字段 |
LEFT JOIN (左连接) |
保留左表所有记录,右表匹配不到则补 NULL | FROM 表A LEFT JOIN 表B ON 表A.字段=表B.字段 |
RIGHT JOIN (右连接) |
保留右表所有记录,左表匹配不到则补 NULL | FROM 表A RIGHT JOIN 表B ON 表A.字段=表B.字段 |
- 示例 :查询
orders
表中所有订单,同时显示对应用户的用户名(orders
表的user_id
关联users
表的id
)
- INNER JOIN(内连接):只保留两表中匹配条件的记录,是数据分析中最常用的关联方式。`
sql
-- 分析每个学生的姓名、所属班级及数学成绩
SELECT
s.name AS 学生姓名,
c.class_name AS 班级,
sc.score AS 数学成绩
FROM students s
INNER JOIN classes c ON s.class_id = c.class_id -- 学生表关联班级表
INNER JOIN scores sc ON s.id = sc.student_id -- 关联成绩表
WHERE sc.subject = '数学'; -- 筛选数学科目
- LEFT JOIN(左连接) :保留左表所有记录,右表无匹配时显示
NULL
,适合分析 "存在 / 缺失" 类数据(如 "未交作业的学生")。
sql
-- 分析所有学生的英语成绩,包括缺考(成绩为NULL)的学生
SELECT
s.name AS 学生姓名,
sc.score AS 英语成绩
FROM students s
LEFT JOIN scores sc ON s.id = sc.student_id AND sc.subject = '英语';
- RIGHT JOIN(右连接) :与左连接相反,保留右表所有记录,左表无匹配时显示
NULL
,较少用(可通过交换表位置用左连接替代)。
6. 结果分组与聚合:GROUP BY
+ 聚合函数
GROUP BY
用于将表中的数据按照指定字段进行分组,相同值的记录会被归为一组;聚合函数则用于对每个分组内的数据进行计算(如求和、计数、平均值等)。
常用聚合函数:
COUNT()
:统计分组内的记录数SUM()
:计算分组内数值的总和AVG()
:计算分组内数值的平均值MAX()
:获取分组内的最大值MIN()
:获取分组内的最小值
语法示例:
sql
-- 按性别分组,统计每组的学生人数、平均年龄
SELECT
gender,
COUNT(*) AS 人数, -- 统计每个分组的总记录数
AVG(TIMESTAMPDIFF(YEAR, birthdate, CURDATE())) AS 平均年龄 -- 计算平均年龄
FROM students
GROUP BY gender; -- 按gender字段分组
注意事项:
GROUP BY
后通常跟需要分组的字段名,SELECT 子句中只能出现分组字段或聚合函数,不能出现其他非分组字段。
错误示例(包含非分组字段):
sql
SELECT gender, name, COUNT(*) FROM students GROUP BY gender; -- 错误!name不是分组字段
- 可以按多个字段分组(先按第一个字段分组,同组内再按第二个字段细分):
sql
-- 按班级和性别分组,统计每个班级中不同性别的学生人数
SELECT class_id, gender, COUNT(*) AS 人数
FROM students
GROUP BY class_id, gender; -- 多字段分组
7. 分组后过滤:HAVING
HAVING
用于对 GROUP BY
分组后的结果进行过滤(类似 WHERE
,但 WHERE
用于分组前过滤记录,HAVING
用于分组后过滤分组)。
语法示例:
sql
-- 按班级分组,筛选出学生人数 >= 30 的班级
SELECT
class_id,
COUNT(*) AS 班级人数
FROM students
GROUP BY class_id
HAVING 班级人数 >= 30; -- 过滤分组结果
HAVING
与 WHERE
的区别:
特性 | WHERE |
HAVING |
---|---|---|
作用时机 | 分组前过滤记录 | 分组后过滤分组 |
适用对象 | 原始表中的行 | GROUP BY 后的分组 |
能否用聚合函数 | 不能(只能用字段条件) | 能(常用聚合函数结果过滤) |
综合示例(WHERE
+ GROUP BY
+ HAVING
):
sql
-- 1. 先筛选出2005年及以后出生的学生(WHERE)
-- 2. 按班级分组,计算每个班级的平均成绩(GROUP BY + 聚合)
-- 3. 筛选出平均成绩 >= 80 的班级(HAVING)
SELECT
s.class_id,
AVG(sc.score) AS 平均成绩
FROM students s
JOIN scores sc ON s.id = sc.student_id
WHERE YEAR(s.birthdate) >= 2005 -- 分组前过滤:只保留2005年后出生的学生
GROUP BY s.class_id -- 按班级分组
8. 条件分支计算:CASE WHEN
当需要根据字段值动态生成分析结果时(如 "按成绩划分等级""统计不同分数段人数"),需用 CASE WHEN
实现条件逻辑。
语法示例:
sql
-- 分析每个学生的语文成绩,并划分等级(A:90+,B:80-89,C:60-79,D:<60)
SELECT
s.name AS 学生姓名,
sc.score AS 语文成绩,
CASE
WHEN sc.score >= 90 THEN 'A'
WHEN sc.score >= 80 THEN 'B'
WHEN sc.score >= 60 THEN 'C'
ELSE 'D' -- 缺考或不及格
END AS 成绩等级
FROM students s
JOIN scores sc ON s.id = sc.student_id
WHERE sc.subject = '语文';
进阶用法(结合聚合函数):
sql
-- 统计语文成绩各等级的人数
SELECT
CASE
WHEN sc.score >= 90 THEN 'A'
WHEN sc.score >= 80 THEN 'B'
WHEN sc.score >= 60 THEN 'C'
ELSE 'D'
END AS 成绩等级,
COUNT(*) AS 人数 -- 统计每个等级的人数
FROM scores sc
WHERE sc.subject = '语文'
GROUP BY 成绩等级; -- 按等级分组
9. 窗口函数:OVER () 子句
窗口函数是 高级数据分析核心工具 ,可在不分组的前提下,对 "指定窗口范围" 内的数据进行计算(如 "计算每个学生在班级内的成绩排名""求每个班级的成绩平均值并关联到每条学生记录"),避免 GROUP BY
导致的结果行数减少。
常用窗口函数:
- 排名函数 :
RANK()
(跳跃排名)、DENSE_RANK()
(连续排名)、ROW_NUMBER()
(唯一序号)。
sql
-- 分析每个班级内学生的数学成绩排名(按成绩降序)
SELECT
c.class_name AS 班级,
s.name AS 学生姓名,
sc.score AS 数学成绩,
RANK() OVER (PARTITION BY c.class_name ORDER BY sc.score DESC) AS 班级排名
-- PARTITION BY 按班级分组(窗口范围),ORDER BY 按成绩排序
FROM students s
JOIN classes c ON s.class_id = c.class_id
JOIN scores sc ON s.id = sc.student_id
WHERE sc.subject = '数学';
- 聚合窗口函数 :
SUM() OVER()
、AVG() OVER()
等,将聚合结果关联到每条原始记录。
sql
-- 分析每个学生的数学成绩,及所在班级的数学平均成绩、年级平均成绩
SELECT
c.class_name AS 班级,
s.name AS 学生姓名,
sc.score AS 数学成绩,
AVG(sc.score) OVER (PARTITION BY c.class_name) AS 班级平均分, -- 班级窗口的平均值
AVG(sc.score) OVER () AS 年级平均分 -- 全年级窗口的平均值(无PARTITION BY)
FROM students s
JOIN classes c ON s.class_id = c.class_id
JOIN scores sc ON s.id = sc.student_id
WHERE sc.subject = '数学';
HAVING 平均成绩 >= 80; -- 分组后过滤:保留平均成绩≥80的班级
四、数据的增、删、改、查 (DML - 数据操作语言)
1. 插入数据:INSERT INTO
用于向表中添加新记录,基础语法:
sql
-- 完整语法(指定字段)
INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...);
-- 简化语法(按表中所有字段顺序插入,需包含所有字段值)
INSERT INTO 表名 VALUES (值1, 值2, ...);
-- 批量插入
INSERT INTO 表名 (字段1, 字段2) VALUES
(值1, 值2),
(值3, 值4),
(值5, 值6);
示例 :向users
表插入一条用户数据
sql
INSERT INTO users (username, age, email)
VALUES ('张三', 25, 'zhangsan@example.com');
2. 查询数据:SELECT
/ FROM
用于从表中获取数据,是最常用的 DML 命令,基础语法:
sql
-- 基础查询(*表示所有字段)
SELECT 字段1, 字段2, ... FROM 表名;
-- 带条件查询
SELECT 字段 FROM 表名 WHERE 条件;
-- 排序查询(ASC升序,DESC降序,默认升序)
SELECT 字段 FROM 表名 ORDER BY 字段 排序方式;
-- 限制查询结果数量
SELECT 字段 FROM 表名 LIMIT 数量;
-- 去重查询
SELECT DISTINCT 字段 FROM 表名;
示例 :查询users
表中年龄大于 18 的用户,按年龄降序排列,只显示前 5 条
sql
SELECT username, age FROM users
WHERE age > 18
ORDER BY age DESC
LIMIT 5;
3. 更新数据:UPDATE
/ SET
用于修改表中已有记录,必须加WHERE
条件(否则会更新所有记录),基础语法:
sql
UPDATE 表名
SET 字段1 = 新值1, 字段2 = 新值2, ...
WHERE 条件;
示例 :将users
表中id=1
的用户年龄改为 26
sql
UPDATE users
SET age = 26, email = 'new_zhangsan@example.com'
WHERE id = 1;
注意 :无WHERE
条件时会更新表中所有记录,操作前务必确认条件是否正确。
4. 删除数据:DELETE FROM
用于删除表中记录,必须加WHERE
条件(否则会删除所有记录),基础语法:
sql
DELETE FROM 表名 WHERE 条件;
示例 :删除users
表中id=5
的用户
sql
DELETE FROM users WHERE id = 5;
补充 :若需清空表中所有数据(保留表结构),可使用TRUNCATE
(属于 DDL,速度更快,但无法回滚):
sql
TRUNCATE TABLE 表名;
五、权限和事务控制 (DCL - 数据控制语言 & TCL - 事务控制语言)
DCL 主要用于控制数据库用户的访问权限,确保数据安全。核心命令包括 GRANT
(授权)和 REVOKE
(撤销权限)。
TCL 用于控制数据库事务,确保多步操作的原子性、一致性、隔离性和持久性(ACID 特性)。核心命令包括 START TRANSACTION
、COMMIT
和 ROLLBACK
。
1. 创建用户并授权:GRANT
GRANT
用于为用户分配特定权限,语法如下:
sql
-- 创建用户并授权(MySQL 8.0 需先创建用户再授权)
CREATE USER '用户名'@'主机地址' IDENTIFIED BY '密码';
-- 授权(例如:授予对 db1 数据库所有表的查询和插入权限)
GRANT SELECT, INSERT ON db1.* TO '用户名'@'主机地址';
-- 授予所有权限(谨慎使用)
GRANT ALL PRIVILEGES ON *.* TO '用户名'@'主机地址' WITH GRANT OPTION;
主机地址
:localhost
表示本地,%
表示所有远程主机。WITH GRANT OPTION
:允许用户将自己的权限授予其他用户。- 执行后需刷新权限:
FLUSH PRIVILEGES;
2. 撤销权限:REVOKE
REVOKE
用于收回已授予的权限,语法如下:
sql
-- 撤销特定权限
REVOKE SELECT, INSERT ON db1.* FROM '用户名'@'主机地址';
-- 撤销所有权限
REVOKE ALL PRIVILEGES ON *.* FROM '用户名'@'主机地址';
- 撤销后同样需要刷新权限:
FLUSH PRIVILEGES;
3. 事务开始:START TRANSACTION;
或 BEGIN;
用于标记事务的起始点,之后的 SQL 操作将被视为一个整体:
sql
START TRANSACTION; -- 或 BEGIN;
-- 后续的 INSERT/UPDATE/DELETE 等操作
4. 提交事务:COMMIT;
将事务中所有操作永久保存到数据库,事务结束:
sql
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- 两笔更新同时生效
5. 回滚事务:ROLLBACK;
若事务中出现错误,撤销所有已执行的操作,恢复到事务开始前的状态:
sql
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 假设此处出现错误
ROLLBACK; -- 撤销上述更新,数据回到初始状态
事务的保存点(SAVEPOINT)
复杂事务中可设置保存点,灵活回滚到指定位置:
sql
START TRANSACTION;
UPDATE table1 SET col = 1;
SAVEPOINT sp1; -- 设置保存点
UPDATE table2 SET col = 2;
ROLLBACK TO sp1; -- 仅回滚到 sp1 之后的操作
COMMIT; -- 最终提交 table1 的更新
六、部分窗口函数
窗口函数的通用语法
所有窗口函数都遵循以下结构:
sql
函数名([参数]) OVER (
[PARTITION BY 分组字段] -- 按字段划分窗口(类似GROUP BY,可选)
[ORDER BY 排序字段 [ASC|DESC]] -- 窗口内的排序方式(可选)
[窗口范围] -- 如 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW(可选)
)
PARTITION BY
:将数据划分为多个独立窗口(不写则整个表为一个窗口)。ORDER BY
:指定窗口内的排序规则,排名函数和偏移函数必须配合此子句使用。- 窗口范围:默认是从首行到当前行,可通过
ROWS
/RANGE
调整(如 "前 3 行到当前行")。
应用场景
窗口函数特别适合以下分析场景:
- 排名分析(成绩排名、销售 TOP N)
- 同期对比(本月与上月销售额对比)
- 累计计算(累计销售额、累计用户数)
- 占比分析(某产品销售额占总销售额的比例)
- 分组内的首尾值获取(班级最高分 / 最低分学生)
相比传统的 GROUP BY
聚合,窗口函数能在保留原始数据的同时附加分析结果,极大简化了复杂报表的生成逻辑。
1. 排名函数(用于生成排名序号)
-
ROW_NUMBER()
为窗口内的每条记录分配唯一的连续序号(1,2,3...),即使值相同也不会重复。sql-- 按数学成绩降序,为每个班级的学生分配唯一排名 SELECT class_id, name, score, ROW_NUMBER() OVER (PARTITION BY class_id ORDER BY score DESC) AS row_num FROM students;
-
RANK()
生成排名时,相同值会获得相同排名,后续排名会跳过中间序号(如 1,1,3...)。sql-- 数学成绩相同的学生排名相同,下一名次跳跃 SELECT name, score, RANK() OVER (ORDER BY score DESC) AS rnk FROM scores WHERE subject = '数学';
-
DENSE_RANK()
生成排名时,相同值获得相同排名,后续排名连续不跳跃(如 1,1,2...)。sql-- 数学成绩相同的学生排名相同,下一名次连续 SELECT name, score, DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rnk FROM scores WHERE subject = '数学';
2. 聚合类窗口函数(对窗口数据做聚合计算)
将常见聚合函数(SUM
/AVG
/MAX
/MIN
/COUNT
)用于窗口,计算每条记录所在窗口的聚合结果,且不压缩原始行数。
sql
-- 计算每个学生的成绩及所在班级的总分、平均分
SELECT
class_id, name, score,
SUM(score) OVER (PARTITION BY class_id) AS 班级总分,
AVG(score) OVER (PARTITION BY class_id) AS 班级平均分,
MAX(score) OVER (PARTITION BY class_id) AS 班级最高分
FROM students;
3. 分布函数(分析数据分布位置)
-
PERCENT_RANK()
计算当前行在窗口中的相对排名百分比,公式:(当前排名 - 1) / (总记录数 - 1)
,结果范围 [0,1]。sql-- 计算每个学生成绩在班级内的百分比排名 SELECT class_id, name, score, PERCENT_RANK() OVER (PARTITION BY class_id ORDER BY score DESC) AS pct_rank FROM students;
-
CUME_DIST()
计算当前行及之前行的行数占窗口总记录数的比例,结果范围 (0,1],表示 "小于等于当前值的记录占比"。sql-- 计算成绩≤当前学生的比例(如0.8表示80%的学生成绩≤当前值) SELECT name, score, CUME_DIST() OVER (ORDER BY score) AS cume_dist FROM scores WHERE subject = '语文';
4. 偏移函数(获取相邻行数据)
用于访问窗口中当前行之前或之后的指定行数据,常用于计算 "环比""同比" 等差异。
-
LAG(expr, n, default)
获取当前行的前第n
行数据,default
为无数据时的默认值(默认NULL
)。sql-- 获取学生的上一次考试成绩及分数变化 SELECT name, exam_date, score, LAG(score, 1) OVER (PARTITION BY name ORDER BY exam_date) AS 上一次成绩, score - LAG(score, 1) OVER (PARTITION BY name ORDER BY exam_date) AS 分数变化 FROM scores;
-
LEAD(expr, n, default)
获取当前行的后第n
行数据,与LAG
方向相反。sql-- 获取学生的下一次考试成绩 SELECT name, exam_date, score, LEAD(score, 1) OVER (PARTITION BY name ORDER BY exam_date) AS 下一次成绩 FROM scores;
5. 首尾函数(获取窗口内的首尾数据)
-
FIRST_VALUE(expr)
返回窗口内排序后的第一行数据。sql-- 获取每个班级的第一名成绩及学生姓名 SELECT class_id, name, score, FIRST_VALUE(name) OVER (PARTITION BY class_id ORDER BY score DESC) AS 班级第一名 FROM students;
-
LAST_VALUE(expr)
返回窗口内排序后的最后一行数据(注意默认窗口范围是从首行到当前行,需指定RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
才能获取整个窗口的最后一行)。sql-- 获取每个班级的最后一名成绩及学生姓名 SELECT class_id, name, score, LAST_VALUE(name) OVER ( PARTITION BY class_id ORDER BY score DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS 班级最后一名 FROM students;