Administrator
Administrator
发布于 2026-10-27 / 0 阅读
0
0

数据库入门到初级(05):创建第一张表:字段、主键与约束

数据库入门到初级 · 第 05/22 篇。实验口径:MySQL 8.4、InnoDB、utf8mb4。案例:小型商城。

创建表并不是把 Excel 的表头抄一遍。你需要同时回答三个问题:每行是什么、每列存什么、哪些数据不允许进入。本篇使用完整商城结构,后面的查询都以这套结构为基础。

1. 先选择练习库

如果第 3 篇已经导入完整 SQL,可以阅读并用 SHOW CREATE TABLE 检查结构,不要重复创建。同样,以下手动建表路线只对空练习库执行。

CREATE DATABASE IF NOT EXISTS shop_lab
  CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE shop_lab;

数据库像一个存放业务表的容器,USE 指定当前连接默认操作哪个库。IF NOT EXISTS 只避免数据库已存在时报错,不会检查它原来是否具有相同的字符集。

2. 一次看清完整结构

表结构的三层规则

下面按照依赖顺序先建用户、商品,再建订单、明细。

CREATE TABLE users (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL,
  email VARCHAR(100) NOT NULL UNIQUE,
  phone VARCHAR(20) NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

CREATE TABLE products (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(100) NOT NULL,
  price DECIMAL(10,2) NOT NULL,
  stock INT NOT NULL DEFAULT 0,
  is_on_sale TINYINT NOT NULL DEFAULT 1,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT ck_products_price CHECK (price >= 0),
  CONSTRAINT ck_products_stock CHECK (stock >= 0),
  CONSTRAINT ck_products_sale CHECK (is_on_sale IN (0,1))
) ENGINE=InnoDB;

CREATE TABLE orders (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  user_id BIGINT UNSIGNED NOT NULL,
  status VARCHAR(20) NOT NULL DEFAULT 'pending',
  total_amount DECIMAL(10,2) NOT NULL,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id),
  CONSTRAINT ck_orders_total CHECK (total_amount >= 0),
  CONSTRAINT ck_orders_status CHECK (status IN ('pending','paid','cancelled'))
) ENGINE=InnoDB;

CREATE TABLE order_items (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  order_id BIGINT UNSIGNED NOT NULL,
  product_id BIGINT UNSIGNED NOT NULL,
  product_name VARCHAR(100) NOT NULL,
  unit_price DECIMAL(10,2) NOT NULL,
  quantity INT NOT NULL,
  CONSTRAINT fk_items_order FOREIGN KEY (order_id) REFERENCES orders(id),
  CONSTRAINT fk_items_product FOREIGN KEY (product_id) REFERENCES products(id),
  CONSTRAINT ck_items_price CHECK (unit_price >= 0),
  CONSTRAINT ck_items_quantity CHECK (quantity > 0),
  CONSTRAINT uk_items_order_product UNIQUE (order_id, product_id)
) ENGINE=InnoDB;

ENGINE=InnoDB 明确使用支持本系列事务和外键示例的存储引擎。AUTO_INCREMENT 让数据库在未提供编号时分配一个编号,PRIMARY KEY 标识记录身份。

3. 五种约束,各管一件事

约束 解决的问题 示例
PRIMARY KEY 每行如何唯一标识 用户 id
NOT NULL 是否允许缺失 商品名称不能缺失
UNIQUE 某个值或组合能否重复 用户邮箱不能重复
CHECK 值是否满足条件 购买数量必须大于 0
FOREIGN KEY 引用对象是否存在 订单所属用户必须存在

默认值不是约束的替代品。stock DEFAULT 0 表示省略库存时填 0,但如果没有检查约束,显式写入负数仍可能成功。

MySQL 的唯一约束对可空列允许多个 NULL;本系列邮箱同时使用 NOT NULL 和 UNIQUE,表达“每名用户必须有邮箱,且邮箱不重复”。非空也不会阻止空字符串,业务还需要校验格式与空白内容。

uk_items_order_product 表示本教学模型把同一订单中的同一商品合并成一条明细。如果未来一个商品允许不同定制配置,需要把配置维度纳入模型,而不是生搬这个约束。

4. 为什么订单明细还保存商品名称和单价

product_id 用于关联当前商品,product_name 和 unit_price 则保存购买时的快照。商品以后改名或涨价,历史订单仍应保留成交时的信息。这个问题会在第 15 篇进一步展开。

外键字段与引用字段应使用兼容类型,这里统一为 BIGINT UNSIGNED。外键默认不级联删除;删除仍被订单引用的用户会失败,这是本教程选择的历史数据保护规则。

5. 如何查看与修改结构

SHOW TABLES;
DESCRIBE products;
SHOW CREATE TABLE products;

CREATE TABLE product_note_demo (
  id BIGINT UNSIGNED PRIMARY KEY,
  name VARCHAR(100) NOT NULL
) ENGINE=InnoDB;
ALTER TABLE product_note_demo ADD COLUMN note VARCHAR(200) NULL;
SHOW CREATE TABLE product_note_demo;

结构修改只在单独的演示表上进行。MySQL 中许多 DDL 会隐式提交,不能假设外面加了 START TRANSACTION 就能回滚建表或改表;正式环境修改结构还要考虑锁、耗时和已有数据。

练习与答案

练习一:商品价格不允许负数,只有 NOT NULL 够吗? 不够。非空只检查是否缺失,还需要 CHECK (price >= 0)。

练习二:有外键后,创建订单会自动创建用户吗? 不会。外键检查已有用户,用户不存在时会拒绝订单插入。

练习三:怎么确认约束确实写进表里了? 查看 SHOW CREATE TABLE。不要只看客户端界面上的字段列表。

完整结构及下一篇的样例数据也可以直接下载:商城练习 SQL。

延伸阅读


上一篇:第 04 篇 · 系列目录 · 下一篇:第 06 篇


评论