以下对 MySQL 中 DDL(数据定义语言)核心语法 进行 超详细拆解,从基础逻辑到实际场景、细节注意事项全涵盖,帮你彻底吃透数据库 / 表结构操作 👇
一、基础 - SQL-DDL - 数据库操作
核心目标:管理 "数据库" 这个大容器,决定要操作哪些库、怎么创建 / 删除库。
1. 创建数据库(CREATE DATABASE
)
sql
CREATE DATABASE [IF NOT EXISTS] 数据库名
[CHARACTER SET 字符集]
[COLLATE 排序规则];
IF NOT EXISTS
:- 作用:避免 "数据库已存在" 时报
ERROR 1007 (HY000): Can't create database 'mydb'; database exists
错误。 - 场景:脚本初始化环境时,不确定库是否存在,加它更安全。
- 作用:避免 "数据库已存在" 时报
CHARACTER SET
:- 常见值:
utf8
(老旧,仅支持 Basic Multilingual Plane 字符,缺 emoji 等)、utf8mb4
(完整 Unicode,必选!存 emoji、特殊符号)、gbk
(国内项目历史场景)。 - 影响:数据库里所有表、字段默认继承该字符集,若表 / 字段没单独指定,就用库的设置。
- 常见值:
COLLATE
:- 作用:决定字符串比较规则(如大小写是否敏感、排序规则)。
- 搭配示例:
utf8mb4_general_ci
(不区分大小写,排序快)、utf8mb4_unicode_ci
(更符合 Unicode 标准,排序稍慢)、utf8mb4_bin
(区分大小写,按二进制值比较)。
完整示例(创建支持 emoji 的博客数据库):
sql
CREATE DATABASE IF NOT EXISTS blog_db
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
2. 删除数据库(DROP DATABASE
)
sql
DROP DATABASE [IF EXISTS] 数据库名;
- 危险点 :删库会把库里所有表、数据 永久删除,无法恢复!生产环境必须谨慎,最好先备份。
IF EXISTS
:避免 "删不存在的库" 报错,脚本化操作常用。
示例(清理测试库):
sql
DROP DATABASE IF EXISTS test_db;
3. 切换数据库(USE
)
操作表前必须指定 "当前在哪 个库",否则 SQL 不知道表属于哪个库:
sql
USE 数据库名;
示例(进入博客库操作表):
sql
USE blog_db;
-- 之后执行 CREATE TABLE、SELECT 等,默认操作 blog_db 里的表
4. 查看数据库(SHOW DATABASES
)
-
查看服务器上 所有数据库 (需对应权限,普通用户可能看不到系统库):
sqlSHOW DATABASES;
-
想精准筛选?结合
LIKE
(MySQL 特有的模糊匹配):SHOW DATABASES LIKE 'blog%'; -- 找以 blog 开头的库
二、基础 - SQL-DDL - 表操作 - 创建 & 查询
核心目标:设计表结构(字段、类型、约束),并查看表的元数据(结构、创建语句等)。
1. 创建表(CREATE TABLE
)
语法骨架(超详细版):
sql
CREATE TABLE [IF NOT EXISTS] 表名 (
字段1 数据类型 [字段约束] [COMMENT '字段说明'],
字段2 数据类型 [字段约束] [COMMENT '字段说明'],
...
[CONSTRAINT 约束名] 表级约束(如 PRIMARY KEY、FOREIGN KEY),
[COMMENT '表说明']
)
[ENGINE=存储引擎]
[CHARACTER SET 字符集]
[COLLATE 排序规则]
[ROW_FORMAT=行格式];
逐部分拆解:
-
IF NOT EXISTS
:避免重复建表报错,脚本初始化必备。 -
字段定义 :
- 数据类型 :前面 "数据类型" 部分会详细讲,比如
INT
(整数)、VARCHAR
(字符串)等。 - 字段约束 :
NOT NULL
:字段值 必须填 ,不能为NULL
(比如用户手机号、用户名)。UNIQUE
:字段值 全局唯一(比如用户邮箱,全表不能重复)。DEFAULT
:默认值(比如create_time
设为当前时间DEFAULT CURRENT_TIMESTAMP
)。COMMENT
:给字段加说明(方便维护,比如COMMENT '用户真实姓名'
)。
- 数据类型 :前面 "数据类型" 部分会详细讲,比如
-
表级约束 :
-
主键(
PRIMARY KEY
) :-
作用:唯一标识一行数据,不允许重复、不允许
NULL
,常用INT
配合AUTO_INCREMENT
(自增)。 -
写法:可以字段级(
id INT PRIMARY KEY
),也可表级(适合多字段联合主键):sql
sqlCONSTRAINT pk_user PRIMARY KEY (id, username); -- 多字段主键(示例,实际少用)
-
-
外键(
FOREIGN KEY
) :- 作用:关联另一张表的主键,实现 "父子表" 关系(比如订单表
order
关联用户表user
的id
)。 - 写法(表级约束):
ON DELETE CASCADE
:父表(user
)删数据,子表(order
)关联数据 自动级联删除。ON UPDATE CASCADE
:父表主键更新,子表外键 自动级联更新(需谨慎,可能影响性能)。
- 作用:关联另一张表的主键,实现 "父子表" 关系(比如订单表
-
唯一约束(
UNIQUE
) :-
表级写法(适合多字段联合唯一,比如 "用户名 + 邮箱" 组合唯一): sql
CONSTRAINT uk_user UNIQUE (username, email);
-
-
-
存储引擎(
ENGINE
) :InnoDB
:MySQL 5.5+ 后默认,支持 事务 (BEGIN
/COMMIT
/ROLLBACK
)、外键 、行级锁(高并发写入友好),适合业务表(订单、用户)。MyISAM
:不支持事务、外键,但 查询性能高 、支持 全文索引,适合日志表、纯查询表(比如新闻文章表)。MEMORY
:数据存内存,速度极快但重启数据库会丢失,适合临时表、缓存数据。
-
ROW_FORMAT
:- 控制行存储方式,
InnoDB
常用DYNAMIC
(变长字段更高效)、COMPRESSED
(压缩存储,节省空间但稍影响写入)。
- 控制行存储方式,
完整示例(创建带外键的 "用户 - 文章" 表):
sql
USE blog_db; -- 先切到 blog_db 库
CREATE TABLE IF NOT EXISTS user (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID,自增',
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名,唯一',
email VARCHAR(100) NOT NULL UNIQUE COMMENT '用户邮箱',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间',
COMMENT '用户信息表'
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS article (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '文章ID,自增',
title VARCHAR(200) NOT NULL COMMENT '文章标题',
content TEXT COMMENT '文章内容',
author_id INT NOT NULL COMMENT '关联的用户ID',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间',
COMMENT '文章表',
-- 表级外键约束
CONSTRAINT fk_article_user
FOREIGN KEY (author_id)
REFERENCES user(id)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
2. 查询表信息
-
查看库内所有表(
SHOW TABLES
):USE blog_db; SHOW TABLES; -- 列出 blog_db 里的所有表(user、article 等)
-
查看表结构(
DESC
/SHOW COLUMNS
):DESC 表名; -- 或等价写法 SHOW COLUMNS FROM 表名;
输出解析 (以
user
表为例):Field Type Null Key Default Extra id int NO PRI NULL auto_increment username varchar(50) NO UNI NULL email varchar(100) NO UNI NULL create_time datetime YES CURRENT_TIMESTAMP Field
:字段名Type
:数据类型Null
:是否允许NULL
值Key
:索引类型(PRI
主键、UNI
唯一键、MUL
普通索引)Default
:默认值Extra
:额外属性(如auto_increment
自增)
-
查看建表语句(
SHOW CREATE TABLE
):SHOW CREATE TABLE 表名;
作用:
- 看完整的
CREATE TABLE
语句(包括引擎、字符集、约束细节),方便复制、迁移表结构。 - 排查问题(比如引擎是不是
InnoDB
、字符集是否正确)。
- 看完整的
三、基础 - SQL-DDL - 数据类型及案例
核心目标 :选对数据类型,既节省存储空间,又避免业务 bug(比如用 VARCHAR
存手机号,结果长度不够)。
MySQL 数据类型分 数值、字符串、日期时间、特殊类型 四大类,逐个拆解:
1. 数值类型
类型 | 字节 | 范围(有符号) | 场景示例 |
---|---|---|---|
TINYINT |
1 | -128 ~ 127(或 0 ~ 255 无符号) | 性别(0-1)、是否删除(0-1) |
SMALLINT |
2 | -32768 ~ 32767 | 商品库存(小范围数量) |
INT /INTEGER |
4 | -2147483648 ~ 2147483647 | 用户 ID、订单 ID(常用) |
BIGINT |
8 | -9223372036854775808 ~ 9223372036854775807 | 超大数值(比如雪花算法 ID) |
FLOAT |
4 | 单精度浮点(约 ±3.4e-38 ~ ±3.4e+38) | 科学计算、非精准小数(如统计值) |
DOUBLE |
8 | 双精度浮点(约 ±1.7e-308 ~ ±1.7e+308) | 同上,但精度更高 |
DECIMAL(M,D) |
可变 | 精准小数(M 总位数,D 小数位) |
金额(如 DECIMAL(10,2) 存 12345678.90) |
重点注意:
DECIMAL
vsFLOAT/DOUBLE
:- 金融、电商场景(金额计算)必须用
DECIMAL
,因为FLOAT/DOUBLE
存的是 近似值 (比如0.1
用二进制存会有精度丢失,累加可能出错)。 FLOAT/DOUBLE
适合科学计算、对精度要求不高的场景(比如网站访问量统计)。
- 金融、电商场景(金额计算)必须用
案例(订单表金额字段):
sql
CREATE TABLE order (
id INT PRIMARY KEY AUTO_INCREMENT,
amount DECIMAL(10,2) NOT NULL COMMENT '订单金额,精准到分',
quantity INT NOT NULL COMMENT '商品数量',
total DOUBLE COMMENT '临时统计值(非精准,仅展示)'
);
2. 字符串类型
类型 | 特点 | 场景示例 |
---|---|---|
CHAR(n) |
定长,最多 255 字符,不足补空格 | 手机号(11 位固定)、性别(1 位) |
VARCHAR(n) |
变长,最多 65535 字符(实际受行大小限制) | 用户名、文章标题、地址 |
TEXT |
长文本,最多 65535 字符 | 文章内容、用户备注 |
LONGTEXT |
超长文本,最多 4294967295 字符 | 系统日志、大段富文本 |
BLOB |
存二进制数据(图片、文件) | 头像文件(但实际更推荐存 OSS,数据库存路径) |
关键对比 CHAR
vs VARCHAR
:
CHAR
:查询快(因为长度固定,MySQL 可直接定位),但费空间(比如存'abc'
,CHAR(10)
会存成'abc '
补 7 个空格)。适合 短、固定长度 的值(手机号、性别)。VARCHAR
:省空间(存'abc'
就是 3 个字符 + 1 个长度前缀),但查询稍慢(需要解析长度)。适合 变长、长度不固定 的值(用户名、文章标题)。
案例(用户表字段选型):
sql
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
mobile CHAR(11) NOT NULL COMMENT '手机号,固定11位',
username VARCHAR(50) NOT NULL COMMENT '用户名,变长',
avatar VARCHAR(255) COMMENT '头像OSS路径',
bio TEXT COMMENT '个人简介(可能很长)'
);
3. 日期时间类型
类型 | 字节 | 范围 | 场景示例 |
---|---|---|---|
DATE |
3 | 1000-01-01 ~ 9999-12-31 | 生日、订单日期(只存日期) |
TIME |
3 | -838:59:59 ~ 838:59:59 | 上班时长(如 08:30:00 ) |
DATETIME |
8 | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 | 订单创建时间(需精确到秒) |
TIMESTAMP |
4 | 1970-01-01 00:00:01 ~ 2038-01-19 03:14:07 | 记录更新时间(关联时区) |
YEAR |
1 | 1901 ~ 2155(或 0000) | 年份(用得少,一般用 DATE 存 YYYY ) |
关键对比 DATETIME
vs TIMESTAMP
:
DATETIME
:- 范围大(到 9999 年),不关联时区,存啥显示啥。
- 适合 业务时间不涉及时区 的场景(比如国内电商,所有时间按北京时间存)。
TIMESTAMP
:- 范围小(到 2038 年,需注意!),但会 自动转换时区(存的时候转 UTC,查的时候转当前会话时区)。
- 适合 多时区业务(比如海外 APP,用户在纽约、北京看时间自动适配)。
- 常用
DEFAULT CURRENT_TIMESTAMP
记录 "创建时间",ON UPDATE CURRENT_TIMESTAMP
记录 "更新时间":
sql
**案例**(时间字段综合应用):
```sql
CREATE TABLE article (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
publish_date DATE NOT NULL COMMENT '发布日期(仅年月日)',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(精确到秒,北京时间)',
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间(随时区变化)',
duration TIME COMMENT '阅读时长(如 00:10:30 表示10分30秒)'
);
四、基础 - SQL-DDL - 表操作 - 修改 & 删除(深度版)
核心目标:灵活调整已存在的表结构,适应业务变化(如新增字段、修改类型),同时掌握安全删除表的操作。
1. 修改表结构(ALTER TABLE
全场景)
ALTER TABLE
是 DDL 中最复杂的语法之一,支持 增删改字段、约束、引擎、字符集 等,完整语法框架:
sql
ALTER TABLE 表名
[ADD 操作]
[MODIFY 操作]
[CHANGE 操作]
[DROP 操作]
[RENAME 操作]
[其他操作(如改引擎、字符集)];
常用操作详解:
-
添加字段(
ADD
)-
基础语法:
ALTER TABLE 表名 ADD 字段名 数据类型 [约束] [FIRST | AFTER 已有字段名];
-
可选位置:
FIRST
:把新字段放表的第一列。AFTER 字段名
:把新字段放指定字段后面(默认放最后)。
-
示例:
sql-- 给 user 表加 age 字段,放 username 后面 ALTER TABLE user ADD age TINYINT UNSIGNED AFTER username; -- 给 article 表加 is_top 字段(是否置顶),放第一列 ALTER TABLE article ADD is_top TINYINT DEFAULT 0 FIRST;
-
-
修改字段(
MODIFY
vsCHANGE
)-
MODIFY
:只改字段类型、约束、位置,不改字段名。sql-- 把 user 表的 age 字段从 TINYINT 改为 SMALLINT,且允许 NULL ALTER TABLE user MODIFY age SMALLINT UNSIGNED; -- 同时调整位置(放 email 后面) ALTER TABLE user MODIFY age SMALLINT UNSIGNED AFTER email;
-
CHANGE
:既可以改字段名,也能改类型、约束、位置(功能更强)。sql-- 把 user 表的 age 字段改名为 user_age,类型改为 INT ALTER TABLE user CHANGE age user_age INT UNSIGNED;
-
注意 :修改字段可能导致数据丢失!例如:
- 把
VARCHAR(100)
改成VARCHAR(20)
,超长的字符串会被截断。 - 把
INT
改成TINYINT
,超出范围的数值会变成0
或最大值。
- 把
-
-
删除字段(
DROP
)-
语法:
ALTER TABLE 表名 DROP 字段名;
-
警告 :删字段会 永久删除该字段的所有数据,且无法恢复!操作前务必确认。
-
示例:
sql-- 删除 user 表的 user_age 字段 ALTER TABLE user DROP user_age;
-
-
添加 / 删除约束
-
添加主键 :
sql-- 给现有表加主键(表必须没有主键,且字段非空、唯一) ALTER TABLE user ADD PRIMARY KEY (id);
-
删除主键 :
sqlALTER TABLE user DROP PRIMARY KEY;
-
添加唯一约束 :
sql-- 给 email 加唯一约束(确保不重复) ALTER TABLE user ADD UNIQUE (email); -- 加命名的唯一约束(方便后续删除) ALTER TABLE user ADD CONSTRAINT uk_user_email UNIQUE (email);
-
删除唯一约束 (需知道约束名,可通过
SHOW CREATE TABLE
查看):sqlALTER TABLE user DROP INDEX uk_user_email;
-
添加外键 :
sql-- 给 article 表的 author_id 加外键,关联 user 表的 id ALTER TABLE article ADD CONSTRAINT fk_article_author FOREIGN KEY (author_id) REFERENCES user(id) ON DELETE CASCADE;
-
删除外键 (需知道外键名):
sqlALTER TABLE article DROP FOREIGN KEY fk_article_author;
-
-
修改表的其他属性
-
改存储引擎 :
sql-- 把 article 表从 MyISAM 改成 InnoDB(支持事务) ALTER TABLE article ENGINE = InnoDB;
-
改字符集和排序规则 :
sql-- 把 user 表字符集改成 utf8mb4 ALTER TABLE user CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
重命名表 :
sql-- 方法1 ALTER TABLE old_table RENAME TO new_table; -- 方法2(更简洁) RENAME TABLE old_table TO new_table;
-
2. 删除表(DROP TABLE
)
-
基础语法:
DROP TABLE [IF EXISTS] 表名1, 表名2, ...;
(可一次删多张表) -
注意事项 :
- 删表会删除表的 所有结构和数据,且无法恢复(除非有备份)。
- 若表被其他表作为外键引用,直接删会报错,需先删外键约束或先删子表。
- 生产环境删表前,必须通过审批,并确认数据已备份!
-
示例:
sql-- 删单表 DROP TABLE IF EXISTS test_table; -- 删多表 DROP TABLE IF EXISTS temp1, temp2, temp3;
五、DDL 操作的注意事项(避坑指南)
-
事务与 DDL :
DDL 操作(如
CREATE TABLE
、ALTER TABLE
)会 自动提交事务,且无法回滚!执行前务必确认。 -
性能影响:
- 对大表执行
ALTER TABLE
(如加字段、改类型)会 锁表,期间无法读写,可能导致业务中断。 - 优化方案:用
pt-online-schema-change
(Percona 工具)等工具,在线修改表结构不锁表。
- 对大表执行
-
数据安全:
- 任何 DDL 操作(尤其是
DROP
、ALTER
)前,必须备份数据! - 测试环境验证通过后,再在生产环境执行。
- 任何 DDL 操作(尤其是
-
命名规范:
- 数据库、表、字段名用小写字母,下划线分隔(如
user_info
,避免大小写敏感问题)。 - 加
COMMENT
说明,方便后期维护(比如COMMENT '用户注册时间'
)。
- 数据库、表、字段名用小写字母,下划线分隔(如