📄 一句话概括
NOT NULL 是一道闸门:给列贴上这个标签后,塞 NULL 一律报错——「这列必须有值」从口头约定变成数据库铁律。
📝 本节和前面几节的关系
上一节认清了 NULL 的危害(查不到、统计漏),本节讲第一味解药:关键列直接禁止 NULL。注意 Default(4-7)和 NOT NULL 是搭档不是对手——一个管「没填时补什么」,一个管「根本不许没填」。
一、语法与效果
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(20) NOT NULL, -- 名字必须有
email VARCHAR(50) NOT NULL -- 邮箱必须有
);
INSERT INTO users VALUES (1, '张三', '[email protected]'); -- 成功
INSERT INTO users VALUES (2, NULL, '[email protected]'); -- 报错:NOT NULL constraint failed
INSERT INTO users VALUES (2, '李四', NULL); -- 同样报错
哪行没值哪行炸,错误信息直指列名——脏数据在门口就被扔回去。
二、默认行为:多数列「允许 NULL」
不写 NOT NULL 的列默认允许 NULL(这是历史决定,不是设计推荐)。所以关键业务列必须显式声明 NOT NULL:
| 列 | 建议 | 理由 |
|---|---|---|
| 用户名、邮箱 | NOT NULL | 没有名字的用户没有意义 |
| 手机号 | 视业务 | 有些用户真没有 |
| 备注、留言 | 允许 NULL | 天然可空 |
| 主键 | 自动 NOT NULL(4-12 细讲) | 唯一识别的前提 |
三、DEFAULT + NOT NULL:黄金搭档
score DECIMAL(5,2) NOT NULL DEFAULT 0
- 插入没填 → 自动补 0(DEFAULT 兜住,不会撞上 NOT NULL 的墙)
- 显式写 NULL → 报错(NOT NULL 拦住)
两道闸各司其职:缺省有兜底,显式空无门。
四、动手 Demo:三行三命运
CREATE TABLE t (
id INT,
name VARCHAR(20) NOT NULL DEFAULT '无名',
score DECIMAL(5,2) NOT NULL DEFAULT 0
);
INSERT INTO t (id) VALUES (1); -- ① 省略 → 默认值顶上,成功
INSERT INTO t (id, name) VALUES (2, '张三'); -- ② 部分省略 → 缺的补默认,成功
INSERT INTO t (id, name, score) VALUES (3, '李四', NULL); -- ③ 显式 NULL → 报错
③ 的报错正是 NOT NULL 在执法。
五、30 秒实验
给已有数据的表补加 NOT NULL 约束(ALTER TABLE t MODIFY name VARCHAR(20) NOT NULL,MySQL 语法)——如果表里已有 NULL,这条 ALTER 会当场失败:先把存量脏数据清干净,闸门才装得上。
六、常见误区
- 「NOT NULL 了就不用 DEFAULT」:反了——组合起来才完整:没填时有兜底值,显式空时被拦
- 「NULL 能进 NOT NULL 列,只要写 DEFAULT」:显式 NULL 照样被拦,DEFAULT 只救「省略」不救「显式空」
自测三问
1. 哪些列适合 NOT NULL?(业务上必须有值的:用户名、邮箱;天然可空的备注除外) 2. DEFAULT 和 NOT NULL 怎么配合?(DEFAULT 兜省略,NOT NULL 拦显式空) 3. 给已有 NULL 的表加 NOT NULL 会怎样?(ALTER 失败,要先清存量)- ☐ 下一节(4-10 UNIQUE-避免输入与其他记录重复的值)
相关笔记
- NULL-当没有放入任何数据时 —— 上一节:为什么要拦 NULL
- UNIQUE-避免输入与其他记录重复的值 —— 下一节:拦完空值拦重复
- DEFAULT-设置默认值 —— 黄金搭档
- 🗄️ 数据库基础 · 索引 —— 全课路线图