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;
相关推荐
患得患失9492 分钟前
【后端】【Django DRF】从零实现RBAC 权限管理系统
数据库·django·sqlite
__淡墨青衫__18 分钟前
Django之旅:第五节--Mysql数据库操作(一)
数据库·mysql·django
橙序研工坊2 小时前
MySQL的基础语法1(增删改查、DDL、DML、DQL和DCL)
数据库·sql·mysql·database
晴天Y282 小时前
redis部署架构
数据库·redis·架构
gjc5923 小时前
MySQL源码学习系列(二)--面试高频问题:general log、slowlog记录顺序
数据库·学习·mysql·面试·职场和发展
晓oi3 小时前
MySQL———作业实验
数据库·mysql
hh_fine3 小时前
解决 “Cannot read SQL script from class path resource [sql/XX.sql]“ 错误
数据库·sql
余华余华3 小时前
VSCODE npm: 因为在此系统上禁止运行脚本。有关详细信息,请参阅 ...
java·服务器·数据库·笔记·oracle
不剪发的Tony老师3 小时前
IvorySQL:兼容Oracle数据库的开源PostgreSQL
数据库·postgresql·oracle
独行soc3 小时前
2025年渗透测试面试题总结-某快手-安全工程师(题目+回答)
网络·数据库·python·安全·面试·职场和发展·红蓝攻防