📄 一句话概括
收官之作:给三张表配类型、上约束、定属性,写下完整的 CREATE TABLE——从 5-16 的需求清单走到这里,书评网站设计全线贯通,本章全部工序在此合龙。
📝 本节和前面几节的关系
5-14(配型四问法)、5-15(命名规则)、5-18(表清单)三股绳拧成最终成品。落表之后顺手在 SQLite 里建出来、灌数据、跑第三章的查询——设计篇和操作篇在此会师。
一、逐列配型决策(四问法实录)
| 列 | 类型 | 决策理由 |
|---|---|---|
| users.user_id | INT(自增) |
造号,4-11 |
| users.nickname | VARCHAR(20) NOT NULL |
变长短文,昵称必须有 |
| users.email | VARCHAR(50) NOT NULL UNIQUE |
登录凭证:不许空不许重 |
| users.password | VARCHAR(60) NOT NULL |
存哈希后的串(60 位放散列) |
| books.isbn | CHAR(13) NOT NULL |
定长编码当主键,4-3 |
| books.title | VARCHAR(50) NOT NULL |
变长 |
| books.published | DATE |
只记日 |
| reviews.score | DECIMAL(3,1) |
0~10 一位小数 |
| reviews.body | TEXT |
评论文长度不定 |
| reviews.created_at | DATETIME NOT NULL |
精确到秒 |
二、最终成品 DDL
CREATE TABLE users (
user_id INT PRIMARY KEY, -- SQLite 隐式自增
nickname VARCHAR(20) NOT NULL,
email VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(60) NOT NULL
);
CREATE TABLE books (
isbn CHAR(13) PRIMARY KEY,
title VARCHAR(50) NOT NULL,
author VARCHAR(30),
published DATE
);
CREATE TABLE reviews (
review_id INT PRIMARY KEY, -- 隐式自增
user_id INT NOT NULL,
isbn CHAR(13) NOT NULL,
score DECIMAL(3,1) NOT NULL,
body TEXT,
created_at DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(user_id),
FOREIGN KEY (isbn) REFERENCES books(isbn)
);
(SQLite 环境记得先 PRAGMA foreign_keys = ON;——4-13 的提醒。)
三、约束复查:每条都有出处
| 约束 | 出处 | 拦什么 |
|---|---|---|
| email UNIQUE + NOT NULL | 5-17 登录决策 | 重复账号 |
| user_id/isbn NOT NULL(外键列) | 5-17「必须登录才能评」 | 匿名评论 |
| score DECIMAL(3,1) | 5-14 | 99.9 这类非法分值之外,格式也守住 |
| 两把外键 | 5-18 | 给不存在的书/人评论 |
四、动手 Demo:全线贯通
-- 建表(上面三条 DDL)后灌数据、跑查询
INSERT INTO books VALUES ('9787111558422', 'C++ Primer', 'Lippman', '2013-01-01');
INSERT INTO users VALUES (1, '张三', '[email protected]', 'hash123');
INSERT INTO reviews VALUES (1, 1, '9787111558422', 9.5, '经典!', '2026-09-24 09:15:00');
-- 需求 3:某书全部评论+平均分(3-17 的 AVG)
SELECT body, score FROM reviews WHERE isbn = '9787111558422';
SELECT AVG(score) FROM reviews WHERE isbn = '9787111558422';
-- 需求 4:某用户全部书评(3-20 的 JOIN 露一手)
SELECT b.title, r.score, r.body
FROM reviews r
JOIN books b ON r.isbn = b.isbn
WHERE r.user_id = 1;
需求清单上的每一条,都能在这套表上跑出 SQL——这就是设计完成的定义。
五、30 秒实验
往 reviews 塞一条 user_id=99(不存在的用户)——外键报错拦截。再想想:这条防线是谁在哪一节设计出来的?(5-17 定「必须登录」→ 5-19 落 NOT NULL + FOREIGN KEY。)
六、常见误区
- 「DDL 贴上就算完」:设计文档还要留决策理由(为什么 CHAR(13)、为什么 UNIQUE)——没理由的约束半年后必被误删
- 「一次到位,永不改表」:需求会变,但结构变更要走 ALTER 流程——5-1 说的「伤筋动骨」的另一种打开方式
自测三问
1. ISBN 为什么是 CHAR(13) PRIMARY KEY?(定长天然唯一——不用自增造号) 2. reviews 的两把外键各指向谁?(users.user_id、books.isbn) 3. 设计完成的标志是什么?(需求清单每条都能跑出 SQL)- ☑ 第五章完结 —— 第六章 已开始:内部部署、云服务-放置数据库的场所(安放场所)→ 6-4 权限 → 6-6 备份 → 版本升级-更新操作系统和软件的版本(本章收束)
相关笔记
- 表的定义、中间表-书评网站表格设计的示例3-确定需要使用的表 —— 上一节:表清单
- JOIN-合并多个表获取数据 —— 成品表上的第一场实战
- 事务-集中执行无法分割的处理 —— 下一章预告之外,写入时的另一路防线
- 内部部署、云服务-放置数据库的场所 —— 下一章起点:设计好的库安放进哪个场所
- 版本升级-更新操作系统和软件的版本 —— 下一章收束:升级前先转储备份
- 🗄️ 数据库基础 · 索引 —— 全课路线图