SQL详解之DDL
SQL(结构化查询语言)是关系型数据库的核心操作语言,通常可分为四大类,各类语言职责明确、各司其职,其中DDL(数据定义语言)是构建数据库结构的基础,主要用于创建、删除、修改数据库中的各类对象(如数据库、数据表、约束等)。以下先明确四大类SQL的核心区别,再重点详解DDL的使用方法、核心语法及注意事项。
SQL四大分类概述
-
• DDL(数据定义语言):核心用于操作数据库对象(创建、删除、修改),比如创建/删除数据库、创建/修改/删除数据表,核心关键字包括CREATE(创建)、DROP(删除)、ALTER(修改)。
-
• DML(数据操作语言):核心用于操作数据表中的数据,实现数据的增删改查,核心关键字包括INSERT(插入)、DELETE(删除)、UPDATE(更新)、SELECT(查询)。
-
• DCL(数据控制语言):核心用于管理数据库访问权限,保障数据安全,核心关键字包括GRANT(授予权限)、REVOKE(收回权限)。
-
• TCL(事务控制语言):核心用于管理数据库事务,确保数据操作的原子性、一致性、隔离性和持久性,常用关键字包括COMMIT(提交)、ROLLBACK(回滚)、SAVEPOINT(保存点)。
SQL语法规范说明
SQL是不区分大小写的语言,即关键字(如CREATE、DROP)大小写编写均可执行,但为了提升代码可读性、规范编码风格,建议将SQL关键字统一大写,数据库名、表名、字段名等自定义名称统一小写。
注意:若所在公司有明确的SQL编程规范,需严格遵循公司要求,个人编码喜好不能凌驾于团队规范之上,这是职业开发者的基本准则,可有效提升代码的可维护性和团队协作效率。
建库建表
为了让大家更直观地掌握DDL的使用,我们以"学校选课系统"为实战场景,搭建完整的数据库及数据表结构。先明确场景需求和表结构设计,再逐步执行DDL语句,每一步均附带详细说明。
1.场景设计与表结构规划
我们创建名为school的数据库,围绕"学院、老师、学生、课程、选课"五大核心实体设计数据表,各实体关系及表结构如下:
-
• 实体关系:学生与学院(多对一,一个学院有多名学生,一名学生属于一个学院);老师与学院(多对一,同上);老师与课程(多对一,简化设计,一名老师可授多门课,一门课对应一名老师);学生与课程(多对多,一名学生可选多门课,一门课可被多名学生选择,需借助中间表实现)。
-
• 数据表:共5张表,分别是学院表(
tb_college)、学生表(tb_student)、教师表(tb_teacher)、课程表(tb_course)、选课记录表(tb_record,学生与课程多对多关系的中间表)。
2.具体DDL语句(附详细注释)
-- 如果存在名为school的数据库就删除它
DROP DATABASE IF EXISTS `school`;
-- 创建名为school的数据库并设置默认的字符集和排序方式
CREATE DATABASE `school` DEFAULTCHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 切换到school数据库上下文环境
USE `school`;
-- 创建学院表
CREATE TABLE `tb_college`
(
`col_id` int unsigned AUTO_INCREMENT COMMENT '编号',
`col_name` varchar(50) NOT NULL COMMENT '名称',
`col_intro` varchar(500) NOT NULLDEFAULT'' COMMENT '介绍',
PRIMARY KEY (`col_id`)
);
-- 创建学生表
CREATE TABLE `tb_student`
(
`stu_id` int unsigned NOT NULL COMMENT '学号',
`stu_name` varchar(20) NOT NULL COMMENT '姓名',
`stu_sex` boolean NOT NULLDEFAULT1 COMMENT '性别',
`stu_birth` date NOT NULL COMMENT '出生日期',
`stu_addr` varchar(255) DEFAULT'' COMMENT '籍贯',
`col_id` int unsigned NOT NULL COMMENT '所属学院',
PRIMARY KEY (`stu_id`),
CONSTRAINT `fk_student_col_id` FOREIGN KEY (`col_id`) REFERENCES `tb_college` (`col_id`)
);
-- 创建教师表
CREATE TABLE `tb_teacher`
(
`tea_id` int unsigned NOT NULL COMMENT '工号',
`tea_name` varchar(20) NOT NULL COMMENT '姓名',
`tea_title` varchar(10) NOT NULLDEFAULT'助教' COMMENT '职称',
`col_id` int unsigned NOT NULL COMMENT '所属学院',
PRIMARY KEY (`tea_id`),
CONSTRAINT `fk_teacher_col_id` FOREIGN KEY (`col_id`) REFERENCES `tb_college` (`col_id`)
);
-- 创建课程表
CREATE TABLE `tb_course`
(
`cou_id` int unsigned NOT NULL COMMENT '编号',
`cou_name` varchar(50) NOT NULL COMMENT '名称',
`cou_credit` int NOT NULL COMMENT '学分',
`tea_id` int unsigned NOT NULL COMMENT '授课老师',
PRIMARY KEY (`cou_id`),
CONSTRAINT `fk_course_tea_id` FOREIGN KEY (`tea_id`) REFERENCES `tb_teacher` (`tea_id`)
);
-- 创建选课记录表
CREATE TABLE `tb_record`
(
`rec_id` bigint unsigned AUTO_INCREMENT COMMENT '选课记录号',
`stu_id` int unsigned NOT NULL COMMENT '学号',
`cou_id` int unsigned NOT NULL COMMENT '课程编号',
`sel_date` date NOT NULL COMMENT '选课日期',
`score` decimal(4,1) COMMENT '考试成绩',
PRIMARY KEY (`rec_id`),
CONSTRAINT `fk_record_stu_id` FOREIGN KEY (`stu_id`) REFERENCES `tb_student` (`stu_id`),
CONSTRAINT `fk_record_cou_id` FOREIGN KEY (`cou_id`) REFERENCES `tb_course` (`cou_id`),
CONSTRAINT `uk_record_stu_cou` UNIQUE (`stu_id`, `cou_id`)
);
3.DDL关键细节强调(必看)
-
• 反引号(`)的作用:SQL语句中,数据库名、表名、字段名被反引号包裹,并非强制要求,但可有效避免自定义名称与SQL关键字(如TABLE、SELECT)冲突,建议养成使用习惯。
-
• 字符集设置:创建数据库时,通过
DEFAULT CHARACTER SET utf8mb4指定默认字符集为utf8mb4,该字符集支持所有UTF-8编码(包括Emoji),是MySQL 8.x默认字符集,优于传统utf8(仅支持3字节编码)。可通过以下命令查看MySQL支持的所有字符集及默认排序规则:show character set;若需设置MySQL服务启动时默认使用utf8mb4,可修改MySQL配置文件(my.cnf / my.ini),在[mysqld]节点下添加:
character-set-server=utf8mb4(新手可暂不操作,避免配置失误)。 -
• database与schema的区别:创建和删除数据库时,关键字
DATABASE可替换为SCHEMA,二者功能完全一致,例如CREATE SCHEMA school;与CREATE DATABASE school;效果相同。 -
• 建表语句中的
not null是非空约束,它限定了字段不能为空;default用于为字段指定默认值,我们称之为默认值约束;primary key是主键约束,它设定了能够唯一确定一条记录的列,也确保了每条记录都是独一无二的,因为主键不允许重复;foreign key是外键约束,它维持了两张表的参照完整性,举个例子,由于学生表中为 col_id 字段添加了外键约束,限定其必须引用(references)学院表中的 col_id,因此学生表中的学院编号必须来自于学院表中的学院编号,不能够随意为该字段赋值。如果需要给主键约束、外键约束等起名字,可以使用constriant关键字并在后面跟上约束的名字。 -
• COMMENT注释:
COMMENT关键字用于给数据库、表、字段添加注释,详细的注释可大幅提升代码可读性和可维护性,便于后续开发者理解表结构设计意图,建议每一个表和字段都添加合理注释。 -
• 在创建表的时候,可以自行选择底层的存储引擎。MySQL 支持多种存储引擎,可以通过
show engines命令进行查看。MySQL 5.5 以后的版本默认使用的存储引擎是 InnoDB,它是我们推荐大家使用的存储引擎(因为更适合当下互联网应用对高并发、性能以及事务支持等方面的需求),为了 SQL 语句的向下兼容性,我们可以在建表语句结束处右圆括号的后面通过engine=innodb来指定使用 InnoDB 存储引擎。show engines\G说明:上面的 \G 是为了换一种输出方式,在命令行客户端中,如果表的字段很多一行显示不完,就会导致输出的内容看起来非常不舒服,使用 \G 可以将记录的每个列以独占整行的的方式输出,这种输出方式在命令行客户端中看起来会舒服很多。
*************************** 1. row *************************** Engine: InnoDB Support: DEFAULT Comment: Supports transactions, row-level locking, and foreign keys Transactions: YES XA: YES Savepoints: YES *************************** 2. row *************************** Engine: MRG_MYISAM Support: YES Comment: Collection of identical MyISAM tables Transactions: NO XA: NO Savepoints: NO *************************** 3. row *************************** Engine: MEMORY Support: YES Comment: Hash based, stored in memory, useful for temporary tables Transactions: NO XA: NO Savepoints: NO *************************** 4. row *************************** Engine: BLACKHOLE Support: YES Comment: /dev/null storage engine (anything you write to it disappears) Transactions: NO XA: NO Savepoints: NO *************************** 5. row *************************** Engine: MyISAM Support: YES Comment: MyISAM storage engine Transactions: NO XA: NO Savepoints: NO *************************** 6. row *************************** Engine: CSV Support: YES Comment: CSV storage engine Transactions: NO XA: NO Savepoints: NO *************************** 7. row *************************** Engine: ARCHIVE Support: YES Comment: Archive storage engine Transactions: NO XA: NO Savepoints: NO *************************** 8. row *************************** Engine: PERFORMANCE_SCHEMA Support: YES Comment: Performance Schema Transactions: NO XA: NO Savepoints: NO *************************** 9. row *************************** Engine: FEDERATED Support: NO Comment: Federated MySQL storage engine Transactions: NULL XA: NULL Savepoints: NULL 9 rows in set (0.00 sec)下面的表格对MySQL几种常用的数据引擎进行了简单的对比。
特性 InnoDB MRG_MYISAM MEMORY MyISAM 存储限制 有 没有 有 有 事务 支持 锁机制 行锁 表锁 表锁 表锁 B树索引 支持 支持 支持 支持 哈希索引 支持 全文检索 支持(5.6+) 支持 集群索引 支持 数据缓存 支持 支持 索引缓存 支持 支持 支持 支持 数据可压缩 支持 内存使用 高 低 中 低 存储空间使用 高 低 低 批量插入性能 低 高 高 高 是否支持外键 支持 通过上面的比较我们可以了解到,InnoDB 是唯一能够支持外键、事务以及行锁的存储引擎,所以我们之前说它更适合互联网应用,而且在较新版本的 MySQL 中,它也是默认使用的存储引擎。
-
• 数据类型选择技巧:选择字段数据类型时,需遵循"够用即可、精准匹配"的原则,避免浪费存储空间,若不清楚某种数据类型的用法,可通过MySQL帮助系统查询:
? data types说明 :在 MySQLWorkbench 中,不能使用
?获取帮助,要使用对应的命令help。You asked for help about help category: "Data Types" For more information, type 'help <item>', where <item> is one of the following topics: AUTO_INCREMENT BIGINT BINARY BIT BLOB BLOB DATA TYPE BOOLEAN CHAR CHAR BYTE DATE DATETIME DEC DECIMAL DOUBLE DOUBLE PRECISION ENUM FLOAT INT INTEGER LONGBLOB LONGTEXT MEDIUMBLOB MEDIUMINT MEDIUMTEXT SET DATA TYPE SMALLINT TEXT TIME TIMESTAMP TINYBLOB TINYINT TINYTEXT VARBINARY VARCHAR YEAR DATA TYPE获取 varchar 类型的帮助:
? varchar执行结果:
Name: 'VARCHAR' Description: [NATIONAL] VARCHAR(M) [CHARACTER SET charset_name] [COLLATE collation_name] A variable-length string. M represents the maximum column length in characters. The range of M is 0 to 65,535. The effective maximum length of a VARCHAR is subject to the maximum row size (65,535 bytes, which is shared among all columns) and the character set used. For example, utf8 characters can require up to three bytes per character, so a VARCHAR column that uses the utf8 character set can be declared to be a maximum of 21,844 characters. See http://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html. MySQL stores VARCHAR values as a 1-byte or 2-byte length prefix plus data. The length prefix indicates the number of bytes in the value. A VARCHAR column uses one length byte if values require no more than 255 bytes, two length bytes if values may require more than 255 bytes. *Note*: MySQL follows the standard SQL specification, and does not remove trailing spaces from VARCHAR values. VARCHAR is shorthand for CHARACTER VARYING. NATIONAL VARCHAR is the standard SQL way to define that a VARCHAR column should use some predefined character set. MySQL uses utf8 as this predefined character set. http://dev.mysql.com/doc/refman/5.7/en/charset-national.html. NVARCHAR is shorthand for NATIONAL VARCHAR. URL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html在数据类型的选择上,保存字符串数据通常都使用 VARCHAR 和 CHAR 两种类型,前者通常称为变长字符串,而后者通常称为定长字符串;对于 InnoDB 存储引擎,行存储格式没有区分固定长度和可变长度列,因此 VARCHAR 类型和 CHAR 类型没有本质区别,后者不一定比前者性能更好。如果要保存的很大字符串,可以使用 TEXT 类型;如果要保存很大的字节串,可以使用 BLOB(二进制大对象)类型。在 MySQL 中,TEXT 和 BLOB又分别包括 TEXT、MEDIUMTEXT、LONGTEXT 和 BLOB、MEDIUMBLOB、LONGBLOB 三种不同的类型,它们主要的区别在于存储数据的最大大小不同。保存浮点数可以用 FLOAT 或 DOUBLE 类型,FLOAT 已经不推荐使用了,而且在 MySQL 后续的版本中可能会被移除掉。而保存定点数应该使用 DECIMAL 类型,它可以指定小数点前后有效数字的位数。如果要保存时间日期,DATETIME 类型优于 TIMESTAMP 类型,因为前者能表示的时间日期范围更大,后者底层其实就是一个整数,记录了指定的日期时间和 1970-01-01 00:00:00 相差多少个毫秒,该类型在 2038-01-19 03:14:07 之后就会溢出。对于自增字段 AUTO_INCREMENT,如果使用 MySQL 5.x 版本要注意自增字段的回溯问题,当然这个问题在 MySQL 8.x 中已经得到了很好的解决,当然,MySQL 8.x 还有很多其他的好处,不管是功能还是性能上都有很多的优化和调整,因此强烈推荐大家使用 MySQL 8.x 版本。对于高并发访问数据库的场景,AUTO_INCREMENT 不仅存在性能上的问题,还可能在多机结构上产生重复的 ID 值,在这种场景下,使用分布式 ID 生成算法(SnowFlake、TinyID等)才是最好的选择,有兴趣的读者可以自行研究。
删除表和修改表
除了创建数据库和表,DDL还支持删除表、修改表结构(如添加/删除列、修改字段类型、添加/删除约束等),以下以学生表(tb_student)为例,详细讲解常用操作,所有语句均附带注意事项。
1 删除表(DROP TABLE)
删除表的核心关键字为DROP TABLE,有两种常用写法,推荐使用第二种(安全删除,避免表不存在时报错)。
DROP TABLE `tb_student`;
或
DROP TABLE IF EXISTS `tb_student`;
注意事项:若该表被其他表引用(如tb_record表通过外键关联tb_student表),且表中存在数据,则无法直接删除,会报错提示"外键约束冲突";需先删除引用该表的外键约束或引用表,再删除当前表。
2 修改表(ALTER TABLE)
修改表结构的核心关键字为ALTER TABLE,可实现添加列、删除列、修改字段、添加/删除约束、修改表名等操作,以下是最常用的场景示例。
2.1添加新列(ADD COLUMN)
给已存在的表添加新字段,可指定字段类型、约束、默认值等。
ALTER TABLE `tb_student` ADD COLUMN `stu_tel` varchar(20) NOT NULL COMMENT '联系电话';
注意事项:若新增列指定了NOT NULL约束,而表中已存在数据,则会报错(原有数据的新列无值,违反非空约束);解决方法:要么给新列添加DEFAULT默认值,要么先删除表中数据,再添加列。
2.2 删除列(DROP COLUMN)
删除表中不需要的字段,删除后字段及对应数据会永久丢失,需谨慎操作。
ALTER TABLE `tb_student` DROP COLUMN `stu_tel`;
2.3 修改字段数据类型(MODIFY COLUMN)
修改已存在字段的数据类型、约束、默认值,需注意字段中已有数据的兼容性(如将整数类型改为字符串类型,通常兼容;将字符串类型改为整数类型,若字段中有非数字数据,会报错)。
ALTER TABLE `tb_student` MODIFY COLUMN `stu_sex` char(1) NOT NULL DEFAULT 'M' COMMENT '性别';
2.4 修改字段名称(CHANGE COLUMN)
修改字段的名称,同时可修改字段的类型、约束等(与MODIFY的区别:CHANGE可修改字段名,MODIFY仅能修改字段属性)。
ALTER TABLE `tb_student` CHANGE COLUMN `stu_sex` `stu_gender` boolean DEFAULT 1 COMMENT '性别';
2.5 删除约束(DROP CONSTRAINT / DROP FOREIGN KEY)
删除表中的约束(如外键约束、唯一约束),需指定约束名称(建表时通过CONSTRAINT命名的约束,可直接通过名称删除)。
ALTER TABLE `tb_student` DROP FOREIGN KEY `fk_student_col_id`;
2.6 添加约束(ADD CONSTRAINT / ADD FOREIGN KEY)
给表中已存在的字段添加约束,如外键约束、唯一约束等,添加外键约束时,需确保字段类型与关联表的主键字段一致。
ALTER TABLE `tb_student` ADD FOREIGN KEY (`col_id`) REFERENCES `tb_college` (`col_id`);
或
ALTER TABLE `tb_student` ADD CONSTRAINT `fk_student_col_id` FOREIGN KEY (`col_id`) REFERENCES `tb_college` (`col_id`);
说明 :在添加外键约束时,还可以通过
on update和on delete来指定在被引用的表发生删除和更新操作时,应该进行何种处理,二者的默认值都是restrict,表示如果存在外键约束,则不允许更新和删除被引用的数据。除了restrict之外,这里可能的取值还有cascade(级联操作)和set null(设置为空),有兴趣的读者可以自行研究。
2.7 修改表名(RENAME TO)
修改数据表的名称,修改后不影响表中的数据和结构,但会影响所有引用该表的SQL语句(如查询、关联等),需谨慎操作。修改表的名字,例如将学生表的名字修改为 tb_stu_info。
ALTER TABLE `tb_student` RENAME TO `tb_stu_info`;
注意事项:生产环境中,尽量不要修改表名和字段名,若必须修改,需同步修改所有关联的SQL语句、代码逻辑,避免出现业务异常。
总结
-
• DDL操作会直接修改数据库/表结构,操作不可逆(如删除表后,数据和表结构会永久丢失),执行前需确认操作的必要性,建议提前备份数据。
-
• 执行ALTER TABLE修改表结构时,若表中数据量较大,会锁定表,影响业务正常访问,建议在业务低峰期执行。
-
• 外键约束会限制表的删除、数据的更新/删除,若不需要严格的参照完整性,可根据业务场景删除外键约束,提升数据库性能。
-
• 编码规范需统一,关键字大写、自定义名称小写,添加详细注释,便于团队协作和后续维护。
-
• 优先使用MySQL 8.x版本,修复了低版本的诸多问题(如自增回溯),同时提供了更完善的功能和更好的性能。
AI工具,提高学习,工作效率:
国内直接使用顶级AI工具
谷歌浏览器访问:https://www.nezhasoft.cloud/r/vMPJZr
