SQL 是一种专门为关系型数据库设计的语言,用于处理结构化数据。关系型数据库以表格(Table)的形式存储数据,每个表格包含行(Row)和列(Column),SQL 提供了通过声明式语句与这些数据交互的方式。
;
)结束语句是 ANSI SQL 标准的要求,用于明确一条语句的结束。SELECT * FROM employees WHERE department = 'HR';
SELECT name, salary
FROM employees
WHERE department = 'HR'
ORDER BY salary DESC;
SELECT
、FROM
、WHERE
)另起一行。SELECT name,salary FROM employees WHERE department='HR' ORDER BY salary DESC;
SELECT name, salary
FROM employees
WHERE department = 'HR'
ORDER BY salary DESC;
SELECT
、FROM
、WHERE
)和数据库对象名称(如表名、列名)在 MySQL 中默认不区分大小写。例如,SELECT
和 select
等效。employee_name
),以提高代码可读性和一致性。TABLE
、SELECT
)作为表名或列名。employees
而不是 tbl1
。select * from EMPLOYEES; -- 等同于 SELECT * FROM employees;
SELECT name, salary
FROM employees
WHERE department = 'HR';
注释用于为 SQL 代码添加说明,便于理解和维护。SQL 支持单行注释和多行注释,格式在大多数数据库中通用。
-- 注释内容
S 注释内容`(MySQL 和大多数数据库支持)# 注释内容
(MySQL 特有,PostgreSQL 等部分数据库不支持)--
或 #
开始,直到行末。-- 查询 HR 部门员工
SELECT * FROM employees WHERE department = 'HR';
# 这是一个单行注释
/* 注释内容
可以跨多行 */
/*
开始,到 */
结束,可跨越多行。/* 这是一个多行注释
用于解释复杂的查询逻辑 */
SELECT name, salary
FROM employees
WHERE department = 'HR';
#
单行注释主要在 MySQL 中使用,PostgreSQL 和 Oracle 不支持。DDL 用于定义和管理数据库的结构,包括数据库、表、索引、视图等的创建、修改和删除。DDL 语句会直接影响数据库的模式(Schema),执行后通常会自动提交(即无法回滚,具体取决于数据库系统)。
说明:查询数据库管理系统中当前用户有权限访问的所有数据库列表。
SQL命令:
SHOW DATABASES;
操作步骤:
示例:
SHOW DATABASES;
输出示例:
+---------------------+
| Database |
+---------------------+
| information_schema |
| mysql |
| test_db |
| my_app |
+---------------------+
注意事项:
information_schema
和mysql
)是系统数据库,通常用于存储元数据或系统配置。SHOW DATABASES
权限才能执行此操作。说明:查询当前会话正在使用的数据库。
SQL命令:
SELECT DATABASE();
操作步骤:
NULL
或空值。示例:
SELECT DATABASE();
输出示例(假设当前使用的是test_db
):
+------------+
| DATABASE() |
+------------+
| test_db |
+------------+
注意事项:
USE
命令选择数据库,执行此命令会返回空结果。说明:创建新的数据库,可以使用默认字符集或指定特定的字符集和排序规则。
SQL命令:
CREATE DATABASE 数据库名;
CREATE DATABASE 数据库名
CHARACTER SET 字符集
[COLLATE 排序规则];
操作步骤:
utf8mb4
或配置文件中定义的字符集)。utf8mb4
)和排序规则(如utf8mb4_unicode_ci
),数据库将使用这些设置。CREATE DATABASE
命令。示例:
my_app
的数据库,使用默认字符集:CREATE DATABASE my_app;
my_app
的数据库,指定字符集为utf8mb4
和排序规则为utf8mb4_unicode_ci
:CREATE DATABASE my_app
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
输出:
Query OK, 1 row affected (0.01 sec)
常用字符集和排序规则:
utf8mb4
:支持完整的Unicode字符,包括表情符号,推荐用于国际化应用。utf8
:较老的Unicode字符集,仅支持部分字符(不推荐)。latin1
:支持西欧语言字符。utf8mb4_unicode_ci
:基于Unicode标准排序,适用于多语言环境。utf8mb4_general_ci
:简化的排序规则,性能稍高但准确性稍低。latin1_swedish_ci
:适用于拉丁字符集的瑞典语排序规则。注意事项:
CREATE
权限才能创建数据库。说明:删除指定的数据库及其所有内容(包括表、数据等),操作不可逆。
SQL命令:
DROP DATABASE 数据库名;
操作步骤:
DROP DATABASE
命令。示例:
DROP DATABASE my_app;
输出:
Query OK, 0 rows affected (0.02 sec)
注意事项:
DROP
权限才能删除数据库。DROP DATABASE
会报错,除非使用以下命令:DROP DATABASE IF EXISTS 数据库名;
该命令会在数据库不存在时避免报错。
说明:将当前会话的上下文切换到指定的数据库,以便后续操作(如查询表或插入数据)在此数据库中进行。
SQL命令:
USE 数据库名;
操作步骤:
SHOW DATABASES
查看)。USE
命令切换到指定数据库。SELECT
、INSERT
)将在该数据库中执行。示例:
USE my_app;
输出:
Database changed
验证切换:
SELECT DATABASE();
确认当前数据库是否切换成功。注意事项:
USE
命令会报错。以下是上述操作的SQL命令快速参考:
SHOW DATABASES;
SELECT DATABASE();
CREATE DATABASE 数据库名;
CREATE DATABASE 数据库名 CHARACTER SET 字符集 COLLATE 排序规则;
DROP DATABASE 数据库名;
USE 数据库名;
CREATE
、DROP
、SELECT
等),具体权限由数据库管理员分配。utf8mb4
作为默认字符集,以支持更广泛的字符和国际化需求。这一部分介绍 DDL 中用于修改或删除数据库对象的语句,主要包括 ALTER
、DROP
和 TRUNCATE
。
ALTER TABLE table_name
{ ADD column_name datatype [constraints] |
MODIFY column_name datatype [constraints] |
DROP COLUMN column_name |
ADD CONSTRAINT constraint_name constraint_definition |
DROP CONSTRAINT constraint_name };
MODIFY
,Oracle 用 ALTER COLUMN
)。ALTER TABLE employees
ADD email VARCHAR(100);
ALTER TABLE employees
MODIFY name VARCHAR(100);
ALTER TABLE employees
DROP COLUMN email;
ALTER TABLE employees
ADD CONSTRAINT fk_dept
FOREIGN KEY (department) REFERENCES departments(dept_id);
DROP { DATABASE | TABLE | INDEX | VIEW } object_name;
IF EXISTS
避免错误。DROP TABLE employees;
DROP DATABASE company_db;
DROP INDEX idx_salary ON employees;
DROP VIEW hr_employees;
TRUNCATE TABLE table_name;
DELETE
更快,因为不记录每行删除操作。TRUNCATE TABLE employees;
employees
表的数据,但保留表结构。;
)结束,符合 ANSI SQL 标准。ROLLBACK
撤销(PostgreSQL 除外,支持事务中的 DDL)。CREATE
、ALTER
、DROP
、TRUNCATE
)在 MySQL、PostgreSQL、SQL Server、Oracle 等数据库中通用。MODIFY
语法在 SQL Server 中可能是 ALTER COLUMN
。ALTER TABLE
的支持有限(如不支持删除列)。employee_name
)。TABLE
、INDEX
)。-- 创建员工表
或 # 创建员工表
(MySQL)。/* 表结构定义 */
。CREATE DATABASE
)。以下是一个结合创建和修改的 DDL 示例,展示 2.3.1 和 2.3.2 的内容:
-- 2.3.1 创建数据库和表
CREATE DATABASE company_db;
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
department VARCHAR(50),
salary DECIMAL(10, 2)
);
-- 2.3.2 修改表结构
ALTER TABLE employees
ADD hire_date DATE;
-- 清空表数据
TRUNCATE TABLE employees;
-- 删除表
DROP TABLE employees;
CREATE
语句创建数据库(DATABASE
)、表(TABLE
)、索引(INDEX
)和视图(VIEW
),定义数据库结构。ALTER
修改表结构,DROP
删除对象,TRUNCATE
清空表数据,管理数据库模式的变更。说明:列出当前数据库中所有表的名称。
SQL 命令:
SHOW TABLES;
操作步骤:
USE 数据库名;
切换到目标数据库。SHOW TABLES;
命令,数据库返回当前数据库中所有表的列表。示例:
USE my_app;
SHOW TABLES;
输出示例:
+------------------+
| Tables_in_my_app |
+------------------+
| users |
| orders |
| products |
+------------------+
深入分析:
SELECT
权限来查看表列表。注意事项:
SHOW FULL TABLES;
查看更多信息(如表类型:BASE TABLE
或 VIEW
)。说明:查询指定表的字段名、数据类型、约束等结构信息。
SQL 命令:
DESCRIBE 表名;
或:
SHOW COLUMNS FROM 表名;
操作步骤:
DESCRIBE
或 SHOW COLUMNS
命令,返回表的字段详细信息。示例:
DESCRIBE users;
输出示例:
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| username | varchar(50) | NO | | NULL | |
| email | varchar(100)| YES | | NULL | |
| created | datetime | YES | | NULL | |
+----------+-------------+------+-----+---------+----------------+
深入分析:
Field
:字段名。Type
:字段的数据类型。Null
:是否允许为空(YES
表示允许,NO
表示不允许)。Key
:索引类型(PRI
表示主键,UNI
表示唯一索引,MUL
表示普通索引)。Default
:默认值。Extra
:附加信息(如 auto_increment
表示自增)。注意事项:
SHOW CREATE TABLE 表名;
查看更详细的建表语句(见下文)。说明:查看创建指定表的完整 SQL 语句,包括字段定义、约束、索引等。
SQL 命令:
SHOW CREATE TABLE 表名;
操作步骤:
SHOW CREATE TABLE
命令,返回创建表的完整 SQL 语句。示例:
SHOW CREATE TABLE users;
输出示例:
+-------+------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+------------------------------------------------------------------------------------------------------------------+
| users | CREATE TABLE `users` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`email` varchar(100) DEFAULT NULL,
`created` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |
+-------+------------------------------------------------------------------------------------------------------------------+
深入分析:
NOT NULL
)。ENGINE=InnoDB
、字符集 CHARSET=utf8mb4
)。注意事项:
ENGINE
)。说明:创建新表,定义字段、数据类型、约束等。
SQL 命令:
CREATE TABLE 表名 (
字段名1 数据类型 [约束],
字段名2 数据类型 [约束],
...
[表级约束]
) [表选项];
操作步骤:
NOT NULL
、PRIMARY KEY
、DEFAULT
)。CREATE TABLE
命令。示例:
创建一个用户表 users
,包含自增主键、用户名、邮箱和创建时间:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) DEFAULT NULL,
created DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
深入分析:
id
:整型,自增主键。username
:最大 50 个字符的字符串,不允许为空。email
:最大 100 个字符的字符串,允许为空。created
:日期时间类型,默认值为当前时间戳。ENGINE=InnoDB
:使用 InnoDB 存储引擎,支持事务和外键。DEFAULT CHARSET=utf8mb4
:设置表字符集为 utf8mb4
,支持 Unicode。注意事项:
SELECT
、TABLE
)。以下是常见数据类型的详细说明,分为数值类型、字符串类型和日期时间类型。
数值类型用于存储整数或浮点数,常见类型包括:
类型 |
描述 |
范围(有符号) |
存储空间 |
|
微型整数 |
-128 到 127 |
1 字节 |
|
小整数 |
-32,768 到 32,767 |
2 字节 |
|
标准整数 |
-231 到 231-1 |
4 字节 |
|
大整数 |
-263 到 263-1 |
8 字节 |
|
单精度浮点数 |
约 ±3.4E38 |
4 字节 |
|
双精度浮点数 |
约 ±1.79E308 |
8 字节 |
|
定点数,精确小数(M 位数字,D 位小数) |
取决于 M 和 D |
变长 |
特点:
UNSIGNED
关键字指定无符号(如 INT UNSIGNED
范围为 0 到 2^32-1)。DECIMAL
适合金融数据,避免浮点数精度问题。TINYINT
用于状态码)以节省存储空间。示例:
CREATE TABLE products (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
price DECIMAL(10,2),
quantity SMALLINT
);
字符串类型用于存储文本数据,常见类型包括:
类型 |
描述 |
最大长度 |
存储空间 |
|
定长字符串,固定长度 M 个字符 |
0-255 个字符 |
M 字节 |
|
变长字符串,最大长度 M 个字符 |
0-65,535 个字符(视字符集) |
实际长度+1-2 字节 |
|
变长文本,适合大文本 |
65,535 个字符 |
实际长度+2 字节 |
|
中等文本 |
16,777,215 个字符 |
实际长度+3 字节 |
|
大文本 |
4,294,967,295 个字符 |
实际长度+4 字节 |
特点:
CHAR
适合固定长度数据(如状态码),存储效率高。VARCHAR
适合长度可变的数据(如用户名),节省空间。utf8mb4
字符集下,每个字符可能占 1-4 字节。示例:
CREATE TABLE articles (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100) NOT NULL,
content TEXT
);
日期时间类型用于存储日期和时间,常见类型包括:
类型 |
描述 |
范围 |
存储空间 |
|
日期(年-月-日) |
1000-01-01 到 9999-12-31 |
3 字节 |
|
时间(时:分:秒) |
-838:59:59 到 838:59:59 |
3 字节 |
|
日期和时间 |
1000-01-01 00:00:00 到 9999-12-31 23:59:59 |
8 字节 |
|
时间戳,存储 UTC 时间 |
1970-01-01 00:00:01 到 2038-01-19 03:14:07 |
4 字节 |
|
年份 |
1901 到 2155 |
1 字节 |
特点:
DATETIME
:存储实际的日期时间,不受时区影响。TIMESTAMP
:存储 UTC 时间戳,自动转换时区,适合记录事件时间。DATETIME
和 TIMESTAMP
支持 CURRENT_TIMESTAMP
作为默认值。TIMESTAMP
比 DATETIME
更节省空间,但范围较小。示例:
CREATE TABLE events (
id INT AUTO_INCREMENT PRIMARY KEY,
event_name VARCHAR(100),
event_date DATETIME DEFAULT CURRENT_TIMESTAMP
);
案例:设计一个简单的电商系统数据库表结构,包括用户表、商品表和订单表。
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) NOT NULL,
stock SMALLINT UNSIGNED DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
product_id INT NOT NULL,
quantity SMALLINT UNSIGNED NOT NULL,
order_date DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
分析:
DECIMAL
确保精度,库存为无符号整数。InnoDB
引擎支持外键和事务,utf8mb4
字符集支持国际化。应用场景:
SELECT * FROM users WHERE id = 1;
INSERT INTO orders (user_id, product_id, quantity) VALUES (1, 1, 2);
SELECT stock FROM products WHERE id = 1;
以下是修改表结构的常见操作,使用 ALTER TABLE
语句。
说明:向现有表中添加新字段。
SQL 命令:
ALTER TABLE 表名 ADD 字段名 数据类型 [约束];
示例:
向 users
表添加 phone
字段:
ALTER TABLE users ADD phone VARCHAR(20) DEFAULT NULL;
深入分析:
AFTER 字段名
指定插入位置:ALTER TABLE users ADD phone VARCHAR(20) AFTER username;
注意事项:
NULL
)。说明:更改现有字段的数据类型。
SQL 命令:
ALTER TABLE 表名 MODIFY 字段名 新数据类型 [约束];
示例:
将 users
表的 phone
字段类型从 VARCHAR(20)
改为 VARCHAR(30)
:
ALTER TABLE users MODIFY phone VARCHAR(30) DEFAULT NULL;
深入分析:
INT
改为 TINYINT
时值超出范围)。注意事项:
说明:同时更改字段名和数据类型。
SQL 命令:
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型 [约束];
示例:
将 users
表的 phone
字段改为 contact_number
并将类型改为 VARCHAR(50)
:
ALTER TABLE users CHANGE phone contact_number VARCHAR(50) DEFAULT NULL;
深入分析:
CHANGE
允许同时修改字段名和类型,功能比 MODIFY
更强大。NOT NULL
、DEFAULT
)。注意事项:
说明:从表中删除指定字段。
SQL 命令:
ALTER TABLE 表名 DROP 字段名;
示例:
删除 users
表的 contact_number
字段:
ALTER TABLE users DROP contact_number;
深入分析:
注意事项:
说明:更改表的名称。
SQL 命令:
ALTER TABLE 旧表名 RENAME TO 新表名;
或:
RENAME TABLE 旧表名 TO 新表名;
示例:
将 users
表重命名为 customers
:
ALTER TABLE users RENAME TO customers;
深入分析:
注意事项:
说明:删除指定表及其所有数据和结构。
SQL 命令:
DROP TABLE 表名;
示例:
删除 customers
表:
DROP TABLE customers;
深入分析:
注意事项:
DROP TABLE IF EXISTS 表名;
避免表不存在时的报错。说明:先删除表(如果存在),然后重新创建具有相同或不同结构的表。
SQL 命令:
DROP TABLE IF EXISTS 表名;
CREATE TABLE 表名 (
字段定义
);
示例:
删除并重新创建 users
表:
DROP TABLE IF EXISTS users;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
深入分析:
IF EXISTS
确保即使表不存在也不会报错。注意事项:
2.3.2.1 查询创建:
SHOW TABLES;
DESCRIBE 表名;
SHOW CREATE TABLE 表名;
CREATE TABLE 表名 (字段定义) [表选项];
2.3.2.2 数据类型:
TINYINT
、INT
、DECIMAL
等,适合精确或范围不同的场景。CHAR
、VARCHAR
、TEXT
等,适合定长或变长文本。DATETIME
、TIMESTAMP
等,适合时间记录。2.3.2.3 案例:
2.3.2.4 修改:
ALTER TABLE 表名 ADD 字段名 数据类型;
ALTER TABLE 表名 MODIFY 字段名 新数据类型;
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型;
ALTER TABLE 表名 DROP 字段名;
ALTER TABLE 旧表名 RENAME TO 新表名;
2.3.2.5 删除:
DROP TABLE 表名;
DROP TABLE IF EXISTS 表名; CREATE TABLE 表名 (...);
SMALLINT
代替 INT
)可减少存储空间和提高查询效率。CREATE TABLE users (id INT PRIMARY KEY, username VARCHAR(50) UNIQUE);
)。InnoDB
引擎时,表操作(如 CREATE TABLE
、ALTER TABLE
)可在事务中执行,允许回滚:START TRANSACTION;
CREATE TABLE test (id INT);
ROLLBACK;
SHOW TABLES
替换为 SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';
。DESCRIBE
替换为 sp_help '表名';
。CREATE TABLE
需要 CREATE
权限,ALTER TABLE
需要 ALTER
权限)。DROP TABLE
权限,防止误操作。ALTER TABLE
添加字段或调整类型以适应新需求。SHOW CREATE TABLE
导出表结构,结合 INSERT INTO ... SELECT
迁移数据。CREATE TEMPORARY TABLE
创建临时表,仅在当前会话有效,适合临时数据处理。DML 是用于操作数据库中数据的 SQL 语句,主要包括 插入(INSERT)、更新(UPDATE) 和 删除(DELETE) 操作。与 DDL(数据定义语言,如创建表)不同,DML 专注于数据的增删改,而不涉及表结构或数据库对象的定义。
添加数据使用 INSERT INTO
语句,将新记录插入到表中。以下详细说明三种插入方式:给指定字段添加数据、给全部字段添加数据以及批量添加数据。
说明:仅为表的部分字段插入值,未指定的字段将使用默认值或 NULL
。
SQL 命令:
INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...);
操作步骤:
INSERT INTO
语句。示例:
假设有一个 users
表:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) DEFAULT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
插入一条记录,仅指定 username
和 email
:
INSERT INTO users (username, email) VALUES ('alice', '[email protected]');
执行后表内容:
+----+----------+-------------------+---------------------+
| id | username | email | created_at |
+----+----------+-------------------+---------------------+
| 1 | alice | [email protected] | 2025-04-25 10:00:00 |
+----+----------+-------------------+---------------------+
深入分析:
id
:由于是 AUTO_INCREMENT
,自动生成值为 1
。created_at
:使用默认值 CURRENT_TIMESTAMP
,记录插入时间。VALUES
中的值必须与括号中字段的顺序一致。username
是 NOT NULL
,必须提供值。email
允许 NULL
,可以省略(但示例中提供了值)。注意事项:
NOT NULL
且无默认值的字段)被赋值。VARCHAR
字段需要字符串)。说明:为表的所有字段插入值,字段顺序与表结构定义一致。
SQL 命令:
INSERT INTO 表名 VALUES (值1, 值2, ...);
操作步骤:
DESCRIBE 表名;
查看)。INSERT INTO
语句。示例:
继续使用 users
表,插入一条完整记录:
INSERT INTO users VALUES (NULL, 'bob', '[email protected]', '2025-04-25 11:00:00');
执行后表内容:
+----+----------+-------------------+---------------------+
| id | username | email | created_at |
+----+----------+-------------------+---------------------+
| 1 | alice | [email protected] | 2025-04-25 10:00:00 |
| 2 | bob | [email protected] | 2025-04-25 11:00:00 |
+----+----------+-------------------+---------------------+
深入分析:
id
, username
, email
, created_at
)。id
是 AUTO_INCREMENT
,插入 NULL
或省略(见下文)会自动生成递增的值。INSERT INTO users (username, email, created_at) VALUES ('bob', '[email protected]', '2025-04-25 11:00:00');
注意事项:
VALUES
的写法可能导致错误,建议显式指定字段名。NOT NULL
字段必须有值,否则报错。说明:一次性插入多条记录,提高插入效率。
SQL 命令:
INSERT INTO 表名 (字段1, 字段2, ...) VALUES
(值1_1, 值1_2, ...),
(值2_1, 值2_2, ...),
...;
操作步骤:
INSERT INTO
语句。示例:
向 users
表批量插入三条记录:
INSERT INTO users (username, email) VALUES
('charlie', '[email protected]'),
('dave', '[email protected]'),
('eve', '[email protected]');
执行后表内容:
+----+----------+-------------------+---------------------+
| id | username | email | created_at |
+----+----------+-------------------+---------------------+
| 1 | alice | [email protected] | 2025-04-25 10:00:00 |
| 2 | bob | [email protected] | 2025-04-25 11:00:00 |
| 3 | charlie | [email protected] | 2025-04-25 12:00:00 |
| 4 | dave | [email protected] | 2025-04-25 12:00:00 |
| 5 | eve | [email protected] | 2025-04-25 12:00:00 |
+----+----------+-------------------+---------------------+
深入分析:
InnoDB
引擎中,批量插入可在事务中执行,确保数据一致性:START TRANSACTION;
INSERT INTO users (username, email) VALUES ('frank', '[email protected]'), ('grace', '[email protected]');
COMMIT;
注意事项:
max_allowed_packet
)。高级用法:
INSERT INTO ... SELECT
从另一表复制数据:INSERT INTO users (username, email) SELECT name, email FROM old_users;
说明:使用 UPDATE
语句修改表中已有记录的字段值,通常结合 WHERE
条件指定要更新的记录。
SQL 命令:
UPDATE 表名
SET 字段1 = 新值1, 字段2 = 新值2, ...
[WHERE 条件];
操作步骤:
WHERE
条件筛选需要更新的记录(若省略,将更新所有记录)。UPDATE
语句。示例:
id = 1
的用户的邮箱改为 [email protected]
:UPDATE users
SET email = '[email protected]'
WHERE id = 1;
created_at
早于 2025-04-25 的用户的邮箱后缀改为 @updated.com
:UPDATE users
SET email = CONCAT(SUBSTRING_INDEX(email, '@', 1), '@updated.com')
WHERE created_at < '2025-04-25';
username
转为大写:UPDATE users
SET username = UPPER(username);
执行后表内容(假设执行第一个示例):
+----+----------+---------------------+---------------------+
| id | username | email | created_at |
+----+----------+---------------------+---------------------+
| 1 | alice | [email protected] | 2025-04-25 10:00:00 |
| 2 | bob | [email protected] | 2025-04-25 11:00:00 |
| 3 | charlie | [email protected] | 2025-04-25 12:00:00 |
| 4 | dave | [email protected] | 2025-04-25 12:00:00 |
| 5 | eve | [email protected] | 2025-04-25 12:00:00 |
+----+----------+---------------------+---------------------+
深入分析:
id = 1
)确保只更新目标记录。AND
、OR
)或子查询:UPDATE users
SET email = '[email protected]'
WHERE id IN (SELECT user_id FROM orders WHERE order_date < '2024-01-01');
price = price * 1.1
提高价格 10%)。InnoDB
引擎中,UPDATE
语句可在事务中执行,允许回滚:START TRANSACTION;
UPDATE users SET email = '[email protected]' WHERE id = 1;
ROLLBACK;
注意事项:
WHERE
,所有记录都会被更新,可能导致数据损坏。NOT NULL
、外键、唯一键)。WHERE
条件中的字段添加索引(如 id
上的主键索引)以提高查询效率。说明:使用 DELETE
语句删除表中的记录,通常结合 WHERE
条件指定要删除的记录。
SQL 命令:
DELETE FROM 表名
[WHERE 条件];
操作步骤:
WHERE
条件筛选需要删除的记录(若省略,将删除所有记录)。DELETE
语句。示例:
id = 2
的用户:DELETE FROM users WHERE id = 2;
created_at
早于 2025-04-25 的用户:DELETE FROM users WHERE created_at < '2025-04-25';
DELETE FROM users;
执行后表内容(假设执行第一个示例):
+----+----------+---------------------+---------------------+
| id | username | email | created_at |
+----+----------+---------------------+---------------------+
| 1 | alice | [email protected] | 2025-04-25 10:00:00 |
| 3 | charlie | [email protected] | 2025-04-25 12:00:00 |
| 4 | dave | [email protected] | 2025-04-25 12:00:00 |
| 5 | eve | [email protected] | 2025-04-25 12:00:00 |
+----+----------+---------------------+---------------------+
深入分析:
id = 2
)确保只删除目标记录。DELETE FROM users
WHERE id NOT IN (SELECT user_id FROM orders);
DELETE
:逐行删除记录,支持 WHERE
条件,触发触发器,保留表结构。TRUNCATE
:清空整个表,重置自增计数器,速度更快,但不可回滚:TRUNCATE TABLE users;
InnoDB
引擎中,DELETE
语句可在事务中执行,允许回滚:START TRANSACTION;
DELETE FROM users WHERE id = 3;
ROLLBACK;
注意事项:
WHERE
,将删除表中所有记录,需谨慎。ON DELETE CASCADE
:CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
上述设置会在删除 users
表记录时自动删除对应的 orders
记录。
WHERE
条件中的字段添加索引以提高删除效率。DELETE FROM users WHERE id <= 1000 LIMIT 1000;
2.4.1 添加数据:
INSERT INTO 表名 (字段1, 字段2) VALUES (值1, 值2);
INSERT INTO 表名 VALUES (值1, 值2, ...);
INSERT INTO 表名 (字段1, 字段2) VALUES (值1_1, 值1_2), (值2_1, 值2_2), ...;
2.4.2 修改数据:
UPDATE 表名 SET 字段1 = 新值1, 字段2 = 新值2 WHERE 条件;
2.4.3 删除数据:
DELETE FROM 表名 WHERE 条件;
WHERE
条件的字段(如 id
、created_at
)创建索引,加速 UPDATE
和 DELETE
。START TRANSACTION;
INSERT INTO users (username, email) VALUES ('user1', '[email protected]'), ('user2', '[email protected]');
UPDATE users SET email = '[email protected]' WHERE id > 10;
COMMIT;
INSERT IGNORE
或 ON DUPLICATE KEY UPDATE
:INSERT INTO users (username, email) VALUES ('alice', '[email protected]')
ON DUPLICATE KEY UPDATE email = VALUES(email);
SET FOREIGN_KEY_CHECKS = 0;
DELETE FROM users WHERE id = 1;
SET FOREIGN_KEY_CHECKS = 1;
AUTO_INCREMENT
替换为 SERIAL
,批量插入和 ON DUPLICATE KEY UPDATE
需使用 ON CONFLICT
。ON DUPLICATE KEY UPDATE
,需使用 MERGE
语句实现类似功能。INSERT ALL
语法,UPDATE
和 DELETE
支持更复杂的子查询。INSERT
、UPDATE
、DELETE
)。PREPARE stmt FROM 'INSERT INTO users (username, email) VALUES (?, ?)';
SET @username = 'john', @email = '[email protected]';
EXECUTE stmt USING @username, @email;
UPDATE
和 DELETE
权限,避免误操作。UPDATE
用于批量更新订单状态、用户权限等。DELETE
用于定期清理过期日志或无效记录。CREATE TABLE user_logs (
log_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
action VARCHAR(50),
log_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TRIGGER after_user_insert
AFTER INSERT ON users
FOR EACH ROW
INSERT INTO user_logs (user_id, action) VALUES (NEW.id, 'INSERT');
假设电商系统有以下表结构:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100)
);
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2)
);
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
product_id INT,
quantity INT,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
操作示例:
INSERT INTO users (username, email) VALUES
('alice', '[email protected]'),
('bob', '[email protected]');
INSERT INTO products (name, price) VALUES
('Laptop', 999.99),
('Phone', 499.99);
INSERT INTO orders (user_id, product_id, quantity) VALUES (1, 1, 2);
UPDATE products SET price = price * 1.1 WHERE id = 1;
UPDATE users SET email = '[email protected]' WHERE username = 'alice';
DELETE FROM orders WHERE quantity = 0;
DELETE FROM orders WHERE user_id = 2;
DELETE FROM users WHERE id = 2;
分析:
user_id
、product_id
)在引用表中存在。WHERE
条件,避免影响无关记录。orders
)。DQL 是用于查询数据库中数据的 SQL 语句,主要通过 SELECT
语句实现。DQL 不修改数据,仅返回查询结果,广泛用于数据分析、报表生成和应用程序数据检索。
说明:从表中选择指定的字段返回数据。
SQL 命令:
SELECT 字段1, 字段2, ... FROM 表名;
操作步骤:
SELECT
语句列出字段名,字段间用逗号分隔。示例:
假设有一个 users
表:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100),
created_at DATETIME
);
查询 username
和 email
字段:
SELECT username, email FROM users;
输出示例:
+----------+-------------------+
| username | email |
+----------+-------------------+
| alice | [email protected] |
| bob | [email protected] |
| charlie | [email protected] |
+----------+-------------------+
深入分析:
SELECT
语句决定。SELECT *
查询所有字段,但不推荐用于生产环境(影响性能且不明确)。注意事项:
说明:为查询的字段或表达式指定别名,提高结果可读性或适应应用程序需求。
SQL 命令:
SELECT 字段名 [AS] 别名, 字段名 [AS] 别名, ... FROM 表名;
操作步骤:
SELECT
语句中为字段或表达式添加别名。AS
关键字(可选)。示例:
查询 username
和 email
,分别命名为 user_name
和 email_address
:
SELECT username AS user_name, email AS email_address FROM users;
输出示例:
+-----------+-------------------+
| user_name | email_address |
+-----------+-------------------+
| alice | [email protected] |
| bob | [email protected] |
| charlie | [email protected] |
+-----------+-------------------+
深入分析:
created_at
改为 registration_date
)。SELECT price * 1.1 AS new_price FROM products;
)。SELECT username AS "User Name"
)。注意事项:
ORDER BY
,但不能用于 WHERE
(因执行顺序限制,详见 2.5.9)。说明:使用 DISTINCT
关键字去除查询结果中的重复行。
SQL 命令:
SELECT DISTINCT 字段1, 字段2, ... FROM 表名;
操作步骤:
SELECT
后添加 DISTINCT
关键字。示例:
假设 users
表中有重复的 email
值:
SELECT DISTINCT email FROM users;
输出示例(假设原始数据有重复):
+-------------------+
| email |
+-------------------+
| [email protected] |
| [email protected] |
| [email protected] |
+-------------------+
深入分析:
DISTINCT
基于指定字段的组合去重,检查整行是否相同。SELECT DISTINCT field1, field2
去重基于 (field1, field2)
的唯一组合。DISTINCT
涉及排序或哈希操作,可能降低查询性能。注意事项:
DISTINCT
作用于整个结果集,不能单独应用于某个字段。DISTINCT
,可考虑 GROUP BY
替代。说明:基础查询是 DQL 的核心,使用 SELECT ... FROM
结构检索数据。
SQL 命令:
SELECT [DISTINCT] 字段列表 | *
FROM 表名
[WHERE 条件]
[ORDER BY 字段 [ASC | DESC]];
操作步骤:
*
)。WHERE
条件筛选记录。ORDER BY
排序结果。示例:
查询 users
表中所有字段:
SELECT * FROM users;
说明:通过 WHERE
子句添加条件,筛选符合条件的记录。
常见条件运算符:
=
, !=
或 <>
, >
, <
, >=
, <=
AND
, OR
, NOT
BETWEEN ... AND ...
IN
, NOT IN
LIKE
IS NULL
, IS NOT NULL
示例:
查询 username
为 alice
的用户:
SELECT * FROM users WHERE username = 'alice';
SQL 命令:
SELECT 字段列表
FROM 表名
WHERE 条件;
操作步骤:
WHERE
子句定义筛选条件。详细说明:
price > 100
、created_at = '2025-04-25'
AND
:多条件都满足(如 price > 100 AND stock > 0
)。OR
:任一条件满足(如 username = 'alice' OR username = 'bob'
)。NOT
:取反(如 NOT username = 'alice'
)。price BETWEEN 100 AND 200
)。id IN (1, 2, 3)
)。%
表示任意字符,_
表示单个字符)。username LIKE 'a%'
匹配以 a
开头的用户名。email IS NULL
)。示例:
查询 users
表中 email
不为空且 created_at
在 2025-04-25 之后的用户:
SELECT username, email
FROM users
WHERE email IS NOT NULL AND created_at > '2025-04-25';
场景:电商系统的 products
表:
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2),
stock INT
);
查询需求:
SELECT name, price FROM products WHERE price BETWEEN 100 AND 500;
SELECT name, price, stock FROM products WHERE name LIKE 'Phone%' AND stock > 0;
SELECT * FROM products WHERE id IN (1, 3, 5);
输出示例(假设数据):
+---------+-------+
| name | price |
+---------+-------+
| Phone X | 499.99|
| Phone Y | 399.99|
+---------+-------+
分析:
BETWEEN
和 IN
提高查询可读性。LIKE
适合模糊搜索,但对大数据量性能较低,建议结合索引。说明:聚合函数对一组数据进行计算,返回单个值,常用于统计分析。
特点:
GROUP BY
结合使用。NULL
值(除 COUNT(*)
外)。 函数 |
描述 |
示例 |
|
统计记录数 |
|
|
计算数值列总和 |
|
|
计算数值列平均值 |
|
|
查找最大值 |
|
|
查找最小值 |
|
SQL 命令:
SELECT 聚合函数(字段) [AS 别名], ...
FROM 表名
[WHERE 条件];
操作步骤:
WHERE
筛选数据。场景:orders
表:
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
product_id INT,
quantity INT,
order_date DATE
);
查询需求:
SELECT COUNT(*) AS total_orders FROM orders;
SELECT SUM(quantity) AS total_quantity FROM orders;
SELECT MIN(order_date) AS first_order FROM orders;
输出示例:
+--------------+
| total_orders |
+--------------+
| 100 |
+--------------+
分析:
COUNT(*)
统计所有行,COUNT(column)
仅统计非 NULL
行。注意事项:
SUM
仅用于数值类型)。说明:使用 GROUP BY
将数据按指定字段分组,结合聚合函数统计每组数据。
SQL 命令:
SELECT 字段, 聚合函数(字段)
FROM 表名
[WHERE 条件]
GROUP BY 字段
[HAVING 分组后条件];
操作步骤:
WHERE
筛选原始数据(可选)。GROUP BY
分组。HAVING
筛选分组结果(可选)。GROUP BY
之前执行。GROUP BY
之后执行。示例:
统计每个用户的订单数量,筛选订单数大于 2 的用户:
SELECT user_id, COUNT(*) AS order_count
FROM orders
WHERE order_date >= '2025-01-01'
GROUP BY user_id
HAVING order_count > 2;
输出示例:
+---------+-------------+
| user_id | order_count |
+---------+-------------+
| 1 | 5 |
| 3 | 3 |
+---------+-------------+
场景:统计每个商品的销售总量,筛选销售量大于 10 的商品:
SELECT product_id, SUM(quantity) AS total_sold
FROM orders
GROUP BY product_id
HAVING total_sold > 10;
分析:
GROUP BY product_id
按商品分组。SUM(quantity)
计算每组的总订购量。HAVING
筛选销售量大于 10 的组。注意事项:
SELECT
中的非聚合字段必须出现在 GROUP BY
中(MySQL 宽松模式除外)。说明:使用 ORDER BY
对查询结果按指定字段排序。
SQL 命令:
SELECT 字段列表
FROM 表名
[WHERE 条件]
ORDER BY 字段 [ASC | DESC], 字段 [ASC | DESC], ...;
操作步骤:
ASC
为升序,DESC
为降序)。示例:
按 price
降序查询商品:
SELECT name, price FROM products ORDER BY price DESC;
按 stock
升序、price
降序排序:
SELECT name, price, stock
FROM products
ORDER BY stock ASC, price DESC;
场景:查询商品,按价格降序,库存升序:
SELECT name, price, stock
FROM products
WHERE stock > 0
ORDER BY price DESC, stock ASC;
输出示例:
+---------+--------+-------+
| name | price | stock |
+---------+--------+-------+
| Laptop | 999.99 | 10 |
| Phone X | 499.99 | 5 |
| Phone Y | 399.99 | 8 |
+---------+--------+-------+
分析:
注意事项:
ORDER BY price * 1.1 DESC
)。说明:使用 LIMIT
和 OFFSET
(或等效语法)实现分页查询,限制返回的记录数和起始位置。
SQL 命令(MySQL):
SELECT 字段列表
FROM 表名
[WHERE 条件]
[ORDER BY 字段]
LIMIT 每页记录数 [OFFSET 起始位置];
操作步骤:
LIMIT
)。OFFSET
= (页码 - 1) * 每页记录数)。ORDER BY
确保结果顺序一致。场景:分页显示商品,每页 2 条记录,按价格降序:
SELECT name, price FROM products
ORDER BY price DESC
LIMIT 2 OFFSET 0;
SELECT name, price FROM products
ORDER BY price DESC
LIMIT 2 OFFSET 2;
输出示例(第一页):
+---------+--------+
| name | price |
+---------+--------+
| Laptop | 999.99 |
| Phone X | 499.99 |
+---------+--------+
分析:
OFFSET = (page_number - 1) * page_size
。OFFSET
较大可能导致扫描过多记录,建议使用索引或基于主键分页:SELECT name, price FROM products
WHERE id > last_id
ORDER BY id
LIMIT 2;
注意事项:
ORDER BY
字段有明确顺序,避免分页结果不一致。场景:电商系统,包含 users
、products
和 orders
表:
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100)
);
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
price DECIMAL(10,2),
stock INT
);
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
product_id INT,
quantity INT,
order_date DATE,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
查询需求:
SELECT name, price, stock
FROM products
WHERE price > 500 AND stock > 10
ORDER BY price DESC
LIMIT 3 OFFSET 3;
SELECT user_id, COUNT(*) AS order_count
FROM orders
GROUP BY user_id
HAVING order_count > 3
ORDER BY order_count DESC;
SELECT u.username, p.name, o.quantity
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN products p ON o.product_id = p.id
WHERE o.order_date LIKE '2025-01%';
分析:
price
、stock
、user_id
等字段添加索引以优化性能。说明:SQL 查询的逻辑执行顺序决定了子句的处理顺序,影响查询结果和性能。
执行顺序(MySQL 标准):
JOIN
)。示例解析:
SELECT user_id, COUNT(*) AS order_count
FROM orders
WHERE order_date >= '2025-01-01'
GROUP BY user_id
HAVING order_count > 2
ORDER BY order_count DESC
LIMIT 5;
执行步骤:
orders
表获取数据。WHERE
条件,筛选 order_date >= '2025-01-01'
的记录。user_id
分组。HAVING
,保留 COUNT(*) > 2
的组。SELECT
中的 user_id
和 COUNT(*)
,命名为 order_count
。order_count
降序排序。深入分析:
WHERE
和 HAVING
不能直接使用 SELECT
中的别名(如 order_count
),因为 SELECT
在它们之后执行。WHERE
尽早筛选数据可减少后续处理的数据量。WHERE
、GROUP BY
和 ORDER BY
的字段创建索引。2.5.1 基本语法:
SELECT 字段1, 字段2 FROM 表名;
SELECT 字段 AS 别名 FROM 表名;
SELECT DISTINCT 字段 FROM 表名;
2.5.2 基础查询:
SELECT ... FROM ... [WHERE ...] [ORDER BY ...];
2.5.3 条件查询:
SELECT ... FROM ... WHERE 条件;
2.5.4 聚合函数:
COUNT
, SUM
, AVG
, MAX
, MIN
。SELECT 聚合函数(字段) FROM ...;
2.5.5 分组查询:
SELECT ... GROUP BY ... [HAVING ...];
WHERE
vs HAVING
:WHERE
筛选单行,HAVING
筛选组。2.5.6 排序查询:
SELECT ... ORDER BY 字段 [ASC | DESC];
2.5.7 分页查询:
SELECT ... LIMIT n OFFSET m;
2.5.8 案例:
2.5.9 执行顺序:
WHERE
、GROUP BY
、ORDER BY
和 JOIN
的字段创建索引。LIMIT n OFFSET m
,语法相同,但更强调标准 SQL。TOP n
或 OFFSET-FETCH
:SELECT name, price
FROM products
ORDER BY price DESC
OFFSET 3 ROWS FETCH NEXT 2 ROWS ONLY;
ROWNUM
或 FETCH FIRST
:SELECT name, price
FROM products
ORDER BY price DESC
FETCH FIRST 2 ROWS ONLY;
SELECT
权限,限制用户访问敏感字段。PREPARE stmt FROM 'SELECT * FROM users WHERE username = ?';
SET @username = 'alice';
EXECUTE stmt USING @username;
LIKE
实现模糊搜索。DCL 是用于定义数据库访问权限和安全策略的 SQL 语句,主要包括 GRANT(授予权限)、REVOKE(撤销权限)和用户管理相关的操作(如创建、修改、删除用户)。DCL 确保数据库的安全性,防止未经授权的访问或操作,广泛应用于多用户环境下的权限管理和安全控制。
用户管理涉及创建、查询、修改和删除数据库用户账户,以下详细说明查询用户、修改用户密码和删除用户的操作(创建用户在案例中补充)。
说明:查询数据库系统中所有用户账户或特定用户信息。
SQL 命令(MySQL):
SELECT user, host FROM mysql.user;
操作步骤:
mysql
,其中 mysql.user
表存储用户信息。SELECT
语句查询 user
(用户名)和 host
(允许连接的主机)。示例:
查询所有用户:
SELECT user, host FROM mysql.user;
输出示例:
+------------------+-----------+
| user | host |
+------------------+-----------+
| root | localhost |
| mysql.sys | localhost |
| app_user | % |
| readonly_user | 127.0.0.1 |
+------------------+-----------+
深入分析:
user
:用户名。host
:允许连接的主机(%
表示任意主机,localhost
表示本地连接)。mysql.sys
是 MySQL 内部用户,用于系统功能,不应修改。mysql.user
需要 SELECT
权限,通常只有管理员(如 root
用户)有权执行。SHOW GRANTS FOR CURRENT_USER;
或:
SELECT CURRENT_USER();
注意事项:
mysql.user
可能返回敏感信息,建议限制普通用户访问。app_user@%
和 app_user@localhost
是不同账户)。说明:更改指定用户的密码,用于更新登录凭证或增强安全性。
SQL 命令(MySQL 8.0+):
ALTER USER '用户名'@'主机' IDENTIFIED BY '新密码';
操作步骤:
ALTER USER
语句。示例:
为用户 app_user@%
设置新密码 NewPass123
:
ALTER USER 'app_user'@'%' IDENTIFIED BY 'NewPass123';
深入分析:
validate_password
插件控制,可能要求密码包含大小写字母、数字和特殊字符。SHOW VARIABLES LIKE 'validate_password%';
查看策略。SET PASSWORD FOR 'app_user'@'%' = PASSWORD('NewPass123');
或:
UPDATE mysql.user SET authentication_string = PASSWORD('NewPass123') WHERE user = 'app_user' AND host = '%';
FLUSH PRIVILEGES;
mysql.user
表的 authentication_string
列。ALTER USER
权限或对 mysql.user
表的 UPDATE
权限。注意事项:
ACCOUNT LOCK
),需先解锁:ALTER USER 'app_user'@'%' ACCOUNT UNLOCK;
说明:删除指定的用户账户,移除其所有权限和访问能力。
SQL 命令:
DROP USER '用户名'@'主机';
操作步骤:
DROP USER
语句。IF EXISTS
避免用户不存在时的错误。示例:
删除用户 app_user@%
:
DROP USER 'app_user'@'%';
深入分析:
DROP USER 'user1'@'localhost', 'user2'@'%';
DROP USER
权限,通常由管理员执行。DELETE FROM mysql.user WHERE user = 'app_user' AND host = '%';
FLUSH PRIVILEGES;
注意事项:
KILL (SELECT processlist_id FROM information_schema.processlist WHERE user = 'app_user');
SHOW GRANTS
)。场景:管理一个电商系统数据库的用户。
ecommerce_app@%
:CREATE USER 'ecommerce_app'@'%' IDENTIFIED BY 'AppPass2025';
SELECT user, host, authentication_string FROM mysql.user WHERE user = 'ecommerce_app';
SecurePass2025
:ALTER USER 'ecommerce_app'@'%' IDENTIFIED BY 'SecurePass2025';
test_user@%
:DROP USER IF EXISTS 'test_user'@'%';
输出示例(查询用户):
+--------------+------+-----------------------+
| user | host | authentication_string |
+--------------+------+-----------------------+
| ecommerce_app| % | *encrypted_password* |
+--------------+------+-----------------------+
分析:
%
或 localhost
)。权限控制通过授予和撤销权限管理用户对数据库对象的访问和操作能力。
说明:查看用户拥有的权限或数据库对象的权限配置。
SQL 命令:
SHOW GRANTS FOR '用户名'@'主机';
SHOW GRANTS;
操作步骤:
SHOW GRANTS
语句,返回权限列表。示例:
查看用户 ecommerce_app@%
的权限:
SHOW GRANTS FOR 'ecommerce_app'@'%';
输出示例:
+-------------------------------------------------------------+
| Grants for ecommerce_app@% |
+-------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'ecommerce_app'@'%' |
| GRANT SELECT, INSERT, UPDATE ON `ecommerce`.* TO 'ecommerce_app'@'%' |
+-------------------------------------------------------------+
深入分析:
GRANT USAGE ON *.*
:默认权限,表示用户可以登录但无具体操作权限。GRANT SELECT, INSERT, UPDATE ON
ecommerce.*
:用户对 ecommerce
数据库的所有表有 SELECT
、INSERT
和 UPDATE
权限。*.*
(所有数据库和表)。数据库名.*
(某数据库的所有表)。数据库名.表名
。GRANT SELECT (column_name) ON 表名
)。mysql.user
、mysql.db
、mysql.tables_priv
等表中。SELECT
权限或管理员权限。注意事项:
SHOW GRANTS
显示的是授予的权限,可能不包括通过角色继承的权限(MySQL 8.0+ 支持角色)。说明:使用 GRANT
语句为用户分配特定权限。
SQL 命令:
GRANT 权限列表 ON 数据库.对象 TO '用户名'@'主机' [WITH GRANT OPTION];
操作步骤:
SELECT
、INSERT
、ALL PRIVILEGES
)。*.*
、数据库名.*
、数据库名.表名
)。WITH GRANT OPTION
允许用户将权限授予他人。GRANT
语句。常见权限:
SELECT
:查询数据。INSERT
:插入数据。UPDATE
:更新数据。DELETE
:删除数据。CREATE
:创建数据库或表。DROP
:删除数据库或表。ALL PRIVILEGES
:所有权限(不包括 GRANT OPTION
)。示例:
ecommerce_app@%
对 ecommerce
数据库所有表的 SELECT
和 INSERT
权限:GRANT SELECT, INSERT ON ecommerce.* TO 'ecommerce_app'@'%';
admin_user@localhost
全局所有权限,并允许其授予权限:GRANT ALL PRIVILEGES ON *.* TO 'admin_user'@'localhost' WITH GRANT OPTION;
深入分析:
ecommerce.*
适用于所有表。ecommerce.users
仅适用于指定表。GRANT
语句执行后立即生效,无需 FLUSH PRIVILEGES
(除非直接修改权限表)。注意事项:
*.*
授予过多权限,降低安全风险。说明:使用 REVOKE
语句移除用户的特定权限。
SQL 命令:
REVOKE 权限列表 ON 数据库.对象 FROM '用户名'@'主机';
操作步骤:
REVOKE
语句。示例:
ecommerce_app@%
对 ecommerce
数据库的 INSERT
权限:REVOKE INSERT ON ecommerce.* FROM 'ecommerce_app'@'%';
admin_user@localhost
的全局权限:REVOKE ALL PRIVILEGES ON *.* FROM 'admin_user'@'localhost';
深入分析:
WITH GRANT OPTION
并授予了其他用户权限,撤销其权限会级联影响其他用户。REVOKE GRANT OPTION FOR ...
仅撤销授予权限的能力:REVOKE GRANT OPTION FOR ALL PRIVILEGES ON *.* FROM 'admin_user'@'localhost';
GRANT OPTION
或管理员权限。注意事项:
REVOKE
不会报错。SHOW GRANTS
确认。场景:为电商系统配置用户权限。
readonly_user@%
和应用程序用户 app_user@%
:CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'ReadPass2025';
CREATE USER 'app_user'@'%' IDENTIFIED BY 'AppPass2025';
readonly_user
授予 ecommerce
数据库的 SELECT
权限:GRANT SELECT ON ecommerce.* TO 'readonly_user'@'%';
app_user
授予 ecommerce
数据库的 SELECT
, INSERT
, UPDATE
权限:GRANT SELECT, INSERT, UPDATE ON ecommerce.* TO 'app_user'@'%';
SHOW GRANTS FOR 'readonly_user'@'%';
SHOW GRANTS FOR 'app_user'@'%';
app_user
的 UPDATE
权限:REVOKE UPDATE ON ecommerce.* FROM 'app_user'@'%';
输出示例(查询权限):
+----------------------------------------------------+
| Grants for readonly_user@% |
+----------------------------------------------------+
| GRANT USAGE ON *.* TO 'readonly_user'@'%' |
| GRANT SELECT ON `ecommerce`.* TO 'readonly_user'@'%' |
+----------------------------------------------------+
+-------------------------------------------------------------+
| Grants for app_user@% |
+-------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'app_user'@'%' |
| GRANT SELECT, INSERT ON `ecommerce`.* TO 'app_user'@'%' |
+-------------------------------------------------------------+
分析:
readonly_user
仅能查询,app_user
能执行必要操作。2.6.1 管理用户:
SELECT user, host FROM mysql.user;
ALTER USER '用户名'@'主机' IDENTIFIED BY '新密码';
DROP USER '用户名'@'主机';
2.6.2 权限控制:
SHOW GRANTS FOR '用户名'@'主机';
GRANT 权限列表 ON 数据库.对象 TO '用户名'@'主机';
REVOKE 权限列表 ON 数据库.对象 FROM '用户名'@'主机';
validate_password
插件。ALL PRIVILEGES ON *.*
。localhost
,避免 %
通配符。SELECT user, host, create_time FROM mysql.user;
检查用户创建时间。SHOW GRANTS
审查权限。ALTER USER 'app_user'@'%' REQUIRE SSL;
GRANT
, REVOKE
)通常不影响查询性能,但频繁修改权限表可能导致锁竞争。SELECT rolname FROM pg_roles;
ALTER ROLE 用户名 WITH PASSWORD '新密码';
DROP ROLE 用户名;
GRANT SELECT ON 表名 TO 用户名;
REVOKE SELECT ON 表名 FROM 用户名;
SELECT name FROM sys.database_principals WHERE type = 'S';
ALTER LOGIN 用户名 WITH PASSWORD = '新密码';
DROP USER 用户名;
GRANT SELECT ON 表名 TO 用户名;
REVOKE SELECT ON 表名 FROM 用户名;
SELECT username FROM dba_users;
ALTER USER 用户名 IDENTIFIED BY 新密码;
DROP USER 用户名 CASCADE;
GRANT SELECT ON 表名 TO 用户名;
REVOKE SELECT ON 表名 FROM 用户名;
CREATE ROLE 'read_only_role';
GRANT SELECT ON ecommerce.* TO 'read_only_role';
GRANT 'read_only_role' TO 'readonly_user'@'%';
SET DEFAULT ROLE 'read_only_role' FOR 'readonly_user'@'%';
SHOW GRANTS FOR 'read_only_role';
SELECT
, INSERT
, UPDATE
等权限。SELECT
权限。ALL PRIVILEGES
的用户,限制主机为 localhost
。DELETE
权限清理数据。SET GLOBAL general_log = 'ON';
SELECT user, host, db, command FROM information_schema.processlist;
以下是对 3. 函数 的深刻且详细解释,基于常见的数据库管理系统(以 MySQL 为例),涵盖 字符串函数、数值函数、日期函数 和 流程函数,包括每个函数的定义、语法、演示示例、实际应用场景及案例分析。内容将深入探讨函数的用途、性能影响、注意事项及跨数据库差异,力求全面且清晰。
数据库函数是内置的工具,用于处理和转换数据,常用于查询(DQL)、数据操作(DML)和存储过程等场景。MySQL 提供多种类型的函数,包括字符串函数、数值函数、日期函数和流程函数,以下逐一讲解。
说明:字符串函数用于处理和操作文本数据,如拼接、截取、转换大小写等,常用于数据清洗、格式化输出和条件查询。
常见字符串函数:
函数 |
描述 |
语法示例 |
|
拼接多个字符串 |
|
|
返回字符串的字节长度 |
|
|
返回字符串的字符长度 |
|
|
转换为大写 |
|
|
转换为小写 |
|
|
截取子字符串(从 pos 开始,长度 len) |
|
|
去除首尾空格 |
|
|
返回左侧 len 个字符 |
|
|
返回右侧 len 个字符 |
|
|
替换字符串 |
|
演示如下:
假设有一个 users
表:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100)
);
INSERT INTO users (username, email) VALUES
('Alice', '[email protected]'),
('Bob Smith', '[email protected]'),
('Charlie', '[email protected]');
SELECT CONCAT(username, ' - ', email) AS user_info FROM users;
输出:
+------------------------------+
| user_info |
+------------------------------+
| Alice - [email protected] |
| Bob Smith - [email protected] |
| Charlie - [email protected] |
+------------------------------+
SELECT username, LENGTH(email) AS byte_length, CHAR_LENGTH(email) AS char_length
FROM users;
输出:
+-----------+-------------+-------------+
| username | byte_length | char_length |
+-----------+-------------+-------------+
| Alice | 17 | 17 |
| Bob Smith | 20 | 20 |
| Charlie | 20 | 20 |
+-----------+-------------+-------------+
分析:LENGTH
返回字节长度(UTF-8 字符可能占 1-4 字节),CHAR_LENGTH
返回字符数。
SELECT username, LOWER(email) AS normalized_email FROM users;
输出:
+-----------+----------------------+
| username | normalized_email |
+-----------+----------------------+
| Alice | [email protected] |
| Bob Smith | [email protected] |
| Charlie | [email protected] |
+-----------+----------------------+
SELECT username, SUBSTRING(email, LOCATE('@', email) + 1) AS domain
FROM users;
输出:
+-----------+----------------+
| username | domain |
+-----------+----------------+
| Alice | example.com |
| Bob Smith | example.com |
| Charlie | example.com |
+-----------+----------------+
SELECT TRIM(username) AS trimmed, REPLACE(username, ' ', '_') AS replaced
FROM users;
输出:
+-----------+-------------+
| trimmed | replaced |
+-----------+-------------+
| Alice | Alice |
| Bob Smith | Bob_Smith |
| Charlie | Charlie |
+-----------+-------------+
深入分析:
LENGTH
和 CHAR_LENGTH
在多字节字符(如中文、表情符号)下结果不同,需根据字符集(如 utf8mb4
)选择。SUBSTRING
, REPLACE
)对大数据量可能影响性能,建议结合索引或预处理数据。注意事项:
NULL
返回 NULL
(如 CONCAT(NULL, 'text')
返回 NULL
)。UPPER
, LOWER
)受字符集和排序规则影响。WHERE
中对字段应用复杂字符串函数,可能导致索引失效。说明:数值函数用于处理数字数据,如四舍五入、绝对值、随机数等,常用于计算、统计和数据转换。
常见数值函数:
函数 |
描述 |
语法示例 |
|
返回绝对值 |
|
|
四舍五入到 d 位小数 |
|
|
向上取整 |
|
|
向下取整 |
|
|
取模(余数) |
|
|
生成 0 到 1 的随机数 |
|
|
x 的 y 次幂 |
|
演示如下:
假设有一个 products
表:
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
price DECIMAL(10,2),
stock INT
);
INSERT INTO products (name, price, stock) VALUES
('Laptop', 999.99, 10),
('Phone', 499.50, 25),
('Tablet', -150.75, 5);
SELECT name, ABS(price) AS abs_price FROM products;
输出:
+--------+-----------+
| name | abs_price |
+--------+-----------+
| Laptop | 999.99 |
| Phone | 499.50 |
| Tablet | 150.75 |
+--------+-----------+
SELECT name, ROUND(price, 1) AS rounded_price FROM products;
输出:
+--------+---------------+
| name | rounded_price |
+--------+---------------+
| Laptop | 1000.0 |
| Phone | 499.5 |
| Tablet | -150.8 |
+--------+---------------+
SELECT name, CEIL(stock / 5.0) AS ceil_stock, FLOOR(stock / 5.0) AS floor_stock
FROM products;
输出:
+--------+------------+-------------+
| name | ceil_stock | floor_stock |
+--------+------------+-------------+
| Laptop | 2 | 2 |
| Phone | 5 | 5 |
| Tablet | 1 | 1 |
+--------+------------+-------------+
SELECT name, MOD(id, 2) AS mod_id, RAND() AS random_value
FROM products;
输出(RAND()
结果随机):
+--------+--------+--------------+
| name | mod_id | random_value |
+--------+--------+--------------+
| Laptop | 1 | 0.123456 |
| Phone | 0 | 0.789012 |
| Tablet | 1 | 0.456789 |
+--------+--------+--------------+
SELECT name, price * POWER(0.9, 2) AS discounted_price
FROM products;
输出:
+--------+-----------------+
| name | discounted_price |
+--------+-----------------+
| Laptop | 809.9919 |
| Phone | 404.5950 |
| Tablet | -122.1075 |
+--------+-----------------+
深入分析:
DECIMAL
类型适合金融计算,ROUND
可控制小数位数。RAND()
用于随机排序或抽样,但不适合加密场景。WHERE
条件中对字段应用(如 WHERE ROUND(price) = 100
),可能导致全表扫描。注意事项:
NULL
返回 NULL
。POWER('a', 2)
会报错)。说明:日期函数用于处理日期和时间数据,如提取日期部分、计算时间差、格式化输出等,常用于时间分析和报表。
常见日期函数:
函数 |
描述 |
语法示例 |
|
返回当前日期和时间 |
|
|
返回当前日期 |
|
|
返回当前时间 |
|
|
日期加法 |
|
|
日期减法 |
|
|
计算日期差(天) |
|
|
格式化日期 |
|
|
提取年/月/日 |
|
演示如下:
假设有一个 orders
表:
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
order_date DATETIME
);
INSERT INTO orders (user_id, order_date) VALUES
(1, '2025-04-20 10:00:00'),
(2, '2025-04-22 15:30:00'),
(1, '2025-04-25 09:00:00');
SELECT NOW() AS current_time, CURDATE() AS current_date, CURTIME() AS current_time_only;
输出:
+---------------------+---------------------+------------------+
| current_time | current_date | current_time_only |
+---------------------+---------------------+------------------+
| 2025-04-25 10:00:00 | 2025-04-25 | 10:00:00 |
+---------------------+---------------------+------------------+
SELECT order_date,
DATE_ADD(order_date, INTERVAL 7 DAY) AS due_date,
DATE_SUB(order_date, INTERVAL 1 DAY) AS prev_day
FROM orders;
输出:
+---------------------+---------------------+---------------------+
| order_date | due_date | prev_day |
+---------------------+---------------------+---------------------+
| 2025-04-20 10:00:00 | 2025-04-27 10:00:00 | 2025-04-19 10:00:00 |
| 2025-04-22 15:30:00 | 2025-04-29 15:30:00 | 2025-04-21 15:30:00 |
| 2025-04-25 09:00:00 | 2025-05-02 09:00:00 | 2025-04-24 09:00:00 |
+---------------------+---------------------+---------------------+
SELECT user_id, order_date,
DATEDIFF(NOW(), order_date) AS days_since_order
FROM orders;
输出:
+---------+---------------------+------------------+
| user_id | order_date | days_since_order |
+---------+---------------------+------------------+
| 1 | 2025-04-20 10:00:00 | 5 |
| 2 | 2025-04-22 15:30:00 | 3 |
| 1 | 2025-04-25 09:00:00 | 0 |
+---------+---------------------+------------------+
SELECT order_date,
DATE_FORMAT(order_date, '%Y-%m') AS year_month,
YEAR(order_date) AS order_year,
MONTH(order_date) AS order_month
FROM orders;
输出:
+---------------------+------------+------------+-------------+
| order_date | year_month | order_year | order_month |
+---------------------+------------+------------+-------------+
| 2025-04-20 10:00:00 | 2025-04 | 2025 | 4 |
| 2025-04-22 15:30:00 | 2025-04 | 2025 | 4 |
| 2025-04-25 09:00:00 | 2025-04 | 2025 | 4 |
+---------------------+------------+------------+-------------+
深入 analysis:
DATETIME
和 TIMESTAMP
类型的字段支持日期函数,TIMESTAMP
受时区影响。DATE_FORMAT
支持多种格式(如 %Y
表示四位年,%m
表示两位月)。WHERE
条件中可能导致索引失效(如 WHERE YEAR(order_date) = 2025
),建议改为范围查询(如 WHERE order_date >= '2025-01-01' AND order_date < '2026-01-01'
)。注意事项:
NULL
返回 NULL
。DATE
, DATETIME
或 TIMESTAMP
。SET time_zone = '+8:00';
)可能影响 NOW()
等函数。说明:流程函数(或控制流函数)用于条件判断和逻辑控制,返回不同值基于输入条件,常用于动态查询和数据转换。
常见流程函数:
函数 |
描述 |
语法示例 |
|
如果 expr 为真,返回 true_value,否则返回 false_value |
|
|
如果 expr 为 NULL,返回 default_value |
|
|
如果 expr1 = expr2,返回 NULL,否则返回 expr1 |
|
|
多条件分支判断 |
|
演示如下:
使用 products
和 users
表。
SELECT name, stock, IF(stock > 0, 'In Stock', 'Out of Stock') AS stock_status
FROM products;
输出:
+--------+-------+----------------+
| name | stock | stock_status |
+--------+-------+----------------+
| Laptop | 10 | In Stock |
| Phone | 25 | In Stock |
| Tablet | 5 | In Stock |
+--------+-------+----------------+
SELECT username, IFNULL(email, 'No Email') AS email_status
FROM users;
输出:
+-----------+----------------------+
| username | email_status |
+-----------+----------------------+
| Alice | [email protected] |
| Bob Smith | [email protected] |
| Charlie | [email protected] |
+-----------+----------------------+
SELECT name, price, NULLIF(price, -150.75) AS adjusted_price
FROM products;
输出:
+--------+---------+----------------+
| name | price | adjusted_price |
+--------+---------+----------------+
| Laptop | 999.99 | 999.99 |
| Phone | 499.50 | 499.50 |
| Tablet | -150.75 | NULL |
+--------+---------+----------------+
SELECT name, price,
CASE
WHEN price > 500 THEN 'Expensive'
WHEN price > 100 THEN 'Moderate'
ELSE 'Cheap'
END AS price_category
FROM products;
输出:
+--------+---------+----------------+
| name | price | price_category |
+--------+---------+----------------+
| Laptop | 999.99 | Expensive |
| Phone | 499.50 | Moderate |
| Tablet | -150.75 | Cheap |
+--------+---------+----------------+
深入分析:
CASE
支持多条件分支,适合复杂逻辑;IF
更简单,适合二元判断。IFNULL
和 NULLIF
是处理空值的利器,常用于数据清洗。SELECT
中高效,但在 WHERE
中可能影响优化,建议简化条件。注意事项:
NULL
的处理需明确(如 IF(NULL, 1, 0)
返回 0)。CASE
或 IF
,可能降低可读性和性能。场景:电商系统,包含 users
、products
和 orders
表:
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100)
);
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
price DECIMAL(10,2),
stock INT
);
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
product_id INT,
order_date DATETIME,
quantity INT
);
INSERT INTO users VALUES
(1, 'Alice', '[email protected]'),
(2, 'Bob', NULL);
INSERT INTO products VALUES
(1, 'Laptop', 999.99, 10),
(2, 'Phone', 499.50, 0),
(3, 'Tablet', 299.99, 5);
INSERT INTO orders VALUES
(1, 1, 1, '2025-04-20 10:00:00', 2),
(2, 1, 2, '2025-04-22 15:30:00', 1),
(3, 2, 3, '2025-04-25 09:00:00', 3);
案例需求:
SELECT
CONCAT(UPPER(LEFT(username, 1)), LOWER(SUBSTRING(username, 2))) AS formatted_name,
SUBSTRING(email,abel
SUBSTRING(email, LOCATE('@', email) + 1) AS email_domain
FROM users;
输出:
+----------------+--------------+
| formatted_name | email_domain |
+----------------+--------------+
| Alice | example.com |
| Bob | NULL |
+----------------+--------------+
分析:格式化用户名首字母大写,提取邮箱域名,处理空值。
SELECT name,
ROUND(price * 0.9, 2) AS discounted_price,
IF(stock > 0, CEIL(stock / 5.0), 0) AS stock_batches
FROM products;
输出:
+--------+--------------------+---------------+
| name | discounted_price | stock_batches |
+--------+--------------------+---------------+
| Laptop | 899.99 | 2 |
| Phone | 449.55 | 0 |
| Tablet | 269.99 | 1 |
+--------+--------------------+---------------+
分析:应用折扣并按批次分组库存,便于库存管理。
SELECT
user_id,
order_date,
DATE_FORMAT(order_date, '%Y-%m-%d %H:%i') AS formatted_date,
DATEDIFF(NOW(), order_date) AS days_since_order
FROM orders;
输出:
+---------+---------------------+------------------+------------------+
| user_id | order_date | formatted_date | days_since_order |
+---------+---------------------+------------------+------------------+
| 1 | 2025-04-20 10:00:00 | 2025-04-20 10:00 | 5 |
| 1 | 2025-04-22 15:30:00 | 2025-04-22 15:30 | 3 |
| 2 | 2025-04-25 09:00:00 | 2025-04-25 09:00 | 0 |
+---------+---------------------+------------------+------------------+
分析:格式化日期并计算时间差,用于订单跟踪。
SELECT
o.id,
u.username,
p.name,
CASE
WHEN o.quantity > 5 THEN 'Large Order'
WHEN o.quantity > 1 THEN 'Medium Order'
ELSE 'Small Order'
END AS order_size,
IFNULL(u.email, 'No Email') AS email_status
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN products p ON o.product_id = p.id;
输出:
+----+----------+--------+-------------+--------------+
| id | username | name | order_size | email_status |
+----+----------+--------+-------------+--------------+
| 1 | Alice | Laptop | Medium Order| [email protected] |
| 2 | Alice | Phone | Small Order | [email protected] |
| 3 | Bob | Tablet | Medium Order| No Email |
+----+----------+--------+-------------+--------------+
分析:分类订单规模,处理空邮箱,提升报表可读性。
3.1 字符串函数:
CONCAT
, LENGTH
, UPPER
, SUBSTRING
, TRIM
, etc.3.2 数值函数:
ABS
, ROUND
, CEIL
, MOD
, RAND
, etc.3.3 日期函数:
NOW
, DATE_ADD
, DATEDIFF
, DATE_FORMAT
, etc.3.4 流程函数:
IF
, IFNULL
, NULLIF
, CASE
.案例:
WHERE
或 JOIN
中对字段应用函数(如 WHERE UPPER(username) = 'ALICE'
),会导致索引失效。ALTER TABLE users ADD normalized_email VARCHAR(100) GENERATED ALWAYS AS (LOWER(email)) STORED;
||
代替 CONCAT
,LENGTH
类似。ROUND
, ABS
相同,RANDOM()
代替 RAND()
。NOW()
, AGE()
代替 DATEDIFF
。COALESCE
代替 IFNULL
,CASE
相同。+
拼接,LEN
代替 CHAR_LENGTH
。ROUND
, ABS
类似,RAND()
相同。GETDATE()
代替 NOW()
, DATEDIFF
类似。ISNULL
代替 IFNULL
, CASE
相同。||
拼接,SUBSTR
代替 SUBSTRING
。ROUND
, ABS
类似,DBMS_RANDOM.VALUE
代替 RAND()
。SYSDATE
代替 NOW()
, MONTHS_BETWEEN
代替 DATEDIFF
。NVL
代替 IFNULL
, CASE
相同。PREPARE stmt FROM 'SELECT * FROM users WHERE username = ?';
SET @username = 'Alice';
EXECUTE stmt USING @username;
TRIM
, REPLACE
, IFNULL
清理用户输入。DATE_FORMAT
, ROUND
, CASE
格式化统计数据。IF
, CASE
根据条件生成不同输出。RAND()
实现数据采样或 A/B 测试。DELIMITER //
CREATE FUNCTION format_price(price DECIMAL(10,2)) RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
RETURN CONCAT('$', ROUND(price, 2));
END //
DELIMITER ;
SELECT name, format_price(price) FROM products;
SELECT name, price,
RANK() OVER (ORDER BY price DESC) AS price_rank
FROM products;
定义:约束(Constraints)是数据库用来确保数据完整性和一致性的规则,应用于表中的列或表本身。约束在数据插入、更新或删除时自动检查,防止不符合规则的操作,确保数据库中的数据符合业务逻辑和数据模型的要求。
作用:
常见约束类型:
约束类型 |
描述 |
示例 |
|
字段不允许为空 |
|
|
字段值必须唯一(允许 NULL) |
|
|
唯一标识每行,结合 |
|
|
确保字段值引用主表的主键或唯一键 |
|
|
限制字段值满足特定条件 |
|
|
为字段设置默认值 |
|
深入分析:
注意事项:
以下通过示例演示各种约束的定义和效果。
示例表结构:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY, -- 主键约束
username VARCHAR(50) NOT NULL, -- 非空约束
email VARCHAR(100) UNIQUE, -- 唯一约束
age INT CHECK (age >= 18), -- 检查约束(MySQL 8.0+)
created_at DATETIME DEFAULT CURRENT_TIMESTAMP -- 默认值约束
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
amount DECIMAL(10,2) DEFAULT 0.00,
order_date DATE NOT NULL
) ENGINE=InnoDB;
演示:
username
:INSERT INTO users (email, age) VALUES ('[email protected]', 20);
结果:报错 ERROR 1364: Field 'username' doesn't have a default value
。
email
:INSERT INTO users (username, email, age) VALUES ('Alice', '[email protected]', 20);
INSERT INTO users (username, email, age) VALUES ('Bob', '[email protected]', 25);
结果:第二次插入报错 ERROR 1062: Duplicate entry '[email protected]' for key 'email'
。
id
:INSERT INTO users (id, username, email, age) VALUES (1, 'Alice', '[email protected]', 20);
INSERT INTO users (id, username, email, age) VALUES (1, 'Bob', '[email protected]', 25);
结果:报错 ERROR 1062: Duplicate entry '1' for key 'PRIMARY'
。
INSERT INTO users (username, email, age) VALUES ('Charlie', '[email protected]', 16);
结果:报错 ERROR 3819: Check constraint 'users_chk_1' is violated
(MySQL 8.0+)。
created_at
:INSERT INTO users (username, email, age) VALUES ('Alice', '[email protected]', 20);
SELECT username, created_at FROM users;
输出:
+----------+---------------------+
| username | created_at |
+----------+---------------------+
| Alice | 2025-04-25 10:00:00 |
+----------+---------------------+
深入分析:
NOT NULL
和 UNIQUE
的结合,适合唯一标识记录。CHECK
,需在应用层验证。InnoDB
引擎,MyISAM
不支持。注意事项:
定义:外键约束(Foreign Key Constraint)用于建立和强化两个表之间的参照关系,确保子表中的外键值必须存在于主表的主键或唯一键中,或者为 NULL
(如果允许)。外键约束维护 参照完整性,防止无效数据破坏表间关系。
作用:
ON DELETE CASCADE
)。特点:
PRIMARY KEY
或 UNIQUE
约束。InnoDB
引擎(MySQL 中 MyISAM
不支持)。准备数据:
创建 users
和 orders
表,orders
表中的 user_id
引用 users
表的 id
:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
amount DECIMAL(10,2),
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;
INSERT INTO users (username) VALUES ('Alice'), ('Bob');
INSERT INTO orders (user_id, amount) VALUES (1, 199.99), (2, 299.99);
测试:
INSERT INTO orders (user_id, amount) VALUES (3, 99.99);
结果:报错 ERROR 1452: Cannot add or update a child row: a foreign key constraint fails
。
DELETE FROM users WHERE id = 1;
结果:报错 ERROR 1451: Cannot delete or update a parent row: a foreign key constraint fails
,因为 orders
表中存在引用 user_id = 1
的记录。
深入分析:
orders.user_id
的值始终在 users.id
中存在。注意事项:
NOT NULL
,除非业务允许空值。InnoDB
)。说明:在创建表或修改表时添加外键约束。
SQL 命令:
CREATE TABLE 表名 (
字段定义,
[CONSTRAINT 外键名] FOREIGN KEY (外键字段) REFERENCES 主表(主表字段)
[ON DELETE 行为] [ON UPDATE 行为]
);
ALTER TABLE 表名
ADD [CONSTRAINT 外键名] FOREIGN KEY (外键字段) REFERENCES 主表(主表字段)
[ON DELETE 行为] [ON UPDATE 行为];
案例:
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
amount DECIMAL(10,2),
CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;
orders
表未定义外键,添加外键:ALTER TABLE orders
ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id);
深入分析:
fk_user
),便于后续管理;否则 MySQL 自动生成(如 orders_ibfk_1
)。ERROR 1452: Cannot add or update a child row: a foreign key constraint fails
InnoDB
引擎中生效。注意事项:
PRIMARY KEY
或 UNIQUE
约束。说明:移除表中的外键约束,保留字段但不再检查参照完整性。
SQL 命令:
ALTER TABLE 表名 DROP FOREIGN KEY 外键名;
案例:
删除 orders
表中的外键 fk_user
:
ALTER TABLE orders DROP FOREIGN KEY fk_user;
步骤:
SHOW CREATE TABLE orders;
或:
SELECT CONSTRAINT_NAME
FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_NAME = 'orders' AND CONSTRAINT_TYPE = 'FOREIGN KEY';
DROP FOREIGN KEY
语句。深入分析:
user_id
仍保留为普通字段,但不再检查是否引用 users.id
。注意事项:
说明:外键约束支持定义主表记录删除或更新时子表的处理行为,通过 ON DELETE
和 ON UPDATE
子句指定。这些行为确保表间关系在操作时保持一致。
常见行为:
行为 |
描述 |
应用场景 |
|
阻止主表记录的删除/更新(默认) |
严格保护数据一致性 |
|
主表记录删除/更新时,子表记录同步删除/更新 |
自动清理或同步数据 |
|
主表记录删除/更新时,子表外键字段设为 NULL |
解除关系但保留记录 |
|
类似 |
事务场景 |
|
主表记录删除/更新时,子表外键设为默认值 |
自定义默认值(MySQL 不支持) |
演示如下:
重新创建表,定义不同外键行为:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
amount DECIMAL(10,2),
CONSTRAINT fk_user_cascade FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
CREATE TABLE reviews (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
comment TEXT,
CONSTRAINT fk_user_set_null FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE SET NULL ON UPDATE SET NULL
) ENGINE=InnoDB;
INSERT INTO users (username) VALUES ('Alice'), ('Bob');
INSERT INTO orders (user_id, amount) VALUES (1, 199.99), (2, 299.99);
INSERT INTO reviews (user_id, comment) VALUES (1, 'Great product'), (2, 'Fast delivery');
users
表中的用户:DELETE FROM users WHERE id = 1;
SELECT * FROM orders;
输出:
+----+---------+--------+
| id | user_id | amount |
+----+---------+--------+
| 2 | 2 | 299.99 |
+----+---------+--------+
分析:用户 id = 1
删除后,orders
表中对应的记录(user_id = 1
)也被删除。
users
表中的 id
:UPDATE users SET id = 10 WHERE id = 2;
SELECT * FROM orders;
输出:
+----+---------+--------+
| id | user_id | amount |
+----+---------+--------+
| 2 | 10 | 299.99 |
+----+---------+--------+
分析:主表 id
从 2 更新为 10,orders
表中的 user_id
同步更新为 10。
users
表中的用户:DELETE FROM users WHERE id = 10;
SELECT * FROM reviews;
输出:
+----+---------+---------------+
| id | user_id | comment |
+----+---------+---------------+
| 1 | NULL | Great product |
| 2 | NULL | Fast delivery |
+----+---------+---------------+
分析:用户 id = 10
删除后,reviews
表中的 user_id
设为 NULL
。
RESTRICT
:CREATE TABLE payments (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
amount DECIMAL(10,2),
CONSTRAINT fk_user_restrict FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE RESTRICT
) ENGINE=InnoDB;
INSERT INTO payments (user_id, amount) VALUES (1, 50.00);
DELETE FROM users WHERE id = 1;
结果:报错 ERROR 1451: Cannot delete or update a parent row: a foreign key constraint fails
。
深入分析:
NULL
。CASCADE
和 SET NULL
增加触发操作开销。RESTRICT
仅需检查约束,性能较优。START TRANSACTION;
DELETE FROM orders WHERE user_id = 1;
DELETE FROM users WHERE id = 1;
COMMIT;
注意事项:
SET NULL
需确认子表记录仍有效)。ALTER TABLE orders DROP FOREIGN KEY fk_user_cascade;
ALTER TABLE orders ADD CONSTRAINT fk_user_cascade FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;
4.1 概述:
NOT NULL
, UNIQUE
, PRIMARY KEY
, FOREIGN KEY
, CHECK
, DEFAULT
。4.2 约束演示:
NOT NULL
, UNIQUE
, PRIMARY KEY
, CHECK
, DEFAULT
的定义和效果。4.3 外键约束:
ALTER TABLE
添加,案例展示命名和添加流程。DROP FOREIGN KEY
,案例展示查询和删除。CASCADE
, SET NULL
, RESTRICT
的效果。CREATE INDEX idx_user_id ON orders(user_id);
SET FOREIGN_KEY_CHECKS = 0;
-- 批量操作
SET FOREIGN_KEY_CHECKS = 1;
CHECK
更强大,支持复杂表达式。CASCADE
, SET NULL
, RESTRICT
, NO ACTION
, SET DEFAULT
。ALTER TABLE orders ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id);
ALTER TABLE orders DROP CONSTRAINT fk_user;
DEFERRABLE
选项,允许延迟检查:CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE orders DROP CONSTRAINT fk_user;
ALTER TABLE
权限,限制非管理员操作。ERROR 1452
),提供用户友好提示。SELECT o.user_id
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE u.id IS NULL;
ON DELETE CASCADE
清理无效订单。RESTRICT
防止误删账户记录,保护交易完整性。SET NULL
允许删除用户但保留匿名评论。CREATE TABLE order_details (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id),
FOREIGN KEY (order_id, product_id) REFERENCES order_products(order_id, product_id)
);
CREATE TRIGGER check_user_id
BEFORE INSERT ON orders
FOR EACH ROW
BEGIN
IF NOT EXISTS (SELECT 1 FROM users WHERE id = NEW.user_id) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Invalid user_id';
END IF;
END;
SELECT * FROM orders WHERE user_id NOT IN (SELECT id FROM users);
SET GLOBAL log_error_suppression_list = '1451,1452';
多表查询是指从多个表中检索数据的操作,通常通过表之间的关系(如外键)将数据关联起来。MySQL 支持多种多表查询方式,包括连接查询(内连接、外连接、自连接)和子查询,适用于复杂的数据分析和业务逻辑实现。
多表关系定义了表之间的逻辑关联,决定了如何通过键字段连接数据。常见的多表关系包括 一对多、多对多 和 一对一。
说明:一个主表记录对应子表中的多个记录,通常通过外键实现。
示例:
users
表)可以有多个订单(orders
表)。CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50)
);
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
amount DECIMAL(10,2),
FOREIGN KEY (user_id) REFERENCES users(id)
);
users.id
(主表主键)与 orders.user_id
(子表外键)形成一对多关系。特点:
orders.user_id
存在于 users.id
中。深入分析:
orders.user_id
)。ON DELETE CASCADE
自动删除子表记录。说明:多个主表记录与多个子表记录相关联,通过中间表(关联表)实现。
示例:
students
表)可以选修多门课程(courses
表),每门课程可被多个学生选修。CREATE TABLE students (
id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE courses (
id INT PRIMARY KEY,
title VARCHAR(100)
);
CREATE TABLE student_courses (
student_id INT,
course_id INT,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(id),
FOREIGN KEY (course_id) REFERENCES courses(id)
);
student_courses
表通过 student_id
和 course_id
关联 students
和 courses
。特点:
深入分析:
说明:一个主表记录对应一个子表记录,通常用于拆分表结构或扩展信息。
示例:
users
表)与用户详细信息(user_details
表)一对一。CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50)
);
CREATE TABLE user_details (
user_id INT PRIMARY KEY,
phone VARCHAR(20),
FOREIGN KEY (user_id) REFERENCES users(id)
);
user_details.user_id
是主键且为外键,引用 users.id
。特点:
深入分析:
注意事项:
InnoDB
支持外键)。为后续演示准备数据,创建 users
、orders
和 products
表,模拟电商系统的一对多关系:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL
) ENGINE=InnoDB;
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2)
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
product_id INT,
quantity INT,
order_date DATE,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
) ENGINE=InnoDB;
INSERT INTO users (username) VALUES ('Alice'), ('Bob'), ('Charlie');
INSERT INTO products (name, price) VALUES ('Laptop', 999.99), ('Phone', 499.99), ('Tablet', 299.99);
INSERT INTO orders (user_id, product_id, quantity, order_date) VALUES
(1, 1, 2, '2025-04-20'),
(1, 2, 1, '2025-04-22'),
(2, 3, 3, '2025-04-25'),
(NULL, 1, 1, '2025-04-26');
数据说明:
users
:3 个用户。products
:3 个商品。orders
:4 个订单,包含一个无用户(user_id = NULL
)的订单。定义:多表查询通过关联多个表检索数据,通常基于表间的关系(如外键)或条件组合结果。MySQL 支持多种多表查询方式,包括连接查询和子查询。
作用:
挑战:
多表查询主要分为以下两类:
NULL
。深入分析:
内连接(Inner Join)返回两个表中满足连接条件的记录,排除不匹配的行。
说明:通过 WHERE
子句指定连接条件,不显式使用 JOIN
关键字。
SQL 命令:
SELECT 字段列表
FROM 表1, 表2
WHERE 表1.字段 = 表2.字段;
示例:
查询用户和其订单信息:
SELECT u.username, o.id AS order_id, o.quantity
FROM users u, orders o
WHERE u.id = o.user_id;
输出:
+----------+----------+----------+
| username | order_id | quantity |
+----------+----------+----------+
| Alice | 1 | 2 |
| Alice | 2 | 1 |
| Bob | 3 | 3 |
+----------+----------+----------+
分析:
users.id = orders.user_id
的匹配记录。Charlie
(无订单)和 orders.user_id = NULL
的记录被排除。说明:使用 INNER JOIN
关键字明确指定连接条件,可读性更高。
SQL 命令:
SELECT 字段列表
FROM 表1 INNER JOIN 表2
ON 表1.字段 = 表2.字段;
示例三表连接:
查询用户、订单和商品信息:
SELECT u.username, p.name AS product_name, o.quantity
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN products p ON o.product_id = p.id;
输出:
+----------+--------------+----------+
| username | product_name | quantity |
+----------+--------------+----------+
| Alice | Laptop | 2 |
| Alice | Phone | 1 |
| Bob | Tablet | 3 |
+----------+--------------+----------+
案例:
统计每个用户的订单总金额:
SELECT u.username, SUM(o.quantity * p.price) AS total_amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN products p ON o.product_id = p.id
GROUP BY u.id, u.username;
输出:
+----------+--------------+
| username | total_amount |
+----------+--------------+
| Alice | 1499.97 |
| Bob | 899.97 |
+----------+--------------+
深入分析:
user_id
, product_id
)创建索引可加速查询。注意事项:
u
, o
),提高可读性和避免歧义。外连接(Outer Join)返回主表的所有记录,辅表匹配记录填充数据,未匹配的填充 NULL
。
说明:返回左表所有记录,右表匹配记录,未匹配的右表字段为 NULL
。
SQL 命令:
SELECT 字段列表
FROM 表1 LEFT OUTER JOIN 表2
ON 表1.字段 = 表2.字段;
示例:
查询所有用户及其订单(包括无订单用户):
SELECT u.username, o.id AS order_id, o.quantity
FROM users u
LEFT OUTER JOIN orders o ON u.id = o.user_id;
输出:
+----------+----------+----------+
| username | order_id | quantity |
+----------+----------+----------+
| Alice | 1 | 2 |
| Alice | 2 | 1 |
| Bob | 3 | 3 |
| Charlie | NULL | NULL |
+----------+----------+----------+
说明:返回右表所有记录,左表匹配记录,未匹配的左表字段为 NULL
。
SQL 命令:
SELECT 字段列表
FROM 表1 RIGHT OUTER JOIN 表2
ON 表1.字段 = 表2.字段;
示例:
查询所有订单及其用户信息(包括无用户订单):
SELECT u.username, o.id AS order_id, o.quantity
FROM users u
RIGHT OUTER JOIN orders o ON u.id = o.user_id;
输出:
+----------+----------+----------+
| username | order_id | quantity |
+----------+----------+----------+
| Alice | 1 | 2 |
| Alice | 2 | 1 |
| Bob | 3 | 3 |
| NULL | 4 | 1 |
+----------+----------+----------+
案例:
查找未下单的用户:
SELECT u.username
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
输出:
+----------+
| username |
+----------+
| Charlie |
+----------+
深入分析:
注意事项:
NULL
值时,使用 IS NULL
或 COALESCE
。FULL OUTER JOIN
),需通过 UNION
实现。说明:自连接是同一表与自身连接,通常用于层次结构或比较同一表中的记录。
SQL 命令:
SELECT 字段列表
FROM 表 AS 别名1
INNER JOIN 表 AS 别名2
ON 别名1.字段 = 别名2.字段;
案例:
假设 employees
表存储员工和其上级信息:
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50),
manager_id INT
);
INSERT INTO employees (id, name, manager_id) VALUES
(1, 'Alice', NULL),
(2, 'Bob', 1),
(3, 'Charlie', 1),
(4, 'Dave', 2);
SELECT e1.name AS employee, e2.name AS manager
FROM employees e1
LEFT JOIN employees e2 ON e1.manager_id = e2.id;
输出:
+----------+---------+
| employee | manager |
+----------+---------+
| Alice | NULL |
| Bob | Alice |
| Charlie | Alice |
| Dave | Bob |
+----------+---------+
分析:
manager_id = NULL
)也显示。说明:联合查询(UNION
)合并多个查询结果,去除重复记录(UNION ALL
保留重复)。
SQL 命令:
SELECT 字段列表 FROM 表1 WHERE 条件1
UNION [ALL]
SELECT 字段列表 FROM 表2 WHERE 条件2;
案例:
合并用户和产品名称:
SELECT username AS name FROM users
UNION
SELECT name FROM products;
输出:
+----------+
| name |
+----------+
| Alice |
| Bob |
| Charlie |
| Laptop |
| Phone |
| Tablet |
+----------+
分析:
UNION
自动去重,UNION ALL
性能更高(不排序)。深入分析:
e1
, e2
)。UNION ALL
更高效。注意事项:
UNION
列名以第一个查询为准。定义:子查询是嵌套在主查询中的查询,返回结果供主查询使用。子查询通常出现在 WHERE
, FROM
或 SELECT
中,用于分步处理复杂逻辑。
特点:
类型 |
描述 |
返回结果 |
示例 |
标量子查询 |
返回单一值(一行一列) |
单值 |
|
列子查询 |
返回一列值 |
单列 |
|
行子查询 |
返回一行记录 |
单行多列 |
|
表子查询 |
返回结果集 |
多行多列 |
|
说明:返回单一值,常用于比较或赋值。
案例:
查找订单金额高于平均金额的订单:
SELECT id, amount
FROM orders
WHERE amount > (SELECT AVG(amount) FROM orders);
输出(假设平均金额为 224.99):
+----+--------+
| id | amount |
+----+--------+
| 2 | 299.99 |
+----+--------+
分析:
(SELECT AVG(amount) FROM orders)
返回单一值。说明:返回一列值,常与 IN
, NOT IN
使用。
案例:
查找有订单的用户的用户名:
SELECT username
FROM users
WHERE id IN (SELECT user_id FROM orders WHERE user_id IS NOT NULL);
输出:
+----------+
| username |
+----------+
| Alice |
| Bob |
+----------+
分析:
orders.user_id
列表。users.id
在该列表中的记录。说明:返回一行多列,常用于多字段比较。
案例:
查找价格最高且库存最低的商品:
SELECT name, price, stock
FROM products
WHERE (price, stock) = (SELECT MAX(price), MIN(stock) FROM products);
输出(假设数据符合):
+--------+--------+-------+
| name | price | stock |
+--------+--------+-------+
| Laptop | 999.99 | 0 |
+--------+--------+-------+
分析:
(最大价格, 最小库存)
。说明:返回结果集,作为临时表供主查询使用。
案例:
统计订单数大于 1 的用户:
SELECT t.username, t.order_count
FROM (
SELECT u.username, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username
) t
WHERE t.order_count > 1;
输出:
+----------+-------------+
| username | order_count |
+----------+-------------+
| Alice | 2 |
+----------+-------------+
分析:
深入分析:
SELECT u.username, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username
HAVING order_count > 1;
注意事项:
场景:电商系统,分析用户、订单和商品数据。
需求:
实现:
SELECT u.username, p.name AS product_name, o.quantity, o.quantity * p.price AS total_price
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN products p ON o.product_id = p.id;
输出:
+----------+--------------+----------+-------------+
| username | product_name | quantity | total_price |
+----------+--------------+----------+-------------+
| Alice | Laptop | 2 | 1999.98 |
| Alice | Phone | 1 | 499.99 |
| Bob | Tablet | 3 | 899.97 |
+----------+--------------+----------+-------------+
SELECT u.username
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
输出:
+----------+
| username |
+----------+
| Charlie |
+----------+
SELECT p.name, COALESCE(SUM(o.quantity), 0) AS total_sold
FROM products p
LEFT JOIN orders o ON p.id = o.product_id
GROUP BY p.id, p.name;
输出:
+--------+------------+
| name | total_sold |
+--------+------------+
| Laptop | 3 |
| Phone | 1 |
| Tablet | 3 |
+--------+------------+
SELECT o.id, u.username, o.quantity * p.price AS total_price
FROM orders o
INNER JOIN users u ON o.user_id = u.id
INNER JOIN products p ON o.product_id = p.id
WHERE o.quantity * p.price > (SELECT AVG(quantity * price) FROM orders o2 JOIN products p2 ON o2.product_id = p2.id);
输出:
+----+----------+-------------+
| id | username | total_price |
+----+----------+-------------+
| 1 | Alice | 1999.98 |
+----+----------+-------------+
分析:
COALESCE
处理 NULL
值,增强结果可靠性。orders.user_id
, orders.product_id
)和避免复杂子查询。5.1 多表关系:
5.2 多表查询概述:
users
, orders
, products
表。5.3 内连接:
FROM 表1, 表2 WHERE 条件
。INNER JOIN ... ON ...
。5.4 外连接:
5.5 自连接:
5.6 子查询:
5.7 多表查询案例:
user_id
, product_id
)和 WHERE
条件字段创建索引:CREATE INDEX idx_user_id ON orders(user_id);
CREATE INDEX idx_product_id ON orders(product_id);
EXPLAIN
分析查询性能:EXPLAIN SELECT u.username, o.id FROM users u INNER JOIN orders o ON u.id = o.user_id;
-- 子查询
SELECT username FROM users WHERE id IN (SELECT user_id FROM orders);
-- 连接查询
SELECT DISTINCT u.username FROM users u INNER JOIN orders o ON u.id = o.user_id;
LATERAL
提高灵活性:SELECT u.username, o.*
FROM users u
LEFT JOIN LATERAL (SELECT * FROM orders WHERE user_id = u.id LIMIT 1) o ON true;
FULL OUTER JOIN
。TOP
替代 LIMIT
。CROSS APPLY
类似 LATERAL
。(+)
表示外连接:SELECT u.username, o.id FROM users u, orders o WHERE u.id = o.user_id(+);
JOIN
语法。WITH
(CTE)提高可读性:WITH order_counts AS (
SELECT user_id, COUNT(*) AS order_count
FROM orders
GROUP BY user_id
)
SELECT u.username, oc.order_count
FROM users u
LEFT JOIN order_counts oc ON u.id = oc.user_id;
PREPARE stmt FROM 'SELECT u.username FROM users u INNER JOIN orders o ON u.id = o.user_id WHERE u.username = ?';
SET @username = 'Alice';
EXECUTE stmt USING @username;
SELECT
权限,防止未授权访问:GRANT SELECT ON users TO 'app_user'@'%';
GRANT SELECT ON orders TO 'app_user'@'%';
WITH user_orders AS (
SELECT u.id, u.username, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username
)
SELECT username, order_count
FROM user_orders
WHERE order_count > 1;
SELECT u.username, p.name, o.quantity,
RANK() OVER (PARTITION BY u.id ORDER BY o.quantity * p.price DESC) AS price_rank
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN products p ON o.product_id = p.id;
WITH RECURSIVE emp_hierarchy AS (
SELECT id, name, manager_id, 1 AS level
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.id, e.name, e.manager_id, h.level + 1
FROM employees e
INNER JOIN emp_hierarchy h ON e.manager_id = h.id
)
SELECT name, level FROM emp_hierarchy;
SET GLOBAL slow_query_log = 'ON';
SELECT * FROM information_schema.STATISTICS WHERE TABLE_NAME IN ('users', 'orders');
定义:事务(Transaction)是一组数据库操作(通常是 DML 语句,如 INSERT
、UPDATE
、DELETE
),这些操作作为一个整体执行,要么全部成功提交(commit),要么全部失败回滚(rollback),确保数据库状态的一致性和完整性。
作用:
基本概念:
START TRANSACTION
或第一条 DML 语句(在自动提交关闭时)启动。COMMIT
):将操作永久保存到数据库。ROLLBACK
):撤销所有操作,恢复到事务开始前的状态。适用场景:
深入分析:
InnoDB
支持事务(通过日志和锁机制),而 MyISAM
不支持。redo log
和 undo log
)和锁管理的开销,需权衡性能与一致性。READ COMMITTED
, REPEATABLE READ
)影响并发性能和数据可见性。注意事项:
为演示事务操作,创建以下表结构,模拟电商系统的用户余额和订单场景:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
balance DECIMAL(10,2) NOT NULL DEFAULT 0.00
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
amount DECIMAL(10,2) NOT NULL,
order_date DATE NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;
INSERT INTO users (username, balance) VALUES
('Alice', 1000.00),
('Bob', 500.00);
数据说明:
users
:存储用户及其余额。orders
:存储订单信息,user_id
引用 users.id
。说明:未控制事务指未显式使用 START TRANSACTION
、COMMIT
或 ROLLBACK
,操作受数据库的自动提交模式(autocommit
)控制。默认情况下,MySQL 的 InnoDB
引擎启用 autocommit = 1
,每条 DML 语句自动提交。
场景:Alice 下单,扣除余额并记录订单。
SQL 操作:
-- 检查初始余额
SELECT username, balance FROM users WHERE username = 'Alice';
-- 扣除余额
UPDATE users SET balance = balance - 200.00 WHERE username = 'Alice';
-- 插入订单
INSERT INTO orders (user_id, amount, order_date)
VALUES (1, 200.00, '2025-04-25');
-- 检查结果
SELECT username, balance FROM users WHERE username = 'Alice';
SELECT id, user_id, amount FROM orders;
输出:
+----------+---------+
| username | balance |
+----------+---------+
| Alice | 1000.00 |
+----------+---------+
+----------+---------+
| username | balance |
+----------+---------+
| Alice | 800.00 |
+----------+---------+
+----+---------+--------+
| id | user_id | amount |
+----+---------+--------+
| 1 | 1 | 200.00 |
+----+---------+--------+
分析:
场景:Alice 下单,余额不足导致插入订单失败。
SQL 操作:
-- 检查初始余额
SELECT username, balance FROM users WHERE username = 'Alice';
-- 扣除余额(假设余额足够)
UPDATE users SET balance = balance - 1000.00 WHERE username = 'Alice';
-- 插入订单(外键约束失败,user_id 不存在)
INSERT INTO orders (user_id, amount, order_date)
VALUES (999, 1000.00, '2025-04-25');
-- 检查结果
SELECT username, balance FROM users WHERE username = 'Alice';
SELECT id, user_id, amount FROM orders;
输出:
+----------+---------+
| username | balance |
+----------+---------+
| Alice | 800.00 |
+----------+---------+
+----------+---------+
| username | balance |
+----------+---------+
| Alice | -200.00 |
+----------+---------+
+----+---------+--------+
| id | user_id | amount |
+----+---------+--------+
| 1 | 1 | 200.00 |
+----+---------+--------+
ERROR 1452: Cannot add or update a child row: a foreign key constraint fails
.分析:
深入分析:
START TRANSACTION
, COMMIT
, ROLLBACK
)控制操作。注意事项:
autocommit
状态:SELECT @@autocommit;
说明:通过设置事务提交方式(autocommit
)控制事务行为,显式使用 COMMIT
和 ROLLBACK
管理事务。
SQL 命令:
autocommit
:SELECT @@autocommit;
SET autocommit = 0;
SET autocommit = 1;
示例:
-- 查看当前设置
SELECT @@autocommit;
-- 禁用自动提交
SET autocommit = 0;
输出:
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
分析:
autocommit = 0
时,每条 DML 语句不立即提交,需显式 COMMIT
或 ROLLBACK
。SQL 命令:
COMMIT;
示例:Alice 下单,扣除余额并记录订单:
SET autocommit = 0;
-- 扣除余额
UPDATE users SET balance = balance - 200.00 WHERE username = 'Alice';
-- 插入订单
INSERT INTO orders (user_id, amount, order_date)
VALUES (1, 200.00, '2025-04-25');
-- 提交事务
COMMIT;
-- 检查结果
SELECT username, balance FROM users WHERE username = 'Alice';
SELECT id, user_id, amount FROM orders WHERE user_id = 1;
输出:
+----------+---------+
| username | balance |
+----------+---------+
| Alice | 600.00 |
+----------+---------+
+----+---------+--------+
| id | user_id | amount |
+----+---------+--------+
| 1 | 1 | 200.00 |
| 2 | 1 | 200.00 |
+----+---------+--------+
分析:
COMMIT
后永久保存。SQL 命令:
ROLLBACK;
示例:Alice 下单,余额不足导致失败:
SET autocommit = 0;
-- 检查初始余额
SELECT username, balance FROM users WHERE username = 'Alice';
-- 扣除余额
UPDATE users SET balance = balance - 1000.00 WHERE username = 'Alice';
-- 插入订单(外键失败)
INSERT INTO orders (user_id, amount, order_date)
VALUES (999, 1000.00, '2025-04-25');
-- 回滚事务
ROLLBACK;
-- 检查结果
SELECT username, balance FROM users WHERE username = 'Alice';
输出:
+----------+---------+
| username | balance |
+----------+---------+
| Alice | 600.00 |
+----------+---------+
+----------+---------+
| username | balance |
+----------+---------+
| Alice | 600.00 |
+----------+---------+
ERROR 1452: Cannot add or update a child row
.分析:
ROLLBACK
撤销所有操作,余额恢复。深入分析:
COMMIT
将 redo log
写入磁盘,确保持久化。ROLLBACK
使用 undo log
恢复数据。autocommit
增加事务管理开销,但确保一致性。COMMIT
或 ROLLBACK
。注意事项:
autocommit
后,需显式提交或回滚,否则可能导致资源锁定。SELECT @@in_transaction;
说明:使用显式事务语句(START TRANSACTION
)控制事务,适合明确事务边界的场景。
SQL 命令:
START TRANSACTION;
示例:
START TRANSACTION;
-- 检查余额
SELECT username, balance FROM users WHERE username = 'Bob';
分析:
START TRANSACTION
显式开始事务,禁用自动提交。示例:Bob 下单,扣除余额并记录订单:
START TRANSACTION;
UPDATE users SET balance = balance - 300.00 WHERE username = 'Bob';
INSERT INTO orders (user_id, amount, order_date)
VALUES (2, 300.00, '2025-04-25');
COMMIT;
-- 检查结果
SELECT username, balance FROM users WHERE username = 'Bob';
SELECT id, user_id, amount FROM orders WHERE user_id = 2;
输出:
+----------+---------+
| username | balance |
+----------+---------+
| Bob | 200.00 |
+----------+---------+
+----+---------+--------+
| id | user_id | amount |
+----+---------+--------+
| 3 | 2 | 300.00 |
+----+---------+--------+
分析:
COMMIT
使操作持久化。示例:Bob 下单,余额不足:
START TRANSACTION;
UPDATE users SET balance = balance - 500.00 WHERE username = 'Bob';
-- 模拟余额不足检查
SELECT balance FROM users WHERE username = 'Bob';
-- 回滚事务
ROLLBACK;
-- 检查结果
SELECT username, balance FROM users WHERE username = 'Bob';
输出:
+---------+
| balance |
+---------+
| -300.00 |
+---------+
+----------+---------+
| username | balance |
+----------+---------+
| Bob | 200.00 |
+----------+---------+
分析:
深入分析:
START TRANSACTION
清晰定义事务边界,适合复杂逻辑。START TRANSACTION;
UPDATE users SET balance = balance - 100.00 WHERE username = 'Bob';
SAVEPOINT savepoint1;
UPDATE users SET balance = balance - 200.00 WHERE username = 'Bob';
ROLLBACK TO savepoint1;
COMMIT;
SHOW ENGINE INNODB STATUS;
注意事项:
COMMIT
或 ROLLBACK
),否则可能导致连接挂起。SET TRANSACTION
设置隔离级别:SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
事务的四大特性(ACID)是数据库事务的核心原则,确保数据操作的可靠性和一致性。
undo log
记录操作前状态,回滚时恢复。user_id
必须存在于 users
表。REPEATABLE READ
):redo log
记录提交操作,崩溃后恢复。深入分析:
InnoDB
使用 undo log
回滚未提交操作。redo log
和双写缓冲(doublewrite buffer)确保数据写入磁盘。SERIALIZABLE
)增加锁开销,降低并发性能。ERROR 1213: Deadlock found when trying to get lock; try restarting transaction
注意事项:
SELECT @@transaction_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SHOW VARIABLES LIKE 'innodb_log_file_size';
6.1 事务简介:
6.2 事务操作:
users
和 orders
表,模拟电商场景。autocommit = 0
,显式 COMMIT
或 ROLLBACK
。START TRANSACTION
显式控制事务。6.3 事务四大特性:
START TRANSACTION;
UPDATE users SET balance = balance - 100.00 WHERE id = 1;
COMMIT;
START TRANSACTION;
INSERT INTO orders (user_id, amount) VALUES (1, 100.00);
COMMIT;
START TRANSACTION;
INSERT INTO orders (user_id, amount) VALUES (1, 200.00);
COMMIT;
users.id
, orders.user_id
)创建索引。innodb_log_file_size
提高日志性能。READ COMMITTED
,支持 SERIALIZABLE
。SAVEPOINT my_savepoint;
RELEASE SAVEPOINT my_savepoint;
EXCEPTION
块。READ COMMITTED
。BEGIN TRANSACTION
:BEGIN TRANSACTION;
UPDATE users SET balance = balance - 100.00 WHERE id = 1;
COMMIT TRANSACTION;
SELECT @@TRANCOUNT;
COMMIT
,回滚使用 ROLLBACK
。SET CONSTRAINTS DEFERRED
延迟约束检查。GRANT UPDATE, INSERT ON users TO 'app_user'@'%';
ERROR 1205: Lock wait timeout exceeded; try restarting transaction
SET GLOBAL general_log = 'ON';
START TRANSACTION;
UPDATE accounts SET balance = balance - 100.00 WHERE id = 1;
UPDATE accounts SET balance = balance + 100.00 WHERE id = 2;
COMMIT;
START TRANSACTION;
UPDATE products SET stock = stock - 1 WHERE id = 1;
INSERT INTO orders (user_id, product_id, quantity) VALUES (1, 1, 1);
UPDATE users SET balance = balance - 100.00 WHERE id = 1;
COMMIT;
START TRANSACTION;
INSERT INTO new_table SELECT * FROM old_table;
COMMIT;
XA START 'xid';
UPDATE users SET balance = balance - 100.00 WHERE id = 1;
XA END 'xid';
XA PREPARE 'xid';
XA COMMIT 'xid';
START TRANSACTION;
INSERT INTO users (username, balance) VALUES ('Charlie', 300.00);
SAVEPOINT savepoint1;
UPDATE users SET balance = balance - 200.00 WHERE username = 'Charlie';
ROLLBACK TO savepoint1;
COMMIT;
SELECT * FROM information_schema.INNODB_TRX;
SELECT * FROM information_schema.INNODB_LOCKS;
innodb_deadlock_detect
自动处理死锁:SHOW VARIABLES LIKE 'innodb_deadlock_detect';
SET SESSION innodb_lock_wait_timeout = 50;
SHOW STATUS LIKE 'Innodb_log%';
以下是对 MySQL 存储引擎 InnoDB 的深刻且详细介绍,涵盖其定义、特性、实现机制、优势、局限性、应用场景、性能优化、与其他存储引擎的对比,以及在实际使用中的注意事项。内容基于 MySQL 的上下文(以最新版本如 8.0+ 为例),力求全面、清晰,并结合实际案例和深入分析。
相信仔细阅读上面内容的朋友可以发现,一些语句之后为什么加上InnoDB,下面简单补充一下相关知识,我也将在sql文章下部详细介绍它。
定义:InnoDB 是 MySQL 的默认存储引擎(自 MySQL 5.5.5 起),是一个支持事务、行级锁、外键约束和高并发的高性能存储引擎,适用于需要数据一致性和可靠性的应用。InnoDB 通过 ENGINE=InnoDB
语句在创建表时指定。
核心目标:
语法示例:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL
) ENGINE=InnoDB;
InnoDB 提供了丰富的特性,使其成为 MySQL 中最常用的存储引擎。以下是其主要特性及其详细说明:
COMMIT
),要么全部失败(ROLLBACK
),符合 ACID 特性(原子性、一致性、隔离性、持久性)。START TRANSACTION;
UPDATE users SET balance = balance - 100 WHERE id = 1;
INSERT INTO orders (user_id, amount) VALUES (1, 100);
COMMIT;
SELECT ... FOR SHARE
)。UPDATE
, DELETE
)。START TRANSACTION;
UPDATE users SET balance = balance - 100 WHERE id = 1; -- 锁定 id=1 的行
COMMIT;
DB_TRX_ID
, DB_ROLL_PTR
)。undo log
),写操作创建新版本。REPEATABLE READ
,避免脏读和不可重复读。READ COMMITTED
, READ UNCOMMITTED
, SERIALIZABLE
。SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT balance FROM users WHERE id = 1; -- 读取快照
COMMIT;
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;
ON DELETE CASCADE
, ON UPDATE SET NULL
等。SHOW ENGINE INNODB STATUS;
会显示恢复过程。
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50)
) ENGINE=InnoDB;
id
是聚集索引,数据按 id
排序存储。
ROW_FORMAT=COMPRESSED
或 KEY_BLOCK_SIZE
配置。CREATE TABLE logs (
id INT PRIMARY KEY,
message TEXT
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
CREATE TABLE articles (
id INT PRIMARY KEY,
content TEXT,
FULLTEXT (content)
) ENGINE=InnoDB;
SELECT * FROM articles WHERE MATCH(content) AGAINST('keyword');
ibdata1
)或独立表空间(.ibd
文件)。innodb_file_per_table = 1
)便于管理:SHOW VARIABLES LIKE 'innodb_file_per_table';
ib_logfile0
, ib_logfile1
等文件中。innodb_log_file_size
, innodb_log_files_in_group
。SELECT ... FOR UPDATE
)。REPEATABLE READ
级别)。ALTER TABLE
)触发。SHOW ENGINE INNODB STATUS;
DB_TRX_ID
, DB_ROLL_PTR
),跟踪事务版本。SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
innodb_buffer_pool_size
(建议占服务器内存 60-80%)。SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
特性 |
InnoDB |
MyISAM |
Memory |
Archive |
事务支持 |
是 |
否 |
否 |
否 |
锁粒度 |
行级锁 |
表级锁 |
表级锁 |
表级锁 |
外键 |
是 |
否 |
否 |
否 |
全文索引 |
是(5.6+) |
是 |
否 |
否 |
崩溃恢复 |
是 |
否 |
否 |
否 |
存储方式 |
表空间(.ibd) |
文件(.MYD, .MYI) |
内存 |
压缩文件 |
适用场景 |
高并发、事务 |
只读、简单插入 |
临时表 |
归档数据 |
对比分析:
innodb_buffer_pool_size
(如 4GB 服务器设为 2-3GB):SET GLOBAL innodb_buffer_pool_size = 2147483648; -- 2GB
SHOW STATUS LIKE 'Innodb_buffer_pool%';
innodb_log_file_size
(如 512MB)以减少日志切换:SET GLOBAL innodb_log_file_size = 536870912;
innodb_flush_log_at_trx_commit
:1
(默认):每次提交写入磁盘,最高可靠性。0
或 2
:延迟写入,提高性能但降低持久性。CREATE INDEX idx_user_id ON orders(user_id);
SELECT * FROM information_schema.STATISTICS WHERE TABLE_NAME = 'users';
START TRANSACTION;
UPDATE users SET balance = balance - 100 WHERE id = 1;
COMMIT;
READ COMMITTED
降低锁冲突)。innodb_file_per_table = 1
):SET GLOBAL innodb_file_per_table = 1;
OPTIMIZE TABLE users;
innodb_thread_concurrency
(如 0 表示无限制):SET GLOBAL innodb_thread_concurrency = 0;
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
START TRANSACTION;
INSERT INTO orders (user_id, amount) VALUES (1, 200);
UPDATE users SET balance = balance - 200 WHERE id = 1;
COMMIT;
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50),
department_id INT,
FOREIGN KEY (department_id) REFERENCES departments(id)
) ENGINE=InnoDB;
CREATE TABLE logs (
id INT PRIMARY KEY,
message TEXT,
FULLTEXT (message)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
SHOW TABLE STATUS WHERE Name = 'users';
ALTER TABLE users ENGINE=InnoDB;
SET FOREIGN_KEY_CHECKS = 0;
-- 操作
SET FOREIGN_KEY_CHECKS = 1;
SHOW ENGINE INNODB STATUS;
START TRANSACTION;
-- 操作
COMMIT;
mysqldump
或 xtrabackup
备份 InnoDB 表:mysqldump -u root -p --single-transaction database_name > backup.sql
innodb_force_recovery
配置正确以恢复损坏表。SHOW GLOBAL STATUS LIKE 'Innodb%';
SELECT * FROM information_schema.INNODB_TRX;
DEFERRABLE
)。对比分析:
案例:电商订单处理
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50),
balance DECIMAL(10,2)
) ENGINE=InnoDB;
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
stock INT
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
product_id INT,
amount DECIMAL(10,2),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
) ENGINE=InnoDB;
INSERT INTO users VALUES (1, 'Alice', 1000.00);
INSERT INTO products VALUES (1, 'Laptop', 10);
START TRANSACTION;
UPDATE users SET balance = balance - 200.00 WHERE id = 1;
UPDATE products SET stock = stock - 1 WHERE id = 1;
INSERT INTO orders (user_id, product_id, amount) VALUES (1, 1, 200.00);
COMMIT;
优化:
user_id
和 product_id
创建索引:CREATE INDEX idx_user_id ON orders(user_id);
CREATE INDEX idx_product_id ON orders(product_id);
SET GLOBAL innodb_buffer_pool_size = 4294967296; -- 4GB
InnoDB 核心特性:
优势:
局限性:
应用场景:
优化建议:
注意事项: