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
    • 为域数据类型的列指定默认值。该值可以是任何不含变量的表达式(但不允许使用子查询)。默认表达式的数据类型必须与域的数据类型匹配。若未指定默认值,则默认值为空值。
    • 在任何未为列指定值的插入操作中,将使用默认表达式。若为特定列定义了默认值,则该值将覆盖与域相关的任何默认值。反之,域默认值则会覆盖与底层数据类型关联的任何默认值。
  • CONSTRAINT constraint_name
    • 约束的可选名称。若未指定,系统将自动生成名称。
  • NOT NULL
    • 此域的值被禁止为空值(但请参阅下文的注意事项)。
  • NULL
    • 此域的值允许为空。这是默认值。
    • 本条款仅用于与非标准SQL数据库的兼容性。不建议在新应用程序中使用。
  • CHECK (expression)
    • CHECK子句用于指定域值必须满足的完整性约束或测试条件。每个约束必须是返回布尔结果的表达式,应使用VALUE关键字指代待测试的值。评估结果为TRUE或UNKNOWN的表达式视为成功。若表达式返回FALSE结果,则报告错误且不允许将该值转换为域类型。
    • 目前,CHECK表达式不能包含子查询,也不能引用除VALUE之外的变量。
    • 当域包含多个CHECK约束时,它们将按名称字母顺序进行测试。(7.0之前的数据库版本不遵循任何特定的CHECK约束触发顺序。)

注意

在将值转换为域类型时,会检查域约束(特别是NOT NULL约束)。即使存在此类约束,理论上属于域类型的列仍可能被读取为空值。例如,在外连接查询中,若域列位于外连接的可空侧,就会出现这种情况。更微妙的例子是:

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

空标量子查询将产生一个空值,该值被视为域类型,因此对其不再进行约束检查,插入操作将成功完成。

由于SQL普遍假设空值是所有数据类型的有效值,因此很难避免此类问题。最佳实践是设计域约束时允许空值,然后根据需要对域类型的列应用NOT NULL约束,而不是直接对域类型应用。

YMatrix数据库假定CHECK约束的条件是不可变的,即对于相同的输入值,它们将始终返回相同的结果。正是基于这一假设,才合理地在值首次转换为域类型时检查CHECK约束,而在其他情况下则不进行检查。(这本质上与表CHECK约束的处理方式相同。)

打破此假设的常见方式之一是在CHECK表达式中引用用户自定义函数,随后更改该函数的行为。数据库虽不禁止此操作,但不会检测到域类型中已存储的值是否违反了CHECK约束。这将导致后续的数据库转储和还原操作失败。处理此类变更的推荐方法是:先使用ALTER DOMAIN删除约束,调整函数定义后重新添加约束,从而重新验证存储数据是否符合约束条件。

示例

此示例创建了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 标准。

另见

ALTER DOMAIN, DROP DOMAIN