MySQL 进阶语法:函数、约束、多表查询、事务

目录

[一、MySQL 常用函数](#一、MySQL 常用函数)

[1. 字符串函数](#1. 字符串函数)

[1.1 基本字符串操作](#1.1 基本字符串操作)

[1.2 字符串截取与处理](#1.2 字符串截取与处理)

[1.3 字符串搜索与替换](#1.3 字符串搜索与替换)

[2. 数值函数](#2. 数值函数)

[2.1 基本数学运算](#2.1 基本数学运算)

[2.2 数学计算](#2.2 数学计算)

[2.3 随机数与符号](#2.3 随机数与符号)

[3. 日期时间函数](#3. 日期时间函数)

[3.1 获取当前时间](#3.1 获取当前时间)

[3.2 日期时间计算](#3.2 日期时间计算)

[3.3 日期时间提取](#3.3 日期时间提取)

[3.4 日期时间格式化](#3.4 日期时间格式化)

[4. 条件函数](#4. 条件函数)

[4.1 流程控制函数](#4.1 流程控制函数)

[4.2 聚合函数](#4.2 聚合函数)

[5. 窗口函数 (MySQL 8.0+)](#5. 窗口函数 (MySQL 8.0+))

[6. JSON 函数 (MySQL 5.7+)](#6. JSON 函数 (MySQL 5.7+))

[7. 系统信息函数](#7. 系统信息函数)

[8. 加密函数](#8. 加密函数)

[二、MySQL 约束](#二、MySQL 约束)

[1. 主键约束 (PRIMARY KEY)](#1. 主键约束 (PRIMARY KEY))

[1.1 基本用法](#1.1 基本用法)

[1.2 修改表添加主键](#1.2 修改表添加主键)

[1.3 自增主键](#1.3 自增主键)

[2. 外键约束 (FOREIGN KEY)](#2. 外键约束 (FOREIGN KEY))

[2.1 基本用法](#2.1 基本用法)

[2.2 级联操作](#2.2 级联操作)

[2.3 修改表添加外键](#2.3 修改表添加外键)

[3. 唯一约束 (UNIQUE)](#3. 唯一约束 (UNIQUE))

[3.1 基本用法](#3.1 基本用法)

[3.2 多列组合唯一](#3.2 多列组合唯一)

[3.3 修改表添加唯一约束](#3.3 修改表添加唯一约束)

[4. 非空约束 (NOT NULL)](#4. 非空约束 (NOT NULL))

[4.1 基本用法](#4.1 基本用法)

[4.2 修改表添加非空约束](#4.2 修改表添加非空约束)

[5. 默认值约束 (DEFAULT)](#5. 默认值约束 (DEFAULT))

[5.1 基本用法](#5.1 基本用法)

[5.2 修改表添加默认值](#5.2 修改表添加默认值)

[6. 检查约束 (CHECK)](#6. 检查约束 (CHECK))

[6.1 基本用法](#6.1 基本用法)

[6.2 命名检查约束](#6.2 命名检查约束)

[6.3 修改表添加检查约束](#6.3 修改表添加检查约束)

[7. 约束管理](#7. 约束管理)

[7.1 查看约束](#7.1 查看约束)

[7.2 删除约束](#7.2 删除约束)

三、多表查询

[1. 内连接 (INNER JOIN)](#1. 内连接 (INNER JOIN))

[2. 左外连接 (LEFT JOIN)](#2. 左外连接 (LEFT JOIN))

[3. 右外连接 (RIGHT JOIN)](#3. 右外连接 (RIGHT JOIN))

[4. 全外连接 (FULL OUTER JOIN) - MySQL不支持,可用UNION模拟](#4. 全外连接 (FULL OUTER JOIN) - MySQL不支持,可用UNION模拟)

[5. 交叉连接 (CROSS JOIN)](#5. 交叉连接 (CROSS JOIN))

[6. 自连接 (SELF JOIN)](#6. 自连接 (SELF JOIN))

[7. 自然连接 (NATURAL JOIN)](#7. 自然连接 (NATURAL JOIN))

[8. USING 子句](#8. USING 子句)

[9. 子查询](#9. 子查询)

[9.1 WHERE子句中的子查询](#9.1 WHERE子句中的子查询)

(1)标量子查询(返回单个值)

(2)列子查询(返回单列多行)

(3)行子查询(返回单行多列)

[9.2 FROM子句中的子查询(派生表)](#9.2 FROM子句中的子查询(派生表))

[9.3 SELECT子句中的子查询(标量子查询)](#9.3 SELECT子句中的子查询(标量子查询))

[9.4 HAVING子句中的子查询](#9.4 HAVING子句中的子查询)

[9.5 EXISTS和NOT EXISTS子查询](#9.5 EXISTS和NOT EXISTS子查询)

[10. 集合操作](#10. 集合操作)

[10.1 UNION 和 UNION ALL](#10.1 UNION 和 UNION ALL)

[10.2 INTERSECT (MySQL 8.0.31+)](#10.2 INTERSECT (MySQL 8.0.31+))

[10.3 EXCEPT/MINUS (MySQL 8.0.31+)](#10.3 EXCEPT/MINUS (MySQL 8.0.31+))

四、事务 (Transaction)

[1. 事务的基本特性 (ACID)](#1. 事务的基本特性 (ACID))

[2. 事务控制语句](#2. 事务控制语句)

[3. 事务隔离级别](#3. 事务隔离级别)

[4. 事务并发问题](#4. 事务并发问题)

(1)脏读 (Dirty Read)

(2)不可重复读 (Non-repeatable Read)

(3)幻读 (Phantom Read)

[5. 保存点 (SAVEPOINT)](#5. 保存点 (SAVEPOINT))


一、MySQL 常用函数

MySQL 提供了丰富的内置函数,可以用于数据处理、计算和转换。这些函数主要分为以下几类:

1. 字符串函数

1.1 基本字符串操作
sql 复制代码
 -- 连接字符串
 SELECT CONCAT('Hello', ' ', 'World'); -- 输出: Hello World
 SELECT CONCAT_WS('-', '2023', '01', '01'); -- 用分隔符连接: 2023-01-01
 ​
 -- 字符串长度
 SELECT LENGTH('MySQL'); -- 字节数: 5
 SELECT CHAR_LENGTH('MySQL'); -- 字符数: 5
 ​
 -- 大小写转换
 SELECT UPPER('mysql'); -- MYSQL
 SELECT LOWER('MySQL'); -- mysql
1.2 字符串截取与处理
sql 复制代码
 -- 截取字符串
 SELECT SUBSTRING('MySQL', 2, 3); -- ySQ (从第2个字符开始,取3个)
 SELECT LEFT('MySQL', 2); -- My
 SELECT RIGHT('MySQL', 3); -- SQL
 ​
 -- 去除空格
 SELECT TRIM('  MySQL  '); -- 'MySQL'
 SELECT LTRIM('  MySQL'); -- 'MySQL'
 SELECT RTRIM('MySQL  '); -- 'MySQL'
 ​
 -- 填充字符串
 SELECT LPAD('5', 3, '0'); -- 005
 SELECT RPAD('Hi', 5, '!'); -- Hi!!!
1.3 字符串搜索与替换
sql 复制代码
 -- 查找位置
 SELECT INSTR('MySQL', 'SQL'); -- 3 (SQL在MySQL中的位置)
 SELECT LOCATE('SQL', 'MySQL'); -- 3
 ​
 -- 替换字符串
 SELECT REPLACE('MySQL', 'SQL', 'Database'); -- MyDatabase
 ​
 -- 正则表达式
 SELECT 'MySQL' REGEXP '^My'; -- 1 (匹配成功)
 SELECT REGEXP_REPLACE('abc123', '[0-9]', 'X'); -- abcXXX

2. 数值函数

2.1 基本数学运算
sql 复制代码
 -- 四舍五入
 SELECT ROUND(3.14159, 2); -- 3.14
 SELECT ROUND(123.456, -1); -- 120 (小数点左侧舍入)
 ​
 -- 取整
 SELECT CEIL(3.14); -- 4 (向上取整)
 SELECT FLOOR(3.14); -- 3 (向下取整)
 SELECT TRUNCATE(3.14159, 2); -- 3.14 (截断)
 ​
 -- 绝对值
 SELECT ABS(-10); -- 10
2.2 数学计算
sql 复制代码
 -- 幂运算
 SELECT POWER(2, 3); -- 8 (2的3次方)
 SELECT SQRT(16); -- 4 (平方根)
 ​
 -- 对数
 SELECT LOG(2, 8); -- 3 (以2为底8的对数)
 SELECT LN(10); -- 自然对数
 SELECT LOG10(100); -- 2
 ​
 -- 三角函数
 SELECT SIN(PI()/2); -- 1
 SELECT COS(0); -- 1
 SELECT TAN(PI()/4); -- 约等于1
2.3 随机数与符号
sql 复制代码
 -- 随机数
 SELECT RAND(); -- 0到1之间的随机数
 SELECT FLOOR(1 + RAND() * 10); -- 1-10的随机整数
 ​
 -- 符号判断
 SELECT SIGN(-10); -- -1
 SELECT SIGN(0); -- 0
 SELECT SIGN(10); -- 1

3. 日期时间函数

3.1 获取当前时间
sql 复制代码
 SELECT NOW(); -- 当前日期和时间 (2023-01-01 12:34:56)
 SELECT CURDATE(); -- 当前日期 (2023-01-01)
 SELECT CURTIME(); -- 当前时间 (12:34:56)
 SELECT UNIX_TIMESTAMP(); -- 当前UNIX时间戳
3.2 日期时间计算
sql 复制代码
 -- 日期加减
 SELECT DATE_ADD(NOW(), INTERVAL 1 DAY); -- 加1天
 SELECT DATE_SUB(NOW(), INTERVAL 1 MONTH); -- 减1个月
 SELECT NOW() + INTERVAL 1 HOUR; -- 加1小时
 ​
 -- 日期差
 SELECT DATEDIFF('2023-12-31', '2023-01-01'); -- 364 (天数差)
 SELECT TIMESTAMPDIFF(MONTH, '2023-01-01', '2023-12-31'); -- 11 (月数差)
3.3 日期时间提取
sql 复制代码
 -- 提取日期部分
 SELECT YEAR(NOW()); -- 2023
 SELECT MONTH(NOW()); -- 1-12
 SELECT DAY(NOW()); -- 1-31
 SELECT HOUR(NOW()); -- 0-23
 SELECT MINUTE(NOW()); -- 0-59
 SELECT SECOND(NOW()); -- 0-59
 ​
 -- 星期和季度
 SELECT DAYNAME(NOW()); -- Monday
 SELECT DAYOFWEEK(NOW()); -- 1=周日, 2=周一,...,7=周六
 SELECT QUARTER(NOW()); -- 1-4
3.4 日期时间格式化
sql 复制代码
 -- 格式化日期
 SELECT DATE_FORMAT(NOW(), '%Y-%m-%d'); -- 2023-01-01
 SELECT DATE_FORMAT(NOW(), '%H:%i:%s'); -- 12:34:56
 SELECT DATE_FORMAT(NOW(), '%W, %M %e, %Y'); -- Sunday, January 1, 2023
 ​
 -- 解析日期字符串
 SELECT STR_TO_DATE('01-01-2023', '%d-%m-%Y'); -- 2023-01-01

4. 条件函数

4.1 流程控制函数
sql 复制代码
 -- IF函数
 SELECT IF(1 > 0, 'True', 'False'); -- True
 SELECT IFNULL(NULL, 'Default'); -- Default
 SELECT NULLIF(10, 10); -- NULL (两值相等返回NULL)
 ​
 -- CASE WHEN
 SELECT 
     score,
     CASE 
         WHEN score >= 90 THEN 'A'
         WHEN score >= 80 THEN 'B'
         WHEN score >= 70 THEN 'C'
         ELSE 'D'
     END AS grade
 FROM students;
4.2 聚合函数
sql 复制代码
 -- 基本聚合
 SELECT COUNT(*) FROM users; -- 记录数
 SELECT AVG(price) FROM products; -- 平均值
 SELECT SUM(quantity) FROM order_items; -- 总和
 SELECT MAX(salary) FROM employees; -- 最大值
 SELECT MIN(age) FROM customers; -- 最小值
 ​
 -- 分组聚合
 SELECT department_id, AVG(salary)
 FROM employees
 GROUP BY department_id
 HAVING AVG(salary) > 5000;

5. 窗口函数 (MySQL 8.0+)

sql 复制代码
 -- 排名函数
 SELECT 
     name, salary,
     RANK() OVER (ORDER BY salary DESC) AS rank,
     DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank,
     ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
 FROM employees;
 ​
 -- 分区计算
 SELECT 
     department_id, name, salary,
     AVG(salary) OVER (PARTITION BY department_id) AS dept_avg_salary
 FROM employees;
 ​
 -- 累计计算
 SELECT 
     order_date, amount,
     SUM(amount) OVER (ORDER BY order_date) AS running_total
 FROM orders;

6. JSON 函数 (MySQL 5.7+)

sql 复制代码
 -- 创建JSON
 SELECT JSON_OBJECT('name', 'John', 'age', 30);
 SELECT JSON_ARRAY(1, 'a', TRUE, NULL);
 ​
 -- 提取JSON值
 SELECT JSON_EXTRACT('{"name": "John", "age": 30}', '$.name'); -- "John"
 SELECT JSON_UNQUOTE(JSON_EXTRACT('{"name": "John"}', '$.name')); -- John
 ​
 -- 修改JSON
 SELECT JSON_SET('{"name": "John"}', '$.age', 30); -- {"name": "John", "age": 30}
 SELECT JSON_REMOVE('{"name": "John", "age": 30}', '$.age'); -- {"name": "John"}

7. 系统信息函数

sql 复制代码
 -- 数据库信息
 SELECT DATABASE(); -- 当前数据库名
 SELECT USER(); -- 当前用户
 SELECT VERSION(); -- MySQL版本
 ​
 -- 连接信息
 SELECT CONNECTION_ID(); -- 连接ID
 SELECT LAST_INSERT_ID(); -- 最后插入的ID
 ​
 -- 性能分析
 SELECT BENCHMARK(1000000, MD5('test')); -- 执行MD5 100万次

8. 加密函数

sql 复制代码
 -- 哈希函数
 SELECT MD5('password'); -- 32字符MD5哈希
 SELECT SHA1('password'); -- 40字符SHA1哈希
 SELECT SHA2('password', 256); -- 64字符SHA256哈希
 ​
 -- 加密解密
 SELECT AES_ENCRYPT('secret', 'key');
 SELECT AES_DECRYPT(encrypted_data, 'key');
 ​
 -- 密码函数
 SELECT PASSWORD('mypass'); -- 已废弃,不推荐使用

二、MySQL 约束

约束是用于限制表中数据类型的规则,确保数据的准确性和可靠性。MySQL 支持多种约束类型,以下是简要介绍:

1. 主键约束 (PRIMARY KEY)

1.1 基本用法
sql 复制代码
 -- 创建表时定义单列主键
 CREATE TABLE users (
     user_id INT PRIMARY KEY,
     username VARCHAR(50) NOT NULL
 );
 ​
 -- 创建表时定义多列组合主键
 CREATE TABLE order_items (
     order_id INT,
     product_id INT,
     quantity INT,
     PRIMARY KEY (order_id, product_id)
 );
1.2 修改表添加主键
sql 复制代码
 ALTER TABLE employees ADD PRIMARY KEY (emp_id);
1.3 自增主键
sql 复制代码
 CREATE TABLE products (
     product_id INT AUTO_INCREMENT PRIMARY KEY,
     product_name VARCHAR(100) NOT NULL
 );

2. 外键约束 (FOREIGN KEY)

2.1 基本用法
sql 复制代码
 CREATE TABLE orders (
     order_id INT PRIMARY KEY,
     customer_id INT,
     order_date DATE,
     FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
 );
2.2 级联操作
sql 复制代码
 CREATE TABLE order_items (
     item_id INT PRIMARY KEY,
     order_id INT,
     product_id INT,
     FOREIGN KEY (order_id) REFERENCES orders(order_id)
         ON DELETE CASCADE  -- 主表删除时级联删除
         ON UPDATE CASCADE, -- 主表更新时级联更新
     FOREIGN KEY (product_id) REFERENCES products(product_id)
         ON DELETE SET NULL -- 主表删除时设为NULL
 );
2.3 修改表添加外键
sql 复制代码
 ALTER TABLE employees
 ADD CONSTRAINT fk_dept
 FOREIGN KEY (department_id) REFERENCES departments(dept_id);

3. 唯一约束 (UNIQUE)

3.1 基本用法
sql 复制代码
 CREATE TABLE employees (
     emp_id INT PRIMARY KEY,
     email VARCHAR(100) UNIQUE,
     phone VARCHAR(20),
     CONSTRAINT uc_phone UNIQUE (phone) -- 命名约束
 );
3.2 多列组合唯一
sql 复制代码
 CREATE TABLE class_registry (
     student_id INT,
     class_id INT,
     semester VARCHAR(10),
     UNIQUE (student_id, class_id, semester)
 );
3.3 修改表添加唯一约束
sql 复制代码
 ALTER TABLE products ADD UNIQUE (product_code);

4. 非空约束 (NOT NULL)

4.1 基本用法
sql 复制代码
 CREATE TABLE customers (
     customer_id INT PRIMARY KEY,
     name VARCHAR(100) NOT NULL,
     email VARCHAR(100) NOT NULL UNIQUE
 );
4.2 修改表添加非空约束
sql 复制代码
 ALTER TABLE employees MODIFY COLUMN hire_date DATE NOT NULL;

5. 默认值约束 (DEFAULT)

5.1 基本用法
sql 复制代码
 CREATE TABLE orders (
     order_id INT PRIMARY KEY,
     order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     status VARCHAR(20) DEFAULT 'Pending',
     total_amount DECIMAL(10,2) DEFAULT 0.00
 );
5.2 修改表添加默认值
sql 复制代码
 ALTER TABLE products 
 ALTER COLUMN stock SET DEFAULT 0;

6. 检查约束 (CHECK)

6.1 基本用法
sql 复制代码
 CREATE TABLE employees (
     emp_id INT PRIMARY KEY,
     name VARCHAR(100) NOT NULL,
     salary DECIMAL(10,2) CHECK (salary > 0),
     age INT CHECK (age >= 18 AND age <= 65),
     gender VARCHAR(10) CHECK (gender IN ('Male', 'Female', 'Other'))
 );
6.2 命名检查约束
sql 复制代码
 CREATE TABLE products (
     product_id INT PRIMARY KEY,
     price DECIMAL(10,2),
     discount DECIMAL(10,2),
     CONSTRAINT chk_price CHECK (price > 0),
     CONSTRAINT chk_discount CHECK (discount >= 0 AND discount <= price)
 );
6.3 修改表添加检查约束
sql 复制代码
 ALTER TABLE employees
 ADD CONSTRAINT chk_salary CHECK (salary > 0);

7. 约束管理

7.1 查看约束
sql 复制代码
 -- 查看表的所有约束
 SELECT * FROM information_schema.TABLE_CONSTRAINTS 
 WHERE TABLE_SCHEMA = 'your_database' AND TABLE_NAME = 'your_table';
 ​
 -- 查看外键约束
 SELECT * FROM information_schema.REFERENTIAL_CONSTRAINTS 
 WHERE CONSTRAINT_SCHEMA = 'your_database';
7.2 删除约束
sql 复制代码
 -- 删除主键
 ALTER TABLE users DROP PRIMARY KEY;
 ​
 -- 删除外键
 ALTER TABLE orders DROP FOREIGN KEY fk_customer;
 ​
 -- 删除唯一约束
 ALTER TABLE employees DROP INDEX uc_phone;
 ​
 -- 删除检查约束 (MySQL 8.0.16+)
 ALTER TABLE employees DROP CHECK chk_salary;

三、多表查询

1. 内连接 (INNER JOIN)

sql 复制代码
 -- 基本内连接
 SELECT 
     e.emp_id, 
     e.emp_name, 
     d.dept_name
 FROM 
     employees e
 INNER JOIN 
     departments d ON e.dept_id = d.dept_id;
 ​
 -- 多表内连接
 SELECT 
     o.order_id,
     c.customer_name,
     p.product_name,
     oi.quantity
 FROM 
     orders o
 INNER JOIN customers c ON o.customer_id = c.customer_id
 INNER JOIN order_items oi ON o.order_id = oi.order_id
 INNER JOIN products p ON oi.product_id = p.product_id;

2. 左外连接 (LEFT JOIN)

sql 复制代码
 -- 保留左表所有记录
 SELECT 
     d.dept_name,
     e.emp_name
 FROM 
     departments d
 LEFT JOIN 
     employees e ON d.dept_id = e.dept_id;

3. 右外连接 (RIGHT JOIN)

sql 复制代码
 -- 保留右表所有记录
 SELECT 
     e.emp_name,
     d.dept_name
 FROM 
     employees e
 RIGHT JOIN 
     departments d ON e.dept_id = d.dept_id;

4. 全外连接 (FULL OUTER JOIN) - MySQL不支持,可用UNION模拟

sql 复制代码
 -- 使用UNION模拟全连接
 SELECT 
     e.emp_name,
     d.dept_name
 FROM 
     employees e
 LEFT JOIN 
     departments d ON e.dept_id = d.dept_id
 UNION
 SELECT 
     e.emp_name,
     d.dept_name
 FROM 
     employees e
 RIGHT JOIN 
     departments d ON e.dept_id = d.dept_id
 WHERE 
     e.dept_id IS NULL;

5. 交叉连接 (CROSS JOIN)

sql 复制代码
 -- 笛卡尔积
 SELECT 
     e.emp_name,
     p.project_name
 FROM 
     employees e
 CROSS JOIN 
     projects p;

6. 自连接 (SELF JOIN)

sql 复制代码
 -- 查找员工及其经理
 SELECT 
     e1.emp_name AS employee,
     e2.emp_name AS manager
 FROM 
     employees e1
 LEFT JOIN 
     employees e2 ON e1.manager_id = e2.emp_id;
 ​
 -- 查找同一部门的员工对
 SELECT 
     a.emp_name AS employee1,
     b.emp_name AS employee2,
     a.dept_id
 FROM 
     employees a
 JOIN 
     employees b ON a.dept_id = b.dept_id
 WHERE 
     a.emp_id < b.emp_id;

7. 自然连接 (NATURAL JOIN)

sql 复制代码
 -- 自动匹配相同名称的列
 SELECT 
     e.emp_name,
     d.dept_name
 FROM 
     employees e
 NATURAL JOIN 
     departments d;

8. USING 子句

sql 复制代码
 -- 简化连接条件
 SELECT 
     e.emp_name,
     d.dept_name
 FROM 
     employees e
 JOIN 
     departments d USING (dept_id);

9. 子查询

9.1 WHERE子句中的子查询
(1)标量子查询(返回单个值)
sql 复制代码
 -- 查询高于平均工资的员工
 SELECT emp_name, salary
 FROM employees
 WHERE salary > (SELECT AVG(salary) FROM employees);
 ​
 -- 查询最后入职的员工
 SELECT emp_name, hire_date
 FROM employees
 WHERE hire_date = (SELECT MAX(hire_date) FROM employees);
(2)列子查询(返回单列多行)
sql 复制代码
 -- 使用IN操作符
 SELECT emp_name, dept_id
 FROM employees
 WHERE dept_id IN (SELECT dept_id FROM departments WHERE location = 'New York');
 ​
 -- 使用ANY/SOME操作符
 SELECT emp_name, salary
 FROM employees
 WHERE salary > ANY (SELECT salary FROM employees WHERE dept_id = 10);
 ​
 -- 使用ALL操作符
 SELECT emp_name, salary
 FROM employees
 WHERE salary > ALL (SELECT salary FROM employees WHERE dept_id = 10);
(3)行子查询(返回单行多列)
sql 复制代码
 -- 查询与特定员工工资和部门相同的其他员工
 SELECT emp_name, salary, dept_id
 FROM employees
 WHERE (salary, dept_id) = (SELECT salary, dept_id FROM employees WHERE emp_id = 100);
9.2 FROM子句中的子查询(派生表)
sql 复制代码
 -- 计算每个部门的平均工资,然后查询高于公司平均工资的部门
 SELECT d.dept_name, dept_avg.avg_salary
 FROM departments d
 JOIN (
     SELECT dept_id, AVG(salary) AS avg_salary
     FROM employees
     GROUP BY dept_id
 ) dept_avg ON d.dept_id = dept_avg.dept_id
 WHERE dept_avg.avg_salary > (SELECT AVG(salary) FROM employees);
 ​
 -- 使用派生表进行分页
 SELECT *
 FROM (
     SELECT emp_id, emp_name, salary
     FROM employees
     ORDER BY salary DESC
     LIMIT 10
 ) AS top_earners;
9.3 SELECT子句中的子查询(标量子查询)
sql 复制代码
 -- 查询员工信息及其部门平均工资
 SELECT 
     emp_id,
     emp_name,
     salary,
     (SELECT AVG(salary) FROM employees e2 WHERE e2.dept_id = e1.dept_id) AS dept_avg_salary,
     salary - (SELECT AVG(salary) FROM employees e2 WHERE e2.dept_id = e1.dept_id) AS diff_from_avg
 FROM employees e1;
 ​
 -- 查询产品信息及订单数量
 SELECT 
     p.product_id,
     p.product_name,
     (SELECT COUNT(*) FROM order_items oi WHERE oi.product_id = p.product_id) AS order_count
 FROM products p;
9.4 HAVING子句中的子查询
sql 复制代码
 -- 查询平均工资高于公司平均工资的部门
 SELECT 
     dept_id, 
     AVG(salary) AS avg_salary
 FROM employees
 GROUP BY dept_id
 HAVING AVG(salary) > (SELECT AVG(salary) FROM employees);
 ​
 -- 查询订单数量超过客户平均订单数的客户
 SELECT 
     customer_id, 
     COUNT(*) AS order_count
 FROM orders
 GROUP BY customer_id
 HAVING COUNT(*) > (SELECT AVG(order_count) 
                    FROM (SELECT COUNT(*) AS order_count 
                          FROM orders 
                          GROUP BY customer_id) AS counts);
9.5 EXISTS和NOT EXISTS子查询
sql 复制代码
 -- 查询有订单的客户
 SELECT customer_name
 FROM customers c
 WHERE EXISTS (
     SELECT 1 
     FROM orders o 
     WHERE o.customer_id = c.customer_id
 );
 ​
 -- 查询没有订单的客户
 SELECT customer_name
 FROM customers c
 WHERE NOT EXISTS (
     SELECT 1 
     FROM orders o 
     WHERE o.customer_id = c.customer_id
 );
 ​
 -- 查询购买了所有产品的客户
 SELECT customer_name
 FROM customers c
 WHERE NOT EXISTS (
     SELECT product_id
     FROM products p
     WHERE NOT EXISTS (
         SELECT 1
         FROM orders o
         JOIN order_items oi ON o.order_id = oi.order_id
         WHERE o.customer_id = c.customer_id
         AND oi.product_id = p.product_id
     )
 );

10. 集合操作

10.1 UNION 和 UNION ALL
sql 复制代码
 -- 合并结果集 (去重)
 SELECT product_id FROM current_products
 UNION
 SELECT product_id FROM discontinued_products;
 ​
 -- 合并结果集 (保留重复)
 SELECT product_id FROM current_products
 UNION ALL
 SELECT product_id FROM discontinued_products;
10.2 INTERSECT (MySQL 8.0.31+)
sql 复制代码
 -- 交集
 SELECT customer_id FROM premium_customers
 INTERSECT
 SELECT customer_id FROM active_customers;
10.3 EXCEPT/MINUS (MySQL 8.0.31+)
sql 复制代码
 -- 差集
 SELECT employee_id FROM all_employees
 EXCEPT
 SELECT employee_id FROM current_employees;

四、事务 (Transaction)

1. 事务的基本特性 (ACID)

  • 原子性 (Atomicity): 事务是不可分割的工作单位。

  • 一致性 (Consistency): 事务执行前后数据库保持一致状态。

  • 隔离性 (Isolation): 多个事务并发执行时互不干扰。

  • 持久性 (Durability): 事务提交后对数据库的改变是永久的。

2. 事务控制语句

sql 复制代码
 -- 开始事务
 START TRANSACTION;
 ​
 -- 执行SQL语句
 INSERT INTO accounts (user_id, balance) VALUES (1, 1000);
 UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
 UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
 ​
 -- 提交事务
 COMMIT;
 ​
 -- 回滚事务
 ROLLBACK;

3. 事务隔离级别

sql 复制代码
 -- 查看当前隔离级别
 SELECT @@transaction_isolation;
 ​
 -- 设置隔离级别(会话级)
 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
 ​
 -- 设置隔离级别(全局)
 SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
 ​
 -- 四种隔离级别
 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
 SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- MySQL默认
 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

四种隔离级别比较:

隔离级别 脏读 不可重复读 幻读 性能
READ UNCOMMITTED 可能 可能 可能 最高
READ COMMITTED 不可能 可能 可能 高
REPEATABLE READ(默认) 不可能 不可能 可能 中
SERIALIZABLE 不可能 不可能 不可能 低

4. 事务并发问题

(1)脏读 (Dirty Read)

读取到其他事务未提交的数据。

sql 复制代码
 -- 事务A
 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
 START TRANSACTION;
 SELECT * FROM accounts WHERE user_id = 1; -- 可能读取到事务B未提交的数据
 ​
 -- 事务B
 START TRANSACTION;
 UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
 -- 尚未提交
(2)不可重复读 (Non-repeatable Read)

同一事务内多次读取同一数据结果不同。

sql 复制代码
 -- 事务A
 SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
 START TRANSACTION;
 SELECT * FROM accounts WHERE user_id = 1; -- 第一次读取
 ​
 -- 事务B提交了更新
 UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
 COMMIT;
 ​
 SELECT * FROM accounts WHERE user_id = 1; -- 第二次读取结果不同
(3)幻读 (Phantom Read)

同一事务内多次查询返回的结果集不同。

sql 复制代码
 -- 事务A
 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
 START TRANSACTION;
 SELECT * FROM accounts WHERE balance > 1000; -- 返回10条记录
 ​
 -- 事务B插入新记录并提交
 INSERT INTO accounts VALUES (11, '新用户', 1500);
 COMMIT;
 ​
 SELECT * FROM accounts WHERE balance > 1000; -- 返回11条记录

5. 保存点 (SAVEPOINT)

sql 复制代码
 START TRANSACTION;
 ​
 INSERT INTO orders (order_id, user_id) VALUES (1, 1);
 SAVEPOINT savepoint1;
 ​
 UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
 -- 如果出现问题可以回滚到保存点
 ROLLBACK TO savepoint1;
 ​
 COMMIT;
相关推荐
小羊没烦恼!4 分钟前
浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色
前端·数据库·后端·python·web安全·oracle
hgf10117 分钟前
大内密探 · 案卷 1.2:一夫当关,万夫莫开(Receive Enable)
数据库·mysql
data analyse 45623 分钟前
页面卸载时埋点上报总丢失?sendBeacon 上报与补偿方案
大数据·运维·服务器·前端·数据库·人工智能·数据分析
企查查数据服务24 分钟前
充电桩集采准入:用企业数据做供应商失信批量核验
大数据·数据库·人工智能
敲上瘾31 分钟前
分布式系统——Redis哨兵:自动故障转移与选举原理
linux·数据库·redis·分布式·缓存·微服务
子沫20201 小时前
mysql慢sql
sql·mysql
2501_933923251 小时前
MySQL CRUD 详解:表数据插入、更新与删除,附生产避坑指南
数据库·mysql
kaixin_啊啊1 小时前
飞牛部署Mtab完整实战:Docker安装、MySQL建库与固定地址访问
mysql·docker·容器
爱喝水的鱼丶3 小时前
SAP-ABAP:S/4 HANA ABAP 新特性入门:与 ECC ABAP 的核心差异、架构优势与学习路径规划
运维·数据库·性能优化·sap·abap·hana·开发交流
余槐i10 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化