创建数据表
本教程共 46 篇 · 第 12 篇 · 更新于 2026-07-30 · 约 14 分钟阅读
12. 创建数据表
本节目标:学会用 CREATE TABLE 建表,掌握列定义、数据类型、NOT NULL/DEFAULT 约束的写法,理解表选项 ENGINE 和 CHARSET 的作用,能查看和验证表结构。
前面铺垫了那么多,这一节终于开始建表了。表是数据库里存数据的基本单位,建表就是给数据”设计格子”:有几列、每列存什么、有什么规矩。
12.1 CREATE TABLE 的基本语法
建表语句的骨架长这样:
CREATE TABLE [IF NOT EXISTS] 表名 (
列名1 数据类型 [列约束],
列名2 数据类型 [列约束],
...
[表级约束]
) [表选项];
拆开看:
CREATE TABLE:建表关键字;IF NOT EXISTS:可选,表已存在时不报错;表名:你要建的表叫啥;- 括号里:每一列的定义,列之间用逗号隔开;
表选项:存储引擎、字符集等整张表的设置。
12.2 建第一张表:users
先建我们后面要反复用的 users 用户表:
USE shop;
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
age TINYINT UNSIGNED,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
逐列解释:
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY:无符号整数、自增、主键;username VARCHAR(50) NOT NULL:变长字符串,最长 50,不能为空;email VARCHAR(100) NOT NULL:变长字符串,最长 100,不能为空;age TINYINT UNSIGNED:无符号小整数(0~255),可为空;created_at DATETIME DEFAULT CURRENT_TIMESTAMP:日期时间,默认当前时间。
建成功返回:
Query OK, 0 rows affected (0.03 sec)
Note建表前一定要先
USE 库名选好库,否则会报 “No database selected”。也可以用全限定名shop.users,但日常用USE更省事。
12.3 列定义的三要素
每一列的定义由三部分组成:
列名 数据类型 [约束]
- 列名:见名知意,用小写加下划线;
- 数据类型:前面几章学的,
INT、VARCHAR、DATETIME等; - 约束:可选,规定这列的规矩,如
NOT NULL、DEFAULT、PRIMARY KEY。
-- 标准写法
username VARCHAR(50) NOT NULL
-- 也能这样写(类型和约束顺序可换,但不推荐)
username VARCHAR(50) NOT NULL DEFAULT ''
12.4 NOT NULL 约束
NOT NULL 表示这列不能存 NULL(空值),必须给值。
CREATE TABLE t (
a INT NOT NULL, -- 必须给值
b INT -- 可以为 NULL
);
插入时不给 a 值会报错:
INSERT INTO t(b) VALUES(1);
-- ERROR: Field 'a' doesn't have a default value
Tip实战经验:能加 NOT NULL 就加。NULL 会带来很多麻烦—比较、计数、索引都会出问题。只有”确实可能没有值”的列(如中间名、备注)才允许 NULL。养成”默认 NOT NULL”的习惯。
12.5 DEFAULT 默认值
DEFAULT 给列设个默认值。插入时不指定这列,就自动用默认值。
CREATE TABLE orders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id INT UNSIGNED NOT NULL,
amount DECIMAL(10,2) NOT NULL,
status ENUM('pending','paid','shipped','done') NOT NULL DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
status默认'pending':新订单默认待处理;created_at默认CURRENT_TIMESTAMP:自动填创建时间。
插入时省略这些列:
INSERT INTO orders(user_id, amount) VALUES(1, 99.50);
mysql> SELECT * FROM orders;
+----+---------+--------+---------+---------------------+
| id | user_id | amount | status | created_at |
+----+---------+--------+---------+---------------------+
| 1 | 1 | 99.50 | pending | 2026-07-30 14:30:00 |
+----+---------+--------+---------+---------------------+
status 和 created_at 自动填了默认值。
Note几个特殊默认值:
CURRENT_TIMESTAMP:当前时间,可用于DATETIME/TIMESTAMP;NULL:默认为空(列允许 NULL 时);- 字符串默认值要用引号:
DEFAULT 'pending';- 8.0.13 起,
BLOB/TEXT列也能设默认值了(之前不行)。
12.6 PRIMARY KEY 主键
主键(Primary Key) 是能唯一标识每一行的列(或列组合),整张表只能有一个主键。
-- 单列主键
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
...
);
-- 也可以单独一行写
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT,
...
PRIMARY KEY (id)
);
主键的特点:
- 唯一:每行的主键值不能重复;
- 非空:主键列自动是
NOT NULL; - 建索引:主键自动建索引,查询快。
复合主键
多个列组合成一个主键:
CREATE TABLE order_items (
order_id INT UNSIGNED,
product_id INT UNSIGNED,
quantity INT NOT NULL,
PRIMARY KEY (order_id, product_id)
);
(order_id, product_id) 组合唯一,单个列可以重复,但组合不能重复。
Tip复合主键用得少,日常更常用单列自增主键。复合主键适合”关联表”这种没有自然单列主键的场景。
12.7 表选项:ENGINE 和 CHARSET
建表时括号后面的表选项,控制整张表的”配置”。
ENGINE:存储引擎
) ENGINE=InnoDB;
指定存储引擎,不写就用默认的 InnoDB。除非有特殊原因,一律用 InnoDB(支持事务、行锁、外键)。查看服务器支持哪些引擎用 SHOW ENGINES;。
CHARSET / COLLATE:字符集和排序规则
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
不写就继承数据库的设置。显式写上更清晰,推荐每张表都明确字符集。
Warning如果库里既有 utf8 表又有 utf8mb4 表,连接查询时可能报 “Illegal mix of collations” 错误。全库统一 utf8mb4 能避免这类问题。
其他表选项
CREATE TABLE t (
...
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
AUTO_INCREMENT=1000 -- 自增起始值
COMMENT='用户表'; -- 表注释
AUTO_INCREMENT=1000:自增列从 1000 开始;COMMENT='用户表':给表加注释,方便维护。
12.8 IF NOT EXISTS 防报错
表已存在时再建会报错:
mysql> CREATE TABLE users (id INT);
ERROR 1050 (42S01): Table 'users' already exists
加 IF NOT EXISTS,存在就跳过:
CREATE TABLE IF NOT EXISTS users (
id INT
);
-- Query OK, 0 rows affected, 1 warning (0.00 sec)
Note
IF NOT EXISTS只保证”表存在就不建”,不检查表结构是否和你写的一致。已存在的表不会被修改。所以它主要用于脚本防报错,不能用来”幂等更新表结构”。
12.9 查看表是否建好
SHOW TABLES:列出所有表
SHOW TABLES;
+----------------+
| Tables_in_shop |
+----------------+
| orders |
| users |
+----------------+
SHOW CREATE TABLE:看建表语句
SHOW CREATE TABLE users\G
\G 让输出竖排,更易读:
*************************** 1. row ***************************
Table: users
Create Table: CREATE TABLE `users` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`email` varchar(100) NOT NULL,
`age` tinyint unsigned DEFAULT NULL,
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
这个命令非常有用,能看到 MySQL 实际存的完整表结构(包括它自动补的默认值、字符集等)。
12.10 DESCRIBE:看表结构概览
DESCRIBE(简写 DESC)用表格形式显示列信息,比 SHOW CREATE TABLE 更简洁:
DESC users;
+------------+------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+-------------------+----------------+
| id | int unsigned | NO | PRI | NULL | auto_increment |
| username | varchar(50) | NO | | NULL | |
| email | varchar(100) | NO | | NULL | |
| age | tinyint unsigned | YES | | NULL | |
| created_at | datetime | YES | | CURRENT_TIMESTAMP | |
+------------+------------------+------+-----+-------------------+----------------+
各列含义:
Field:列名;Type:数据类型;Null:是否允许 NULL(NO不允许);Key:索引类型(PRI主键);Default:默认值;Extra:额外信息(如auto_increment)。
Tip忘了表有哪些列、什么类型,第一反应就是
DESC 表名。这是日常用得最多的命令之一。
12.11 一个完整的建表示例
把这一节学的都用上,建两张配套的表(注意外键后面约束章细讲,这里先看结构):
USE shop;
-- 用户表
CREATE TABLE IF NOT EXISTS users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
age TINYINT UNSIGNED,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 订单表
CREATE TABLE IF NOT EXISTS orders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id INT UNSIGNED NOT NULL,
amount DECIMAL(10,2) NOT NULL,
status ENUM('pending','paid','shipped','done') NOT NULL DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
- 用
IF NOT EXISTS防报错; - 主键统一
INT UNSIGNED AUTO_INCREMENT; - 能
NOT NULL的都加上; created_at用默认值自动填;- 显式指定
ENGINE=InnoDB和CHARSET=utf8mb4; - 加了表注释方便维护;
- 订单表给
user_id建了普通索引(INDEX后面索引章讲)。
12.12 建表的设计心得
最后分享几条实战心得:
- 表名用名词复数或单数要统一:要么全
users/orders,要么全user/order,别混; - 主键统一叫
id:别有的表叫user_id、有的叫uid,乱; - 每张表都带
created_at:记录创建时间,排查问题救命用; - 能用 NOT NULL 就 NOT NULL:少用 NULL,省心;
- 金额用 DECIMAL,时间用 DATETIME,文本用 VARCHAR:类型选对,后面少返工;
- 建表前想清楚再加列:大表加列有代价,设计阶段多花十分钟想清楚;
- 字符集统一 utf8mb4:别留 latin1、utf8 的历史包袱。
12.13 小结
这一节学会了建表:
CREATE TABLE基本语法:列定义 + 表选项;- 列定义三要素:列名、数据类型、约束;
NOT NULL禁止空值,DEFAULT设默认值,能加就加;PRIMARY KEY主键唯一标识行,自动非空、自动建索引;- 表选项
ENGINE=InnoDB、CHARSET=utf8mb4; IF NOT EXISTS防止表已存在报错;SHOW TABLES列表,SHOW CREATE TABLE看建表语句,DESC看结构概览。
表建好了,但需求会变,下一节讲怎么用 ALTER TABLE 修改表结构。