mysql菜鸟教程
8.4 非空约束(NOT NULL)必须填写
在创建表时,我们经常需要明确规定某些字段是必须填写的,不能为空。例如,用户注册时用户名不能为空、订单金额不能为空、商品名称不能为空。这时就需要使用非空约束(NOT NULL),它强制指定列的值不能为 NULL(未知或缺失)。
一、非空约束的作用
非空约束 非常简单直接:它要求该列在插入或更新记录时必须提供一个非 NULL 的值。如果试图将 NULL 插入到有 NOT NULL 约束的列中,数据库会拒绝操作并报错。
为什么需要非空约束?
保证数据完整性:确保关键字段都有值,避免出现“空记录”。
业务逻辑强制:例如,用户名、订单金额等字段在业务上必须存在,不应缺失。
避免程序错误:应用程序假设某些字段有值,如果数据库中出现 NULL 可能导致程序异常或计算错误。
便于查询和分析:NULL 的处理需要特殊语法(IS NULL),尽量避免过多的 NULL 可以简化查询逻辑。
二、非空约束的创建与使用
1. 在建表时指定 NOT NULL
直接在列定义后面添加 NOT NULL 关键字:
CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL, -- 用户名不能为空 email VARCHAR(100) NOT NULL, -- 邮箱不能为空 age TINYINT NULL -- 年龄可以为空(如果不写 NULL,默认也是允许 NULL) );
注意:如果不显式指定 NOT NULL,默认是允许 NULL 的(即 NULL 约束)。
2. 组合使用 NOT NULL 与 DEFAULT
NOT NULL 常与 DEFAULT 配合使用,为列指定一个默认值,这样即使插入时未提供值,也会自动填充默认值,从而避免违反非空约束。
CREATE TABLE products ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(200) NOT NULL, price DECIMAL(10,2) NOT NULL DEFAULT 0.00, -- 默认价格为0,且不能为空 stock INT NOT NULL DEFAULT 0 );
3. 修改表添加 NOT NULL 约束
如果表已经存在,可以使用 ALTER TABLE 添加非空约束。但必须确保现有数据中该列没有 NULL 值,否则操作会失败。
-- 假设已有表 users,现在要将 phone 列设为 NOT NULL -- 第一步:先检查是否有 NULL 值 SELECT * FROM users WHERE phone IS NULL; -- 如果有 NULL,需要先处理(更新为默认值或删除这些记录) UPDATE users SET phone = '' WHERE phone IS NULL; -- 或设为默认值 -- 第二步:修改列,添加 NOT NULL ALTER TABLE users MODIFY phone VARCHAR(20) NOT NULL;
4. 删除 NOT NULL 约束
如果需要取消非空约束,允许列为空,可以使用 ALTER TABLE ... MODIFY 去掉 NOT NULL:
ALTER TABLE users MODIFY phone VARCHAR(20) NULL;
或直接不指定 NOT NULL(默认就是允许 NULL):
ALTER TABLE users MODIFY phone VARCHAR(20); -- 等价于允许 NULL
三、NULL 与空字符串的区别
初学者容易混淆 NULL 和 空字符串('')。它们在数据库中是两个完全不同的概念:
NULL 不能参与常规的比较运算(如 =, <>),必须用 IS NULL 判断。
空字符串是一个普通的值,可以用 = 比较,也会占用存储空间(虽然很小)。
非空约束只禁止 NULL,不禁止空字符串。所以如果业务上要求“手机号不能为空”,但允许空字符串作为占位符,那么 NOT NULL 约束仍然有效,因为空字符串不是 NULL。
四、非空约束的注意事项
默认值的影响:如果一个列既有 NOT NULL 又有 DEFAULT,插入时若未指定该列,则使用默认值填充,不会违反约束。如果没有 DEFAULT,则必须显式提供值。
与主键的关系:主键列自动具有 NOT NULL 和 UNIQUE 属性,无需重复指定。
修改已有列时的风险:向已有表添加 NOT NULL 约束前,必须确保现有数据没有 NULL,否则修改会失败。务必先检查和清理数据。
存储引擎差异:NOT NULL 是 SQL 标准,所有存储引擎都支持。
性能影响:NOT NULL 本身对性能几乎没有影响,但它可以让索引更高效(因为索引不需要存储 NULL 值)。
五、最佳实践建议
在业务上必须存在的字段都加上 NOT NULL,例如:用户名、邮箱、创建时间、状态等。
合理使用 DEFAULT:对于有明确默认值的字段,如 create_time 默认当前时间、status 默认 1,可以简化插入操作。
避免不必要的 NULL:过多的 NULL 会让查询复杂化,也占用存储空间(虽然 MySQL 中 NULL 的存储开销很小,但逻辑上复杂)。能用空字符串或 0 代替的,尽量使用这些默认值。
设计时考虑:在设计表结构时,就明确每个字段是否允许为空,而不是事后匆忙添加约束。
六、实战练习
场景:设计一个“文章表” articles
要求:
文章标题不能为空。
文章内容不能为空。
作者 ID 不能为空(外键)。
发布时间默认当前时间,且不能为空。
阅读量默认为 0,可以为空(但建议非空,这里练习用 NULL)。
状态默认为“草稿”,不能为空。
请写出建表语句,并尝试插入几条数据测试。
参考答案:
CREATE TABLE articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
author_id INT NOT NULL,
publish_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
views INT DEFAULT 0, -- 允许 NULL,但设置了默认值后插入时可省略
status ENUM('draft', 'published', 'archived') NOT NULL DEFAULT 'draft'
);
-- 正常插入
INSERT INTO articles (title, content, author_id)
VALUES ('MySQL 教程', '这是一篇关于 MySQL 的文章...', 1);
-- 尝试插入 NULL 标题(应失败)
INSERT INTO articles (title, content, author_id) VALUES (NULL, '内容', 1);
-- 错误:Column 'title' cannot be null
-- 尝试省略必填字段(应失败)
INSERT INTO articles (content, author_id) VALUES ('内容', 1);
-- 错误:Field 'title' doesn't have a default value
-- 插入默认值演示
INSERT INTO articles (title, content, author_id, status)
VALUES ('高级 SQL', '内容...', 2, DEFAULT); -- status 使用默认值 'draft'挑战题
假设你有一个 employees 表,包含 name、email、phone 三列。现在需要将 email 改为 NOT NULL,但表中可能已经存在 email 为 NULL 的记录。请写出操作步骤。
步骤:
查询是否有 NULL:SELECT * FROM employees WHERE email IS NULL;
处理 NULL 值:将 NULL 更新为默认值,例如 UPDATE employees SET email = '' WHERE email IS NULL; 或设置一个占位符。
修改列:ALTER TABLE employees MODIFY email VARCHAR(100) NOT NULL;
七、非空约束要点总结
非空约束是数据库设计中最基础也最重要的约束之一。它帮助我们确保关键数据不会缺失,为后续的数据处理打下坚实基础。

发表评论
所有评论