教学文章
Technology Exchange
热门课程
400电话

免费咨询热线
400-090-9964

教学文章

PostgreSQL教程-数据定义-检查约束

时间:2021-10-09 来源:

5.4.1. 检查约束

一个检查约束是最普通的约束类型。它允许我们指定一个特定列中的值必须要满足一个布尔表达式。例如,为了要求正值的产品价格,我们可以使用:

CREATE TABLE products (

product_no integer,

name text,

price numeric CHECK (price > 0)

);

如你所见,约束定义就和默认值定义一样跟在数据类型之后。默认值和约束之间的顺序没有影响。一个检查约束有关键字CHECK以及其后的包围在圆括号中的表达式组成。检查约束表达式应该涉及到被约束的列,否则该约束也没什么实际意义。

我们也可以给与约束一个独立的名称。这会使得错误消息更为清晰,同时也允许我们在需要更改约束时能引用它。语法为:

CREATE TABLE products (

product_no integer,

name text,

price numeric CONSTRAINT positive_price CHECK (price > 0)

);

要指定一个命名的约束,请在约束名称标识符前使用关键词CONSTRAINT,然后把约束定义放在标识符之后(如果没有以这种方式指定一个约束名称,系统将会为我们选择一个)。

一个检查约束也可以引用多个列。例如我们存储一个普通价格和一个打折后的价格,而我们希望保证打折后的价格低于普通价格:

CREATE TABLE products (

product_no integer,

name text,

price numeric CHECK (price > 0),

discounted_price numeric CHECK (discounted_price > 0),

CHECK (price > discounted_price)

);

前两个约束看起来很相似。第三个则使用了一种新语法。它并没有依附在一个特定的列,而是作为一个独立的项出现在逗号分隔的列列表中。列定义和这种约束定义可以以混合的顺序出现在列表中。

我们将前两个约束称为列约束,而第三个约束为表约束,因为它独立于任何一个列定义。列约束也可以写成表约束,但反过来不行,因为一个列约束只能引用它所依附的那一个列(PostgreSQL并不强制要求这个规则,但是如果我们希望表定义能够在其他数据库系统中工作,那就应该遵循它)。上述例子也可以写成:

CREATE TABLE products (

product_no integer,

name text,

price numeric,

CHECK (price > 0),

discounted_price numeric,

CHECK (discounted_price > 0),

CHECK (price > discounted_price)

);

甚至是:

CREATE TABLE products (

product_no integer,

name text,

price numeric CHECK (price > 0),

discounted_price numeric,

CHECK (discounted_price > 0 AND price > discounted_price)

);

这只是口味的问题。

表约束也可以用列约束相同的方法来指定名称:

CREATE TABLE products (

product_no integer,

name text,

price numeric,

CHECK (price > 0),

discounted_price numeric,

CHECK (discounted_price > 0),

CONSTRAINT valid_discount CHECK (price > discounted_price)

);

需要注意的是,一个检查约束在其检查表达式值为真或空值时被满足。因为当任何操作数为空时大部分表达式将计算为空值,所以它们不会阻止被约束列中的空值。为了保证一个列不包含空值,可以使用下一节中的非空约束。

注意

PostgreSQL不支持引用表数据以外的要检查的新增或更新的行的CHECK约束。 虽然违反此规则的CHECK约束在简单测试中看起来能工作,它不能保证数据库不会达到约束条件为假(false)的状态(由于涉及的其他行随后发生了更改)。 这将导致数据库转储和重新加载失败。 即使完整的数据库状态与约束一致,重新加载也可能失败,因为行未按照满足约束的顺序加载。 如果可能的话,使用UNIQUE, EXCLUDE,或 FOREIGN KEY约束以表示跨行和跨表限制。

如果你希望的是在插入行时的时候对其他行进行一次性检查,而不是持续维护的一致性保证,一个自定义的 trigger 可以用于实现这个功能。 (此方法避免了转储/重新加载问题,因为pg_dump不会重新安装触发器直到重新加载数据之后,因此不会在转储/重新加载期间强制执行检查。)

注意

PostgreSQL假定CHECK约束的条件是不可变的,也就是说,它们始终为同一输入行提供相同的结果。 这个假设是仅在插入或更新行时,而不是在其他时间检查CHECK约束的原因。 (上面关于不引用其他表数据的警告实际上是此限制的特殊情况。)

打破此假设的常见方法的一个示例是在 CHECK表达式中引用用户定义的函数,然后更改该函数的行为。 PostgreSQL不会禁止那样,但它不会注意到现在表中是否有行违反了CHECK约束。这将导致后续数据库转储和重新加载失败。 处理此类更改的建议方法是删除约束(使用ALTER TABLE),调整函数定义,然后重新添加约束,从而对所有表行进行重新检查。

版权所有@北京神脑资讯技术有限公司(CUUG,中国UNIX用户协会) Copyright ALL Rights Reserved 京ICP备11008061号-1

CUUG旗下网站:www.cuug.com.cn www.cuug.com oracle.cuug.com bbs.cuug.com www.cuug.net

电话:010-59426307 010-59426319 邮政编码:100089

地址:北京市海淀区北清路164号28-38号院