数据定义语言(Data Definition Language,简称 DDL)主要用于定义或修改数据库的结构,包括数据库、表、视图、索引等。它是我们构建数据库大厦的"设计图纸"和"骨架"。
🔰 SQL 基础入门常识(新手必读)
作为 SQL 的初学者,在编写任何 SQL 代码之前,请牢记以下几条铁律:
- 三种注释的写法 :
# 注释内容:单行注释(MySQL 特有方式,推荐日常使用)。-- 注释内容:单行注释(标准 SQL 方式,注意--后面必须有一个空格!,否则会报错)。/* 注释内容 */:多行注释,适合写长篇大论或场景说明。
- 大小写规范 :
- SQL 关键字(如
CREATE、TABLE、INT)在数据库中不区分大小写。 - 行业推荐规范:关键字一律大写,库名、表名、列名等自定义名称一律小写,这样代码可读性极高。
- SQL 关键字(如
- 语句结束符 :
- 每一条完整的 SQL 语句都建议以英文分号
;结尾,以此告诉 MySQL 这一条指令结束了。
- 每一条完整的 SQL 语句都建议以英文分号
- 反单引号 (`````) 的妙用 :
- 键盘 Tab 键上方的那个键 `````(反单引号)。如果在命名时,你的表名或列名不幸和 MySQL 的系统关键字冲突了(比如你想建一个叫
create的表),可以用反单引号包裹起来:CREATE TABLE `create` ( ... );。
- 键盘 Tab 键上方的那个键 `````(反单引号)。如果在命名时,你的表名或列名不幸和 MySQL 的系统关键字冲突了(比如你想建一个叫
- DDL 的"破坏性" :
- DDL 操作(如
DROP删除、TRUNCATE清空)直接作用于物理文件,默认是无法撤销(回滚)的。在生产环境中执行此类操作前,请务必反复确认!
- DDL 操作(如
1. DDL之数据库操作
1.1 数据库创建
创建数据库的核心语法如下:
-
基础创建 :
sqlCREATE DATABASE 数据库名; -
安全创建 (推荐!防止因为同名库已存在而导致程序运行报错中断):
sqlCREATE DATABASE IF NOT EXISTS 数据库名; -
指定字符集 (建议使用
utf8mb4,支持存储 Emoji 表情和更多生僻字):sqlCREATE DATABASE 数据库名 CHARACTER SET utf8mb4; -
指定排序规则 (排序规则决定了字符比较和排序时的逻辑,如是否区分大小写):
sqlCREATE DATABASE 数据库名 COLLATE utf8mb4_0900_ai_ci; -
同时指定字符集与排序规则 :
sqlCREATE DATABASE 数据库名 CHARACTER SET 字符集 COLLATE 排序方式;
!NOTE\] **MySQL 8.0 默认字符集与排序规则**: * 字符集:`utf8mb4` * 排序规则:`utf8mb4_0900_ai_ci`(`ai` 代表 Accent Insensitive 区分重音,`ci` 代表 Case Insensitive **不区分大小写**)
查询当前数据库默认的字符集与排序规则
sql
-- 查看当前数据库字符集配置
SHOW VARIABLES LIKE 'character_set_database';
-- 查看当前数据库排序规则配置
SHOW VARIABLES LIKE 'collation_database';
✍️ 示例与练习
创建名为 ddl_d1 的数据库,指定字符集为 utf8mb4,且排序规则使用大小写敏感(Case Sensitive,末尾是 cs)的 utf8mb4_0900_as_cs 模式:
sql
-- as: Accent Sensitive (区分重音), cs: Case Sensitive (区分大小写)
CREATE DATABASE IF NOT EXISTS ddl_d1 CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs;
1.2 数据库查看与管理
以下是常用的数据库查询与切换指令,建议逐行执行观察效果:
sql
-- 1. 查看当前连接的 MySQL 服务器中所有的数据库
SHOW DATABASES;
-- 2. 查看当前正在使用的是哪一个数据库(若未选中任何库,会返回 NULL)
SELECT DATABASE();
-- 3. 选中或切换到指定的数据库(在对表进行增删改查前,**必须**先选中库!)
USE mysql;
-- 4. 在不切换当前数据库的前提下,查看指定数据库(如 mysql 库)下的所有表
SHOW TABLES FROM mysql;
-- 5. 查看创建某个数据库(如 ddl_d1)时的详细建库 SQL 语句和配置
SHOW CREATE DATABASE ddl_d1;
1.3 数据库修改
主要用于修改数据库的字符集或排序规则。
-
修改字符集与排序方式 :
sqlALTER DATABASE 数据库名 CHARACTER SET 字符集 COLLATE 排序方式;
!WARNING\] **新手避坑** :MySQL 中**没有任何直接修改数据库名称**的指令(如 rename database)。如果你想改库名,正确做法是: 1. 导出/备份原数据库内的数据(使用 mysqldump 等工具)。 2. 删除旧数据库(`DROP DATABASE 旧库名;`)。 3. 创建新名字的数据库。 4. 将数据导入/恢复到新库中。
1.4 数据库删除
-
直接删除 (不推荐,库不存在会报错):
sqlDROP DATABASE 数据库名; -
安全删除 (推荐,如果存在才删除,不存在也不报错):
sqlDROP DATABASE IF EXISTS 数据库名;
1.5 数据库管理综合实战
场景模拟:
- 创建多语言博客平台数据库
blog_platform,采用utf8mb4字符集。 - 切换到该库,查看其默认字符集和排序规则。
- 修改排序规则为大小写敏感的
utf8mb4_0900_as_cs。 - 模拟项目废弃,安全删除数据库。
sql
-- 1. 创建数据库(如果不存在则创建,并指定字符集)
CREATE DATABASE IF NOT EXISTS blog_platform CHARACTER SET utf8mb4;
-- 2. 切换至该库
USE blog_platform;
-- 查看字符集和排序规则参数
SHOW VARIABLES LIKE 'character_set_database';
SHOW VARIABLES LIKE 'collation_database';
-- 3. 修改排序规则为大小写敏感模式
ALTER DATABASE blog_platform COLLATE utf8mb4_0900_as_cs;
-- 4. 模拟跑路删除项目库
DROP DATABASE IF EXISTS blog_platform;
-- 查看所有数据库,验证是否已成功删除
SHOW DATABASES;
2. DDL之数据表操作
2.1 建表语法与规范
sql
CREATE TABLE [IF NOT EXISTS] 表名 (
列名1 数据类型 [列约束] [COMMENT '列注释'],
列名2 数据类型 [列约束] [COMMENT '列注释'],
...
列名N 数据类型 [列约束] [COMMENT '列注释']
) [ENGINE=存储引擎] [CHARSET=字符集] [COMMENT='表注释'];
💡 核心建表规范(新手必读):
- 最后一列千万不能有逗号。SQL 的列定义之间是用逗号分隔的,如果在最后一列的括号前加了逗号,MySQL 会报错。
- 列注释与表注释 :通过
COMMENT关键字添加,这是极佳的职业习惯,能极大提高后续维护的体验。 - 表名与列名 :要做到"见名知意",尽量避免使用拼音,推荐使用英文下划线命名法(如
user_info)。
2.2 建表实战练习
场景模拟 : 为图书管理系统创建数据库 book_libs,并在其中创建图书表 books。
sql
-- 创建并切换到数据库
CREATE DATABASE IF NOT EXISTS book_libs CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs;
USE book_libs;
-- 创建图书表
CREATE TABLE IF NOT EXISTS books (
book_name VARCHAR(20) COMMENT '图书名',
book_price DOUBLE(4,1) COMMENT '图书价格,格式为最大4位数且含1位小数',
book_num INT COMMENT '图书数量'
) CHARSET = utf8mb4 COMMENT '图书表';
-- 验证表是否创建成功
SHOW TABLES FROM book_libs;
2.3 常用数据类型解析与避坑指南
选择数据类型时,应遵循**"够用就行,空间越小越好"**的原则,能有效提升数据库的查询性能和节约磁盘空间。
① 整数类型
| 类型 | 占用空间 | 无符号范围 (UNSIGNED) | 有符号范围 (SIGNED) | 适用场景 |
|---|---|---|---|---|
| TINYINT | 1 字节 | <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 ∼ 255 0 \sim 255 </math>0∼255 | <math xmlns="http://www.w3.org/1998/Math/MathML"> − 128 ∼ 127 -128 \sim 127 </math>−128∼127 | 极小整数,如:年龄、性别代号、是否删除等 |
| SMALLINT | 2 字节 | <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 ∼ 65 , 535 0 \sim 65,535 </math>0∼65,535 | <math xmlns="http://www.w3.org/1998/Math/MathML"> − 32 , 768 ∼ 32 , 767 -32,768 \sim 32,767 </math>−32,768∼32,767 | 较小整数,如:省份代码、年份等 |
| MEDIUMINT | 3 字节 | <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 ∼ 16 , 777 , 215 0 \sim 16,777,215 </math>0∼16,777,215 | <math xmlns="http://www.w3.org/1998/Math/MathML"> − 8 , 388 , 608 ∼ 8 , 388 , 607 -8,388,608 \sim 8,388,607 </math>−8,388,608∼8,388,607 | 中等范围整数 |
| INT / INTEGER | 4 字节 | <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 ∼ 约 42.9 亿 0 \sim约 42.9亿 </math>0∼约42.9亿 | <math xmlns="http://www.w3.org/1998/Math/MathML"> − 21.4 亿 ∼ 21.4 亿 -21.4亿 \sim 21.4亿 </math>−21.4亿∼21.4亿 | 常用标准整数,如:用户ID、点击量 |
| BIGINT | 8 字节 | <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 ∼ 超大数字 0 \sim超大数字 </math>0∼超大数字 | <math xmlns="http://www.w3.org/1998/Math/MathML"> − 2 63 ∼ 2 63 − 1 -2^{63} \sim 2^{63}-1 </math>−263∼263−1 | 极大整数,如:主键雪花ID、学号、手机号 |
!TIP\] **有符号 (SIGNED) 与 无符号 (UNSIGNED) 的区别**: * 默认情况下,所有整数列都是**有符号**的(即允许存储负数)。 * 如果确定该列的数据绝对不会有负数(例如:年龄、身高、主键ID),必须声明为 `UNSIGNED`。这样不仅能防止输入负数报错,还能将正数的最大范围扩大一倍!
整数表创建示例:
sql
CREATE TABLE t1_integer_demo (
-- tinyint unsigned 刚好适合年龄(0~255岁)
t1_age TINYINT UNSIGNED COMMENT '年龄,无符号',
-- bigint unsigned 适合极大的学号
t1_number BIGINT UNSIGNED COMMENT '学号,无符号且防超范围'
);
② 浮点数与定点数类型
| 类型 | 占用空间 | 语法格式 | 核心特点与新手避坑指南 |
|---|---|---|---|
| FLOAT | 4 字节 | FLOAT(M, D) |
单精度浮点数,存在计算精度丢失。适合身高、体重等不要求极高精度的场景。 |
| DOUBLE | 8 字节 | DOUBLE(M, D) |
双精度浮点数,存在计算精度丢失。适合一般非金融类的科学计算。 |
| DECIMAL | 动态占用 | DECIMAL(M, D) |
定点数,高精度绝不丢失 !金融级数据类型,凡是涉及钱、工资、价格的,必须用它。 |
!NOTE\] **什么是 `(M, D)` 限制?** * `M` 代表 **总有效位数**(最大 65 位)。 * `D` 代表 **小数点后的保留位数**(最大 30 位)。 * 举例:`DOUBLE(4, 1)` 表示总共最多允许输入 4 位数,其中 1 位是小数。例如:`999.9` 可以存,而 `1000.0` 和 `99.99` 就会报错。
③ 字符串类型
| 类型 | 物理占用 | 特点与新手选择建议 |
|---|---|---|
| CHAR(M) | 固定分配 <math xmlns="http://www.w3.org/1998/Math/MathML"> M M </math>M 字符空间 | <math xmlns="http://www.w3.org/1998/Math/MathML"> M M </math>M 最大 255。如果存入数据长度不足 <math xmlns="http://www.w3.org/1998/Math/MathML"> M M </math>M,会在右侧自动补空格,读取时再自动剥离空格。查询性能极佳,适合长度固定的字段(如:性别、身份证号、MD5密码、手机号)。 |
| VARCHAR(M) | 动态按实际长度分配 | <math xmlns="http://www.w3.org/1998/Math/MathML"> M M </math>M 代表最大字符限制。存入多少就占用多少空间,但需要额外 1~2 字节存储长度。性能略低于 CHAR,适合长度经常变化的字段(如:姓名、邮箱、地址)。 |
| TEXT | 独立存储,不占整行限制 | 存放文章、大段评论或正文描述。千万不要指定长度。由于它保存在行外,所以不会占用整行最多 65,535 字节的物理上限。 |
💡 字符串深度避坑:MySQL 的"行字节限制"
- MySQL 规定:表中除了
TEXT/BLOB类型的列外,所有其他列的字节大小总和不能超过 65,535 字节。 - 在
utf8mb4字符集下,1 个字符最多会占用 4 个字节。 - 如果你试图创建一列
VARCHAR(16000)和一列VARCHAR(2000),就会发生: <math xmlns="http://www.w3.org/1998/Math/MathML"> ( 16000 + 2000 ) × 4 (16000 + 2000) \times 4 </math>(16000+2000)×4 字节 <math xmlns="http://www.w3.org/1998/Math/MathML"> = 72 , 000 = 72,000 </math>=72,000 字节,远远超过 65,535 字节,此时数据库将拒绝建表并报错! - 解决方案 :将超长字符串字段的数据类型改为
TEXT,或者缩小字符数限制 <math xmlns="http://www.w3.org/1998/Math/MathML"> M M </math>M。
sql
-- 演示案例
CREATE TABLE t1_varchar_limit_demo (
name1 VARCHAR(16000), -- 接近单行字节极限的 VARCHAR
name2 TEXT -- 超长文本交给 TEXT 类型,安全不受整行大小限制
) CHARSET=utf8mb4;
④ 时间类型
| 类型 | 占用空间 | 格式 | 默认行为与说明 |
|---|---|---|---|
| YEAR | 1 字节 | YYYY |
存储年份。虽然支持两位缩写,但强烈建议存四位年份防混淆。 |
| TIME | 3 字节 | HH:MM:SS |
只存时间,不存日期。 |
| DATE | 3 字节 | YYYY-MM-DD |
只存日期,不存具体时间。适合记录:生日、入职日期。 |
| DATETIME | 8 字节 | YYYY-MM-DD HH:MM:SS |
最通用的日期时间类型,可存储至 9999 年,且不受时区变化影响。 |
| TIMESTAMP | 4 字节 | YYYY-MM-DD HH:MM:SS |
时间戳,受系统时区影响(会随数据库时区切换自动转换显示)。缺点是 2038 年会溢出。 |
🚀 核心黑科技:自动维护"创建时间"与"更新时间"
在实际开发中,几乎每张表都需要记录"这条数据是什么时候被写进去的"、"最后一次修改是在什么时候"。通过以下方式,MySQL 会自动帮我们维护这些时间,完全不需要我们手动传入:
sql
CREATE TABLE t2_auto_time_demo (
name1 VARCHAR(20) COMMENT '用户名',
-- 插入新数据时,MySQL 自动获取当前系统时间写入,后续更新这条数据时该时间保持不变
reg_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '注册日期(自动生成,不变)',
-- 插入新数据时自动写入当前时间;当这条数据被 UPDATE 修改时,MySQL 自动将其翻新为最新修改时间
up_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间(自动维护,动态变动)'
);
2.4 学生借书信息表建表实战
结合上述所有知识点,我们编写一个符合规范的学生登记表:
sql
CREATE TABLE student (
stu_name VARCHAR(20) COMMENT '学生姓名,用 VARCHAR 弹性存储',
stu_sex CHAR(1) COMMENT '学生性别,使用 CHAR(1) 固定存储单字',
stu_age TINYINT UNSIGNED COMMENT '学生年龄,无负数且范围 0-255 足够用',
stu_height DOUBLE(4,1) COMMENT '学生身高,形如 175.5 即可',
stu_birthday DATE COMMENT '学生生日,只需要年月日即可,选择 DATE',
stu_regtime DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '首次注册登记时间',
stu_uptime DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '学生信息最后修改更新时间'
) CHARSET = utf8mb4 COMMENT '学生借阅登记表';
2.5 修改与删除表结构语法
对表结构的修改统称为 ALTER TABLE,这是新手经常觉得难记的部分。请仔细对比下述语法的核心变化:
① 修改表中的列
-
添加新列 :
sql-- FIRST 表示加在表的最前面;AFTER 字段名 表示加在指定列后面。不加则默认拼在最后 ALTER TABLE 表名 ADD 列名 类型 [FIRST | AFTER 某列名]; -
修改列名与类型 (
CHANGE既可以改名也可以改类型,必须写齐"新旧两个列名"):sqlALTER TABLE 表名 CHANGE 原列名 新列名 新类型 [FIRST | AFTER 某列名]; -
修改列类型/位置 (
MODIFY只能修改类型或位置,不能改列名。写一个列名即可):sqlALTER TABLE 表名 MODIFY 列名 新类型 [FIRST | AFTER 某列名]; -
删除列 :
sqlALTER TABLE 表名 DROP 列名;
!NOTE\] **💡 教材/资料排雷** : 在某些教材中可能由于笔误,添加/修改列的语法写为了 `[FIRST | ALTER 列名]`。请注意,**SQL 中绝对没有 `ALTER 列名` 这种用法** !正确的字段排序关键字是 `AFTER 某列名`(置于某字段之后)或 `FIRST`(置于表头第一列)。
② 修改表名
sql
ALTER TABLE 表名 RENAME [TO] 新表名;
③ 删除与清空表
-
删除整个表 (物理删除,表结构和数据一起灰飞烟灭):
sqlDROP TABLE IF EXISTS 表名; -
截断表/清空表数据 (超级实用 !瞬间清空表中所有数据,但完好地保留空表结构):
sqlTRUNCATE TABLE 表名;
2.6 表操作综合实战
场景模拟: 根据要求对员工表进行多次结构升级,体验真实开发中的 DDL 操作。
sql
-- 1. 建立初始员工表(表名拼错为 employeess)
CREATE TABLE employeess (
emp_num INT COMMENT '员工工号',
last_name VARCHAR(50) COMMENT '姓',
first_name VARCHAR(50) COMMENT '名',
mobile VARCHAR(25) COMMENT '手机号',
code INT COMMENT '编号',
job_time VARCHAR(50) COMMENT '入职日期',
birth DATE COMMENT '生日',
note VARCHAR(255) COMMENT '备注信息',
sex VARCHAR(5) COMMENT '性别'
) CHARSET=utf8mb4 COMMENT='初始员工表';
-- 2. 将 mobile 字段的位置调整到 code 字段后面
ALTER TABLE employeess MODIFY mobile VARCHAR(25) AFTER code;
-- 3. 将 birth 字段重命名为 birthday,数据类型保持 DATE 不变
ALTER TABLE employeess CHANGE birth birthday DATE;
-- 4. 优化 sex 字段的数据类型,由 VARCHAR(5) 缩减为更合理的定长 CHAR(1)
ALTER TABLE employeess MODIFY sex CHAR(1);
-- 5. 随着业务升级,删除不再使用的备注字段 note
ALTER TABLE employeess DROP note;
-- 6. 新增"兴趣活动"字段 favoriate_activity,长度限制 100 字符
ALTER TABLE employeess ADD favoriate_activity VARCHAR(100) COMMENT '兴趣活动';
-- 7. 纠正表名,将错误的 employeess 修改为 employees_info
ALTER TABLE employeess RENAME employees_info;
-- 8. 执行 DESC 语句,直观查看最终更新后的完美表结构
DESC employees_info;