# 创建域

CREATE DOMAIN — 定义一个新域

# 概要

CREATE DOMAIN name [ AS ] data_type
    [ COLLATE collation ]
    [ DEFAULT expression ]
    [ constraint [ ... ] ]

where constraint is:

[ CONSTRAINT constraint_name ]
{ NOT NULL | NULL | CHECK (expression) }

# 描述

创建域创建一个新域。域本质上是一种具有可选约束(对允许的值集的限制)的数据类型。定义域的用户成为其所有者。

如果给出了模式名称(例如,创建域 myschema.mydomain ...) 然后在指定的模式中创建域。否则,它会在当前模式中创建。域名在其架构中存在的类型和域中必须是唯一的。

域可用于将域的常见约束抽象到单个位置以进行维护。例如,几个表可能包含电子邮件地址列,都需要相同的 CHECK 约束来验证地址语法。定义一个域,而不是单独设置每个表的约束。

为了能够创建域,您必须拥有用法基础类型的特权。

# 参数

姓名

要创建的域的名称(可选模式限定)。

数据类型

域的基础数据类型。这可以包括数组说明符。

整理

域的可选排序规则。如果未指定排序规则,则使用基础数据类型的默认排序规则。基础类型必须是可整理的,如果整理被指定。

默认 *表达*

默认子句为域数据类型的列指定默认值。该值是任何无变量表达式(但不允许子查询)。默认表达式的数据类型必须与域的数据类型匹配。如果未指定默认值,则默认值为空值。

默认表达式将用于未指定列值的任何插入操作。如果为特定列定义了默认值,它将覆盖与域关联的任何默认值。反过来,域默认值会覆盖与基础数据类型关联的任何默认值。

约束 *约束名*

约束的可选名称。如果未指定,系统会生成一个名称。

非空

该域的值被防止为空(但请参阅下面的注释)。

空值

该域的值允许为空。这是默认设置。

此子句仅用于与非标准 SQL 数据库兼容。不鼓励在新应用程序中使用它。

查看 (*表达*)

查看子句指定完整性约束或测试域的哪些值必须满足。每个约束必须是产生布尔结果的表达式。它应该使用关键字价值指被测试的值。计算结果为 TRUE 或 UNKNOWN 的表达式成功。如果表达式产生 FALSE 结果,则报告错误并且不允许将值转换为域类型。

目前,查看表达式不能包含子查询,也不能引用除价值.

当一个域有多个查看约束,它们将按名称的字母顺序进行测试。(9.5 之前的 PostgreSQL 版本不遵守任何特定的触发顺序查看约束。)

# 笔记

领域限制,特别是非空, 在将值转换为域类型时检查。尽管存在这样的约束,名义上属于域类型的列可能读为 null。例如,这可能发生在外连接查询中,如果域列位于外连接的可为空侧。一个更微妙的例子是

INSERT INTO tab (domcol) VALUES ((SELECT domcol FROM tab WHERE false));

空标量子 SELECT 将产生一个被认为是域类型的空值,因此不会对其应用进一步的约束检查,并且插入将成功。

避免此类问题非常困难,因为 SQL 普遍假设空值是每种数据类型的有效值。因此,最佳实践是设计域的约束以允许空值,然后应用列非空根据需要对域类型的列进行约束,而不是直接对域类型进行约束。

PostgreSQL 假设查看约束条件是不可变的,也就是说,对于相同的输入值,它们总是会给出相同的结果。这个假设证明了检查查看仅当值第一次转换为域类型时才受到约束,而在其他时候则不受约束。(这个和table的处理本质上是一样的查看约束,如中所述第 5.4.1 节.)

打破这种假设的常见方法的一个示例是在查看表达式,然后更改该函数的行为。PostgreSQL 并不不允许这样做,但它不会注意到是否存在现在违反查看约束。这将导致后续的数据库转储和重新加载失败。处理此类更改的推荐方法是删除约束(使用更改域),调整函数定义,并重新添加约束,从而根据存储的数据重新检查它。

# 例子

此示例创建us_postal_code数据类型,然后在表定义中使用该类型。正则表达式测试用于验证该值是否类似于有效的美国邮政编码:

CREATE DOMAIN us_postal_code AS TEXT
CHECK(
   VALUE ~ '^\d{5}$'
OR VALUE ~ '^\d{5}-\d{4}$'
);

CREATE TABLE us_snail_addy (
  address_id SERIAL PRIMARY KEY,
  street1 TEXT NOT NULL,
  street2 TEXT,
  street3 TEXT,
  city TEXT NOT NULL,
  postal us_postal_code NOT NULL
);

# 兼容性

命令创建域符合 SQL 标准。

# 也可以看看

更改域,删除域