建表时,如果只有字段名和数据类型,数据库还不够“有原则”。
例如:
这些问题,靠应用层当然也可以做校验,但数据库本身也应该承担最后一道兜底责任。这个兜底机制,就是 约束(constraint)。
约束的核心作用是:防止明显不合法的数据进入表里。
它解决的不是“页面怎么提示更友好”,而是“无论谁来写数据库,都不能轻易破坏数据完整性”。
可以把它理解成:
两者不是二选一,而是分工不同。
PostgreSQL 里,入门阶段最值得先掌握这 5 类:
PRIMARY KEYFOREIGN KEYUNIQUECHECKNOT NULL下面逐个看它们解决什么问题。
PRIMARY KEY 表示主键。
主键的作用是:唯一标识表中的每一行数据。
例如用户表里,id 往往就是主键:
CREATE TABLE users (id integer PRIMARY KEY,name text);
这意味着:
id 不能重复id 不能为 NULL所以主键通常是“这张表最核心的身份字段”。
NOT NULL 表示该字段不能为空。
例如:
CREATE TABLE users (id integer PRIMARY KEY,name text NOT NULL);
这表示每条用户记录都必须有 name。
适合加 NOT NULL 的字段通常有:
如果一个字段在业务上一定要有值,就不要让它默认为可空。
UNIQUE 表示字段值不能重复。
例如邮箱通常希望全局唯一:
CREATE TABLE users (id integer PRIMARY KEY,email text UNIQUE);
这意味着:
emailUNIQUE 和 PRIMARY KEY 看起来有点像,但它们的定位不同:
PRIMARY KEY 是表的主身份UNIQUE 是“这个字段也不能重复”一个表只能有一个主键,但可以有多个唯一约束。
CHECK 用来表达“这个字段必须满足某个条件”。
例如商品价格不能为负数:
CREATE TABLE products (id integer PRIMARY KEY,name text NOT NULL,price numeric(10, 2) CHECK (price >= 0));
再例如年龄不能小于 0:
age integer CHECK (age >= 0)
CHECK 很适合放业务上稳定、明确的底线规则。
FOREIGN KEY 表示外键。
它的作用是:让一张表中的字段,引用另一张表中已经存在的记录。
例如评论必须属于某篇文章:
CREATE TABLE articles (id integer PRIMARY KEY,title text NOT NULL);CREATE TABLE comments (id integer PRIMARY KEY,article_id integer REFERENCES articles(id),content text NOT NULL);
这里的 comments.article_id 就是外键。
它表达的含义是:
article_id这类约束对保持数据关系非常重要。
很多时候,约束就是在建表时直接一起写进去的。
例如:
CREATE TABLE users (id integer PRIMARY KEY,email text NOT NULL UNIQUE,name text NOT NULL,age integer CHECK (age >= 0),created_at timestamp NOT NULL DEFAULT NOW());
这张表同时表达了几层规则:
id 是主键email 不能为空且不能重复name 不能为空age 不能小于 0created_at 必须有值,且默认使用当前时间这样表结构本身就已经带有明确的业务边界。
CREATE TABLE authors (id integer PRIMARY KEY,name text NOT NULL);CREATE TABLE books (id integer PRIMARY KEY,author_id integer REFERENCES authors(id),title text NOT NULL,price numeric(10, 2) CHECK (price >= 0));
这里:
authors 存作者books 存图书books.author_id 指向 authors.id它表达的是:一本书必须关联到一个已经存在的作者。
可以用最直观的方式来记:
PRIMARY KEY:每条记录要有唯一身份NOT NULL:这个字段不能缺UNIQUE:这个字段不能和别的记录重复CHECK:这个字段必须符合某个条件FOREIGN KEY:这条数据和另一张表的关系必须真实存在如果你能把这 5 个问题和对应约束建立起直觉,后面的表设计会顺很多。
初学者设计表时,不必一上来把所有规则都写满。
一个很实用的顺序是:
NOT NULLUNIQUECHECKFOREIGN KEY这个顺序比较符合大多数业务表的自然演进。
一个常见误区是:
“前端和后端已经校验过了,数据库就不用加约束了吧?”
不建议这样想。
原因很简单:写数据库的入口不一定只有一个。
除了主应用,还可能有:
如果数据库本身没有底线约束,任何一个入口写错,都可能留下脏数据。
更稳妥的思路是:
这会让后续查询、统计和业务判断都变麻烦。
如果字段本来就是必填,就应该明确写 NOT NULL。
不完全对。
主键是表的核心身份,唯一约束只是额外保证某列不重复,它们不是同一个角色。
外键确实会带来更严格的写入要求,但它也能防止很多关系型数据错误。是否使用要看业务场景,不应该因为怕麻烦就全部放弃。
你现在最重要的是建立下面这些判断:
如果表设计里缺少这些约束,数据库就更容易积累脏数据。
下一篇会开始进入最常见的日常操作:插入、查询、更新、删除,也就是 CRUD。