5.3. Constraints

5.3. Constraints

5.3.约束

Data types are a way to limit the kind of data that can be stored in a table. For many applications,however, the constraint they provide is too coarse. For example, a column containing a product price should probably only accept positive values. But there is no standard data type that accepts only positive numbers. Another issue is that you might want to constrain column data with respect to other columns or rows. For example, in a table containing product information, there should be only one row for each product number.

数据类型是限制表中存储数据的一种方式。然而,对于大多数应用来说,它们提供的约束还是太少了。例如,存储产品价格的列应该只接受正值。但却没有只接受正值的标准数据类型。又或者,你想要根据其他列或行来限制列的数据。例如,存储产品信息的表中,每个产品应仅有一行数据。

To that end, SQL allows you to define constraints on columns and tables. Constraints give you as much control over the data in your tables as you wish. If a user attempts to store data in a column that would violate a constraint, an error is raised. This applies even if the value came from the default value definition.

为此,SQL允许在表和列上定义约束。约束使你可以根据需要尽可能多的控制表中的数据。如果在表中存储违反约束的数据,那么会报错。即使对于默认值,同样适用。

5.3.1. Check Constraints

5.3.1.检查约束

A check constraint is the most generic constraint type. It allows you to specify that the value in a certain column must satisfy a Boolean (truth-value) expression. For instance, to require positive product prices, you could use:

检查约束是最通用的约束类型。你可以通过它定义某一列中的值必须符合布尔表达式(真值)。例如,你可以这样设置以仅接受正的产品价格:

CREATE TABLE products (

product_no integer,

name text,

price numeric CHECK (price > 0)

);

As you see, the constraint definition comes after the data type, just like default value definitions.Default values and constraints can be listed in any order. A check constraint consists of the key word CHECK followed by an expression in parentheses. The check constraint expression should involve the column thus constrained, otherwise the constraint would not make too much sense.

正如上所见,约束定义紧跟在数据类型之后,类似于默认值定义。默认值和约束的顺序可随意。检查约束由关键词CHECK以及用括号括起来的一个表达式组成。检查约束表达式中需要包含约束的列,否则的话,约束就没有任何意义了。

You can also give the constraint a separate name. This clarifies error messages and allows you to refer to the constraint when you need to change it. The syntax is:

当然,也可以单独给约束定义个名字。这会在错误信息中很清晰,而且当你想更改约束的时候,可以有效的指向该约束。语法如下:

CREATE TABLE products (

product_no integer,

name text,

price numeric CONSTRAINT positive_price CHECK (price > 0)

);

So, to specify a named constraint, use the key word CONSTRAINT followed by an identifier followed by the constraint definition. (If you don't specify a constraint name in this way, the system chooses a name for you.)

因此,使用关键字CONSTRAINT后加标识符及约束定义来定义一个命名的约束。(如果没有明确定义约束名称,则系统会自动生成名称。)

A check constraint can also refer to several columns. Say you store a regular price and a discounted price, and you want to ensure that the discounted price is lower than the regular price:

检查约束也可涉及多列。假设表中有正常价格和打折价格,而且需要确保打折价格低于正常价格,则:

CREATE TABLE products (

product_no integer,

name text,

price numeric CHECK (price > 0),

discounted_price numeric CHECK (discounted_price > 0),

CHECK (price > discounted_price)

);

The first two constraints should look familiar. The third one uses a new syntax. It is not attached to a particular column, instead it appears as a separate item in the comma-separated column list. Column definitions and these constraint definitions can be listed in mixed order.

前两个约束看起来挺熟(刚开始讲过的语法)。第三个约束使用了个新的语法。它没有与特定的列绑定,而是在列的列表中以逗号分隔作为了单独的项目。列定义和这些约束定义的顺序可随意。

We say that the first two constraints are column constraints, whereas the third one is a table constraint because it is written separately from any one column definition. Column constraints can also be written as table constraints, while the reverse is not necessarily possible, since a column constraint is supposed to refer to only the column it is attached to. (PostgreSQL doesn't enforce that rule, but you should follow it if you want your table definitions to work with other database systems.) The above example could also be written as:

前两个约束称为列级约束,而第三个约束,因为它独立于列的定义而被称为表级约束。列级约束也可以写成表级约束的样子,但是反过来却不可行,因为列级约束仅应关联到它约束的列。(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)

);

or even:

或者:

CREATE TABLE products (

product_no integer,

name text,

price numeric CHECK (price > 0),

discounted_price numeric,

CHECK (discounted_price > 0 AND price > discounted_price)

);

It's a matter of taste.

这只是个人习惯的问题。

Names can be assigned to table constraints in the same way as column constraints:

表级约束也可像列级约束那样赋予名字:

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)

);

It should be noted that a check constraint is satisfied if the check expression evaluates to true or the null value. Since most expressions will evaluate to the null value if any operand is null, they will not prevent null values in the constrained columns. To ensure that a column does not contain null values, the not-null constraint described in the next section can be used.

需注意,如果检查表达式为真或为null值,则满足检查约束。因为大多数表达式在操作数为null时会求值为null,那么约束列中会可以存储null值。如果需要确保列中没有null值,则可以使用下节介绍的非空约束。

5.3.2. Not-Null Constraints

5.3.2.非空约束

A not-null constraint simply specifies that a column must not assume the null value. A syntax example:

非空约束限定列中不能存储null值。语法示例:

CREATE TABLE products (

product_no integer NOT NULL,

name text NOT NULL,

price numeric

);

A not-null constraint is always written as a column constraint. A not-null constraint is functionally equivalent to creating a check constraint CHECK (column_name IS NOT NULL), but in PostgreSQL creating an explicit not-null constraint is more efficient. The drawback is that you cannot give explicit names to not-null constraints created this way.

非空约束一般写成列级约束。一个非空约束在功能上与创建检查约束CHECK(column_name is not null)是等效的,但是在PostgreSQL中,直接显示的创建非空约束会更有效。缺点是以此方式创建的非空约束不能指定名称。

Of course, a column can have more than one constraint. Just write the constraints one after another:

当然,一列可以有多个约束。将约束一个个排起来就好:

CREATE TABLE products (

product_no integer NOT NULL,

name text NOT NULL,

price numeric NOT NULL CHECK (price > 0)

);

The order doesn't matter. It does not necessarily determine in which order the constraints are checked.

顺序无所谓。约束检查的顺序其实是无关紧要的。

The NOT NULL constraint has an inverse: the NULL constraint. This does not mean that the column must be null, which would surely be useless. Instead, this simply selects the default behavior that the column might be null. The NULL constraint is not present in the SQL standard and should not be used in portable applications. (It was only added to PostgreSQL to be compatible with some other database systems.) Some users, however, like it because it makes it easy to toggle the constraint in a script file.For example, you could start with:

非空约束的反面:空约束。而这并不是意味着此列必须为空,因为如果这样定义的话肯定是没什么用处的(列里面如果所有的数据都为空,那确实没什么意义了。)。而是,这是选择了默认的行为,即此列可能为空。空约束在SQL标准中并不存在,因此不应在可移植程序中使用。(它被添加到PostgreSQL中,仅仅是为了与其他一些数据库系统兼容。)而有些用户却喜欢这个约束,因为这使得在脚本文件中切换约束变得容易一些。例如,可能刚开始的时候这样写表定义:

CREATE TABLE products (

product_no integer NULL,

name text NULL,

price numeric NULL

);

and then insert the NOT key word where desired.

然后,可以在需要的地方加上NOT关键字。

Tip

小贴士

In most database designs the majority of columns should be marked not null.

在大多数数据库设计中,主要的列都应该标记为非空。

5.3.3. Unique Constraints

5.3.3.唯一约束

Unique constraints ensure that the data contained in a column, or a group of columns, is unique among all the rows in the table. The syntax is:

唯一约束用以确保表中的某列或某几列的数据是唯一的。语法为:

CREATE TABLE products (

product_no integer UNIQUE,

name text,

price numeric

);

when written as a column constraint, and:

以上为写作列级约束,接下来:

CREATE TABLE products (

product_no integer,

name text,

price numeric,

UNIQUE (product_no)

);

when written as a table constraint.

以上为写作表级约束。

To define a unique constraint for a group of columns, write it as a table constraint with the column names separated by commas:

如果要为多列定义唯一约束,在可以将其写作表级约束并将列名以逗号分隔:

CREATE TABLE example (

a integer,

b integer,

c integer,

UNIQUE (a, c)

);

This specifies that the combination of values in the indicated columns is unique across the whole table,though any one of the columns need not be (and ordinarily isn't) unique.

以上定义了组合列值在表中是唯一的,但不需要单独的列值是唯一的(通常也不是唯一的)。

You can assign your own name for a unique constraint, in the usual way:

可以为唯一约束定义名称,如下:

CREATE TABLE products (

product_no integer CONSTRAINT must_be_different UNIQUE,

name text,

price numeric

);

Adding a unique constraint will automatically create a unique B-tree index on the column or group of columns listed in the constraint. A uniqueness restriction covering only some rows cannot be written as a unique constraint, but it is possible to enforce such a restriction by creating a unique partial index.

添加唯一约束会自动的在约束列或列组上创建唯一B树索引。仅对于某些行限定唯一不能添加唯一约束,但可以通过创建部分唯一索引来实现。

In general, a unique constraint is violated if there is more than one row in the table where the values of all of the columns included in the constraint are equal. However, two null values are never considered equal in this comparison. That means even in the presence of a unique constraint it is possible to store duplicate rows that contain a null value in at least one of the constrained columns. This behavior conforms to the SQL standard, but we have heard that other SQL databases might not follow this rule.So be careful when developing applications that are intended to be portable.

通常,当约束列中包含的值在表中非唯一的时候就会违反唯一约束。但是,两个空值却是可以的(因为空值不相等)。也就是说,即使有唯一索引,也可以在约束列中存储包含空值的重复行。此行为符合SQL标准,但是貌似有其他SQL数据库不遵守此规则。所以,如果想要构造可移植的应用程序,则要小心此行为。

5.3.4. Primary Keys

5.3.4.主键

A primary key constraint indicates that a column, or group of columns, can be used as a unique identifier for rows in the table. This requires that the values be both unique and not null. So, the following two table definitions accept the same data:

主键约束表示某行或某几行可以作为表的唯一标识符。也就是说,该值需要既唯一又非空。所以,下例中的两个表对数据有相同的限制:

CREATE TABLE products (

product_no integer UNIQUE NOT NULL,

name text,

price numeric

);

CREATE TABLE products (

product_no integer PRIMARY KEY,

name text,

price numeric

);

Primary keys can span more than one column; the syntax is similar to unique constraints:

主键可包含多列;语法与唯一索引类似:

CREATE TABLE example (

a integer,

b integer,

c integer,

PRIMARY KEY (a, c)

);

Adding a primary key will automatically create a unique B-tree index on the column or group of columns listed in the primary key, and will force the column(s) to be marked NOT NULL.

为列添加唯一索引,会自动的为该列或列组创建唯一B树索引,且会强制该列或列组非空。

A table can have at most one primary key. (There can be any number of unique and not-null constraints,which are functionally almost the same thing, but only one can be identified as the primary key.)Relational database theory dictates that every table must have a primary key. This rule is not enforced by PostgreSQL, but it is usually best to follow it.

一个表只能有有一个主键。(虽然能够实现相同功能的唯一和非空约束可以有多个,但主键只能定义一个。)关系型数据库理论规定,每个表必须有主键。虽然PostgreSQL未对此有强制要求,但最好遵守。

Primary keys are useful both for documentation purposes and for client applications. For example, a GUI application that allows modifying row values probably needs to know the primary key of a table to be able to identify rows uniquely. There are also various ways in which the database system makes use of a primary key if one has been declared; for example, the primary key defines the default target column(s) for foreign keys referencing its table.

主键对于文档目的和客户端程序都很有用。例如,一个允许修改行值的GUI应用程序可能需要知道表的主键才能唯一标识行。 如果已经声明了主键,则数据库系统还可以通过多种方式使用主键。 例如,主键为引用其表的外键定义默认目标列。

5.3.5. Foreign Keys

5.3.5.外键

A foreign key constraint specifies that the values in a column (or a group of columns) must match the values appearing in some row of another table. We say this maintains the referential integrity between two related tables.

外键约束指定表中的某列(或某几列)必须与另一张表中的行所匹配。也就是常说的,维持两张关联表间的参照完整性。

Say you have the product table that we have used several times already:

假设有一张表:product:

CREATE TABLE products (

product_no integer PRIMARY KEY,

name text,

price numeric

);

Let's also assume you have a table storing orders of those products. We want to ensure that the orders table only contains orders of products that actually exist. So we define a foreign key constraint in the orders table that references the products table:

假设还有一张储存产品订单信息的表。我们需要确保订单表中仅能包含实际上存在的产品的订单。所以我们来定义一个关联到products表的外键以实现此需求:

CREATE TABLE orders (

order_id integer PRIMARY KEY,

product_no integer REFERENCES products (product_no),

quantity integer

);

Now it is impossible to create orders with non-NULL product_no entries that do not appear in the products table.

现在,就不可能使用在products表中未出现的非空 product_no条目创建订单。

We say that in this situation the orders table is the referencing table and the products table is the referenced table. Similarly, there are referencing and referenced columns.

此处,我们称orders表时引用表,products表是被引用表。类似的,称为引用和被引用列。

You can also shorten the above command to:

上例也可简写为:

CREATE TABLE orders (

order_id integer PRIMARY KEY,

product_no integer REFERENCES products,

quantity integer

);

because in absence of a column list the primary key of the referenced table is used as the referenced column(s).

因为如果不指定被引用列,那么被引用表的主键会默认作为被引用列。

A foreign key can also constrain and reference a group of columns. As usual, it then needs to be written in table constraint form. Here is a contrived syntax example:

外键也可以包含和引用多列。当然,这需要写成表级约束形式。以下为语法示例:

CREATE TABLE t1 (

a integer PRIMARY KEY,

b integer,

c integer,

FOREIGN KEY (b, c) REFERENCES other_table (c1, c2)

);

Of course, the number and type of the constrained columns need to match the number and type of the referenced columns.

当然,约束列的列数和数据类型需要与被引用列的列数和类型相匹配。

You can assign your own name for a foreign key constraint, in the usual way.

也可以使用通常的方式,为外键索引指定名称。

A table can have more than one foreign key constraint. This is used to implement many-to-many relationships between tables. Say you have tables about products and orders, but now you want to allow one order to contain possibly many products (which the structure above did not allow). You could use this table structure:

一个表可以有多个外键约束。这在表的多对多关系中使用。假设有两张关于产品和订单的表,现在,你想让订单中可以包含多个产品(上例中并不允许的行为)。那么可以这样设计表结构以实现需求:

CREATE TABLE products (

product_no integer PRIMARY KEY,

name text,

price numeric

);

CREATE TABLE orders (

order_id integer PRIMARY KEY,

shipping_address text,

...

);

CREATE TABLE order_items (

product_no integer REFERENCES products,

order_id integer REFERENCES orders,

quantity integer,

PRIMARY KEY (product_no, order_id)

);

Notice that the primary key overlaps with the foreign keys in the last table.

请注意,最后一个表中,主键与外键相重叠。

We know that the foreign keys disallow creation of orders that do not relate to any products. But what if a product is removed after an order is created that references it? SQL allows you to handle that as well. Intuitively, we have a few options:

我们知道,外键不会允许创建于产品没有关联的订单。但是,如果在订单创建后,相关联的产品被删除会发生什么呢?SQL也允许处理此类问题。一般有以下几种选择:

• Disallow deleting a referenced product

• Delete the orders as well

• Something else?

  • 不允许删除被引用的产品;

  • 同时删除相关订单;

  • 其他就没了吧?

To illustrate this, let's implement the following policy on the many-to-many relationship example above: when someone wants to remove a product that is still referenced by an order (via order_items), we disallow it. If someone removes an order, the order items are removed as well:

为了说明这一点,让我们对上例中的多对多关系做点更改:当有人想要删掉被引用的产品时(通过order_items),拒绝此操作;如果有人想要删掉订单,那么也删掉订单项:

CREATE TABLE products (

product_no integer PRIMARY KEY,

name text,

price numeric

);

CREATE TABLE orders (

order_id integer PRIMARY KEY,

shipping_address text,

...

);

CREATE TABLE order_items (

product_no integer REFERENCES products ON DELETE RESTRICT,

order_id integer REFERENCES orders ON DELETE CASCADE,

quantity integer,

PRIMARY KEY (product_no, order_id)

);

Restricting and cascading deletes are the two most common options. RESTRICT prevents deletion of a referenced row. NO ACTION means that if any referencing rows still exist when the constraint is checked, an error is raised; this is the default behavior if you do not specify anything. (The essential difference between these two choices is that NO ACTION allows the check to be deferred until later in the transaction, whereas RESTRICT does not.) CASCADE specifies that when a referenced row is deleted, row(s) referencing it should be automatically deleted as well. There are two other options:SET NULL and SET DEFAULT. These cause the referencing column(s) in the referencing row(s) to be set to nulls or their default values, respectively, when the referenced row is deleted. Note that these do not excuse you from observing any constraints. For example, if an action specifies SET DEFAULT but the default value would not satisfy the foreign key constraint, the operation will fail.

限制删除和关联删除基本是最常用的选项了。RESTRICT限制删除一个被引用的列。NO ACTIONS意味着,当检查约束的时候,如果引用列依然存在,那么会报错;这是默认行为。(两者之间的区别是,NO ACTION可以允许在事务中延迟检查,而RESTRICT却不可以。)CASCADE指定当被引用行删除时,引用行也会自动删除。此处还有两个选项:SET NULL和SET DEFAULT。它们指定,当被引用行删除的时候,引用行中的引用列是设为null还是设置为默认值。 请注意,这些并不能使您免于遵守任何约束条件。 例如,如果指定SET DEFAULT,但默认值不满足外键约束,则该操作将不会成功。

Analogous to ON DELETE there is also ON UPDATE which is invoked when a referenced column is changed (updated). The possible actions are the same. In this case, CASCADE means that the updated values of the referenced column(s) should be copied into the referencing row(s).

类似ON DELETE,也有当被引用列被更新的时候使用的ON UPDATE。可能的行为与ON DELETE一致。此处,CASCADE意味着,当被引用列更新的时候,引用列也会相应的更新。

测试:

结果:

Normally, a referencing row need not satisfy the foreign key constraint if any of its referencing columns are null. If MATCH FULL is added to the foreign key declaration, a referencing row escapes satisfying the constraint only if all its referencing columns are null (so a mix of null and non-null values is guaranteed to fail a MATCH FULL constraint). If you don't want referencing rows to be able to avoid satisfying the foreign key constraint, declare the referencing column(s) as NOT NULL.

通常,当引用列为空时,不需要满足外键约束。如果将MATCH FULL添加到外键声明中,则仅当其所有引用列都为null时,引用行才能满足约束条件(因此,保证null和非null值的混合可确保不通过MATCH FULL约束)。 如果您希望引用行必须能够满足外键约束,则建议将引用列声明为NOT NULL。

A foreign key must reference columns that either are a primary key or form a unique constraint. This means that the referenced columns always have an index (the one underlying the primary key or unique constraint); so checks on whether a referencing row has a match will be efficient. Since a DELETE of a row from the referenced table or an UPDATE of a referenced column will require a scan of the referencing table for rows matching the old value, it is often a good idea to index the referencing columns too. Because this is not always needed, and there are many choices available on how to index, declaration of a foreign key constraint does not automatically create an index on the referencing columns.

外键必须引用主键列或者唯一索引列。也就是说,被引用列总是有索引(由主键或唯一约束生成);所以在检查关联行的时候会很快速。因为在被引用表中删行或者更新行的时候,需要检查引用表行中的匹配行,所以在引用列上创建索引,也是一个很好的选择。因为在引用列上创建索引并不总是需要的,且有很多创建索引的选择,所以在声明外键约束的时候并不会自动的在引用列上创建索引。

More information about updating and deleting data is in Chapter 6. Also see the description of foreign key constraint syntax in the reference documentation for CREATE TABLE.

有关更新和删除数据的更多信息,请参见第6章。有关外键约束语法,请参见引用文档中的 CREATE TABLE

5.3.6. Exclusion Constraints

5.3.6.排除约束

Exclusion constraints ensure that if any two rows are compared on the specified columns or expressions using the specified operators, at least one of these operator comparisons will return false or null. The syntax is:

排除约束确保当在任意两行的特定列或表达式上使用特定操作符比较时,操作符比较中至少一个返回false或者null。语法如下:

CREATE TABLE circles (

c circle,

EXCLUDE USING gist (c WITH &&)

);

See also CREATE TABLE ... CONSTRAINT ... EXCLUDE for details.

详情参见 CREATE TABLE ... CONSTRAINT ... EXCLUDE。

Adding an exclusion constraint will automatically create an index of the type specified in the constraint declaration.

添加排除约束将自动创建约束声明中指定类型的索引。

发布了341 篇原创文章 · 获赞 53 · 访问量 88万+

猜你喜欢

转载自blog.csdn.net/ghostliming/article/details/104354422