• 非空约束(NOT NULL):指示某列不能存储 NULL 值。
  • 唯一约束(UNIQUE):确保某列的值都是唯一的。
  • 主键(PRIMARY Key):NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。。
  • 外键(FOREIGN Key): 保证一个表中的数据匹配另一个表中的值的参照完整性。
  • 检查约束(CHECK): 保证列中的值符合指定的条件。
  • 排他约束(EXCLUSION) :排他约束,保证如果将任何两行的指定列或表达式使用指定操作符进行比较,至少其中一个操作符比较将会返回 false 或空值。

约束可以在创建表时规定(通过 CREATE TABLE 语句),或者在表创建之后规定(通过 ALTER TABLE 语句)。
约束确保了数据库中数据的准确性和可靠性。
约束可以是列级或表级。列级约束仅适用于列,表级约束被应用到整个表。

1.非空约束(NOT NULL)

默认情况下列可以保存NULL值,NULL值和没有数据不同,它表示未知的数据。
你可以根据需要指定某列不可以存放NULL值,这时就要用到NOT NULL
示例:

  1. --创建一个company1表,添加了5个字段,其中IDNAMEAGE 设置不接受空值:
  2. runoobdb=# CREATE TABLE company1(
  3. runoobdb(# ID INT PRIMARY KEY NOT NULL,
  4. runoobdb(# NAME TEXT NOT NULL,
  5. runoobdb(# AGE INT NOT NULL,
  6. runoobdb(# ADDRESS CHAR(50),
  7. runoobdb(# SALARY REAL
  8. runoobdb(# );
  9. CREATE TABLE
  10. runoobdb=# SELECT * FROM company1;
  11. id | name | age | address | salary
  12. ----+------+-----+---------+--------
  13. (0 行记录)
  14. --插入NULL数据测试
  15. runoobdb=# INSERT INTO COMPANY1 VALUES(1,'猪八戒',NULL,'高老庄',0);
  16. 错误: 在字段 "age" 中空值违反了非空约束
  17. 描述: 失败, 行包含(1, 猪八戒, null, 高老庄, 0).
  18. runoobdb=# INSERT INTO COMPANY1 VALUES(1,NULL,100,'高老庄',0);
  19. 错误: 在字段 "name" 中空值违反了非空约束
  20. 描述: 失败, 行包含(1, null, 100, 高老庄, 0).
  21. runoobdb=# INSERT INTO COMPANY1 VALUES(NULL,'孙悟空',100,'花果山',0);
  22. 错误: 在字段 "id" 中空值违反了非空约束
  23. 描述: 失败, 行包含(null, 孙悟空, 100, 花果山, 0).
  24. --插入非空数据
  25. runoobdb=# INSERT INTO COMPANY1 VALUES(1,'猪八戒',100,'高老庄',0);
  26. INSERT 0 1

2.唯一约束(UNIQUE)

UNIQUE 约束可以设置列是唯一的,避免同一列出现重复值。

--创建一个表company3,添加五个字段,其中AGE设置为UNIQUE
--此时不能向表中添加两条有相同年龄的记录
runoobdb=# CREATE TABLE company3(
runoobdb(# ID INT PRIMARY KEY     NOT NULL,
runoobdb(# NAME  TEXT             NOT NULL,
runoobdb(# AGE   INT              NOT NULL UNIQUE,
runoobdb(# ADDRESS    CHAR(50),
runoobdb(# SALARY     REAL      DEFAULT 50000.00
runoobdb(# );
CREATE TABLE

--插入数据测试一下
--先插入一条age值为18的数据
runoobdb=# INSERT INTO COMPANY3 VALUES(1,'诸葛亮',18,'西蜀',800);
INSERT 0 1
runoobdb=# SELECT * FROM COMPANY3;
 id |  name  | age |                       address                        | salary
----+--------+-----+------------------------------------------------------+--------
  1 | 诸葛亮 |  18 | 西蜀                                                 |    800
(1 行记录)

--再尝试插入一条age值为18的数据
runoobdb=# INSERT INTO COMPANY3 VALUES(2,'李世民',18,'西安',1000);
错误:  重复键违反唯一约束"company3_age_key"
描述:  键值"(age)=(18)" 已经存在


3.主键(PRIMARY KEY)

主键是数据表中每一条记录的唯一标识,一张表只有一列可以设置主键。
可以使用主键来引用表中的行,也可以通过把主键设置为其他表的外键,来创建表之间的关系。
一个表只能有一个主键,它可以由一个或多个字段组成,如果多个字段作为主键,他们被称为复合键。
如果一个表在任何字段上定义了一个主键,那么在这些字段上不能有两个记录具有相同的值。
主键是非空约束和唯一约束的组合。

--创建一个表,设置ID为主键,那么现在ID是不可以出现重复数据的
runoobdb=# CREATE TABLE COMPANY4(
runoobdb(# ID INT PRIMARY KEY  NOT NULL,
runoobdb(# NAME  TEXT          NOT NULL,
runoobdb(# AGE   INT           NOT NULL,
runoobdb(# ADDRESS  CHAR(50),
runoobdb(# SALARY   REAL
runoobdb(# );
CREATE TABLE

--插入数据测试一下
runoobdb=# INSERT INTO company4 VALUES(1,'大黑熊',1000,'黑风山',100);
INSERT 0 1
runoobdb=# INSERT INTO company4 VALUES(2,'大黑熊',1000,'黑风山',100);
INSERT 0 1
runoobdb=# INSERT INTO company4 VALUES(1,'玉皇大帝',1000,'天庭',100);
错误:  重复键违反唯一约束"company4_pkey"
描述:  键值"(id)=(1)" 已经存在

4.外键(FOREIGN KEY)

FOREIGN KEY 约束,指定列(或一组列)中的值必须匹配另一个表的某一行中出现的值。 通常一个表中的 FOREIGN KEY 指向另一个表中的 UNIQUE KEY(唯一约束的键),即维护了两个相关表之间的引用完整性。

--创建一个表
runoobdb=# CREATE TABLE COMPANY6(
runoobdb(# ID INT PRIMARY KEY NOT NULL,
runoobdb(# NAME   TEXT NOT NULL,
runoobdb(# AGE     INT NOT NULL,
runoobdb(# ADDRESS CHAR(50),
runoobdb(# SALARY  REAL
runoobdb(# );
CREATE TABLE

--创建一张DEPARTMENT1表,并添加3个字段,EMP_ID就是外键,参照 COMPANY6 的 ID: 
runoobdb=# CREATE TABLE DEPARTMENT1(
runoobdb(# ID  INT   PRIMARY KEY     NOT NULL,
runoobdb(# DEPT    CHAR(50)          NOT NULL,
runoobdb(# EMP_ID    INT      references  company6(ID)
runoobdb(# );
CREATE TABLE

5.检查约束(CHECK )

CHECK 约束保证列中的所有值满足某一条件,即对输入一条记录要进行检查。如果条件值为 false,则记录违反了约束,且不能输入到表。

--建一个新的表 COMPANY5,为SALARY列添加CHECK,设置检查条件为大于100,
--SALARY就不能被设置为<=100的值
CREATE TABLE company5(
    ID     INT  PRIMARY KEY         NOT NULL,
    NAME                      TEXT         NOT NULL, 
    AGE                INT          NOT NULL,
    ADDRESS            CHAR(50),
    SALARY             REAL         CHECK(SALARY > 100)
);
> OK
> 时间: 0.106s

--插入一条SALARY>100的数据
runoobdb=# INSERT INTO company5 VALUES(1,'旺旺',19,'星斗大森林',101);
INSERT 0 1  --插入成功了

--插入一条salary<100的数据
runoobdb=# INSERT INTO company5 VALUES(2,'火火',20,'火星',99);
错误:  关系 "company5" 的新列违反了检查约束 "company5_salary_check"  --失败了,因为不符合CHECK的条件
描述:  失败, 行包含(2, 火火, 20, 火星,                               99).

6.排他约束(EXCLUSION)

EXCLUSION 约束确保如果使用指定的运算符在指定列或表达式上比较任意两行,至少其中一个运算符比较将返回 false 或 null。

--创建一个表
CREATE TABLE company7(
    ID  INT   PRIMARY KEY    NOT NULL,
    NAME              TEXT,
    AGE                INT,
    ADDRESS            CHAR(50),
    SALARY             REAL,
    EXCLUDE USING gist
    (NAME WITH =,    --如果满足 NAME 相同,AGE 不相同则不允许插入,否则允许插入
    AGE  WITH <>) -- 其比较的结果是如果整个表边式返回 true,则不允许插入,否则允许
    )
> 错误:  对访问方法 "gist" 数据类型 text 没有默认的操作符表
HINT:  你必须指定一个操作符表给索引或定义一个默认的操作符表给数据类型.
--报错了

--您需要为每个数据库执行一次 CREATE EXTENSION btree_gist 命令,
--这将安装 btree_gist 扩展,它定义了对纯标量数据类型的 EXCLUDE 约束。

--按照要求安装btree_gist扩展
CREATE EXTENSION btree_gist
> OK
> 时间: 0.574s

--重新创建表格
CREATE TABLE company7(
    ID  INT   PRIMARY KEY    NOT NULL,
    NAME              TEXT,
    AGE                INT,
    ADDRESS            CHAR(50),
    SALARY             REAL,
    EXCLUDE USING gist
    (NAME WITH =,    --如果满足 NAME 相同,AGE 不相同则不允许插入,否则允许插入
    AGE  WITH <>) -- 其比较的结果是如果整个表边式返回 true,则不允许插入,否则允许
    )
> OK
> 时间: 0.115s

--由设置的条件可知,当NAME相同,AGE不相同的时候不允许插入,其他条件可以插入
--先创建一条数据
runoobdb=# INSERT INTO COMPANY7 VALUES(1,'Paul',32,'California',20000.00);
INSERT 0 1

-- 此条数据的 NAME 与第一条相同,且 AGE 与第一条也相同,故满足插入条件
runoobdb=# INSERT INTO COMPANY7 VALUES(2,'Paul',32,'California',20000.00);
INSERT 0 1 

--此条数据的NAME与之前的数据不同,AGE相同,允许插入
runoobdb=# INSERT INTO COMPANY7 VALUES(3,'haha',32,'California',20000.00);
INSERT 0 1

--此条数据的NAME与之前的数据相同,且age不相同,不允许插入
runoobdb=# INSERT INTO COMPANY7 VALUES(4,'haha',44,'California',20000.00);
错误:  互相冲突的键值违反排他约束"company7_name_age_excl"
描述:  键(name, age)=(haha, 44)与已存在的键(name, age)=(haha, 32)冲突

--按照设置的条件来说,再插入一条NAME与之前数据不同,AGE也不相同的数据,也是可以插入的
runoobdb=# INSERT INTO COMPANY7 VALUES(4,'大西瓜',15,'新疆',20000);
INSERT 0 1

--加上第一条,共插入了4条数据
runoobdb=# SELECT * FROM COMPANY7;
 id |  name  | age |                       address                        | salary
----+--------+-----+------------------------------------------------------+--------
  1 | Paul   |  32 | California                                           |  20000
  2 | Paul   |  32 | California                                           |  20000
  3 | haha   |  32 | California                                           |  20000
  4 | 大西瓜 |  15 | 新疆                                                 |  20000
(4 行记录)

7.删除约束

删除约束必须知道约束名称,已经知道名称来删除约束很简单,如果不知道名称,则需要找到系统生成的名称,使用 \d 表名 可以找到这些信息。

--语法
ALTER TABLE table_name DROP CONSTRAINT some_name;

--查看表中的约束,下面索引中两个带引号的就是约束的名称
runoobdb=# \d company7
               数据表 "public.company7"
  栏位   |     类型      | 校对规则 |  可空的  | 预设
---------+---------------+----------+----------+------
 id      | integer       |          | not null |
 name    | text          |          |          |
 age     | integer       |          |          |
 address | character(50) |          |          |
 salary  | real          |          |          |
索引:
    "company7_pkey" PRIMARY KEY, btree (id)
    "company7_name_age_excl" EXCLUDE USING gist (name WITH =, age WITH <>)


--删除约束
runoobdb=# ALTER TABLE company7 DROP CONSTRAINT company7_name_age_excl;
ALTER TABLE

--查看约束 "company7_name_age_excl"已经被删除了
runoobdb=# \d company7
               数据表 "public.company7"
  栏位   |     类型      | 校对规则 |  可空的  | 预设
---------+---------------+----------+----------+------
 id      | integer       |          | not null |
 name    | text          |          |          |
 age     | integer       |          |          |
 address | character(50) |          |          |
 salary  | real          |          |          |
索引:
    "company7_pkey" PRIMARY KEY, btree (id)

8.添加约束

链接