CREATE DOMAIN
CREATE DOMAIN — 定义新域
概要
CREATE DOMAIN name [ AS ] data_type
[ COLLATE collation ]
[ DEFAULT expression ]
[ constraint [ ... ] ]
where constraint is:
[ CONSTRAINT constraint_name ]
{ NOT NULL | NULL | CHECK (expression) }
描述
CREATE DOMAIN
创建新域。域本质上是一种数据类型,具有可选约束(对允许的值集的限制)。定义域的用户将成为域的所有者。
如果给出了架构名称(例如,CREATE DOMAIN myschema.mydomain ...
),则在指定的架构中创建域。否则,在当前架构中创建。域名称在其架构中存在的类型和域中必须是唯一的。
域对于将字段上的常见约束抽象到单个位置以进行维护非常有用。例如,多个表可能包含电子邮件地址列,所有列都需要相同的 CHECK 约束来验证地址语法。定义域,而不是单独设置每个表的约束。
要能够创建域,您必须对基础类型具有USAGE
权限。
参数
name
要创建的域的名称(可选架构限定)。
data_type
域的基础数据类型。这可以包括数组说明符。
collation
域的可选排序规则。如果未指定排序规则,则域具有与其基础数据类型相同的排序规则行为。如果指定了
COLLATE
,则基础类型必须可排序。DEFAULT
expression
DEFAULT
子句为域数据类型的列指定默认值。该值是任何无变量表达式(但不允许子查询)。默认表达式的类型必须与域的数据类型匹配。如果未指定默认值,则默认值为 null 值。默认表达式将用于未指定列值的任何插入操作。如果为特定列定义了默认值,则它将覆盖与域关联的任何默认值。反过来,域默认值将覆盖与基础数据类型关联的任何默认值。
CONSTRAINT
constraint_name
约束的可选名称。如果未指定,系统将生成一个名称。
NOT NULL
防止此域的值为 null(但请参见下面的注释)。
NULL
允许此域的值为 null。这是默认设置。
此子句仅用于与非标准 SQL 数据库兼容。不建议在新应用程序中使用它。
CHECK (
expression
)CHECK
子句指定完整性约束或值必须满足的域测试。每个约束必须是一个生成布尔结果的表达式。它应该使用关键字VALUE
来引用正在测试的值。计算结果为 TRUE 或 UNKNOWN 的表达式会成功。如果表达式生成 FALSE 结果,则会报告一个错误,并且不允许将值转换为域类型。目前,
CHECK
表达式不能包含子查询,也不能引用VALUE
以外的变量。当一个域具有多个
CHECK
约束时,它们将按名称按字母顺序进行测试。(PostgreSQL 9.5 之前的版本不遵守任何特定的CHECK
约束触发顺序。)
注释
域约束,特别是NOT NULL
,在将值转换为域类型时进行检查。尽管存在这样的约束,但标称域类型的列仍可能读取为 null。例如,如果域列位于外连接的可空一侧,则可能会在外连接查询中发生这种情况。一个更微妙的例子是
INSERT INTO tab (domcol) VALUES ((SELECT domcol FROM tab WHERE false));
空标量子选择将生成一个空值,该值被认为是域类型,因此不会对其应用进一步的约束检查,并且插入将成功。
由于 SQL 通常假设空值是每个数据类型的有效值,因此很难避免此类问题。因此,最佳做法是设计域的约束,以便允许空值,然后根据需要将列NOT NULL
约束应用于域类型的列,而不是直接应用于域类型。
PostgreSQL假设CHECK
约束的条件是不可变的,也就是说,它们将始终为相同的输入值提供相同的结果。此假设证明了仅在值首次转换为域类型时检查CHECK
约束是合理的,而不是在其他时间检查。(这与表CHECK
约束的处理方式基本相同,如第 5.4.1 节所述。)
打破此假设的常见方法的一个示例是在CHECK
表达式中引用用户定义函数,然后更改该函数的行为。PostgreSQL并不禁止这样做,但它不会注意到现在违反CHECK
约束的域类型的存储值。这会导致后续数据库转储和还原失败。处理此类更改的推荐方法是删除约束(使用ALTER DOMAIN
),调整函数定义,然后重新添加约束,从而针对存储数据重新检查它。
确保域CHECK
表达式不会引发错误也是一种良好的做法。
示例
此示例创建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
);
兼容性
命令CREATE DOMAIN
符合 SQL 标准。