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