============= CREATE DOMAIN ============= .. container:: refentry :name: SQL-CREATEDOMAIN .. container:: titlepage .. container:: refnamediv .. rubric:: CREATE DOMAIN :name: create-domain CREATE DOMAIN — 定义一个新的域 .. container:: refsynopsisdiv .. rubric:: 大纲 :name: 大纲 .. code:: synopsis CREATE DOMAIN name [ AS ] data_type [ COLLATE collation ] [ DEFAULT expression ] [ constraint [ ... ] ] 其中 constraint 是: [ CONSTRAINT constraint_name ] { NOT NULL | NULL | CHECK (expression) } .. container:: refsect1 :name: id-1.9.3.62.5 .. rubric:: 描述 :name: 描述 ``CREATE DOMAIN``\ 创建一个新的域。域 本质上是一种带有可选约束(在允许的值集合上的限制)的数据类型。 定义一个域的用户将成为它的拥有者。 如果给定一个模式名(例如\ ``CREATE DOMAIN myschema.mydomain ...``\ ),那么域将被创建在该指定的模式中。 否则它会被创建在当前模式中。域的名称在其模式中的类型和域之间 必须保持唯一。 域主要被用于把字段上的常用约束抽象到一个单一的位置以便维护。例如, 几个表可能都包含电子邮件地址列,而且都要求相同的 CHECK 约束来验证 地址的语法。可以为此定义一个域,而不是在每个表上都单独设置一个约束。 要创建一个域,你必须在其底层类型上拥有\ ``USAGE``\ 特权。 .. container:: refsect1 :name: id-1.9.3.62.6 .. rubric:: 参数 :name: 参数 .. container:: variablelist *``name``* 要被创建的域的名称(可以被模式限定)。 *``data_type``* 域的底层数据类型。可以包括数组指示符。 *``collation``* 用于该域的可选的排序规则。如果没有指定排序规则,将使用底层 数据类型的默认排序规则。如果指定了\ ``COLLATE``\ , 底层类型必须是可排序的。 ``DEFAULT expression`` ``DEFAULT``\ 子句为该域数据类型的列指定一个默认值。 该值是任何没有变量的表达式(但不允许子查询)。默认值表达式 的数据类型必须匹配域的数据类型。如果没有指定默认值,那么 默认值就是空值。 默认值表达式将被用在任何没有指定列值的插入操作中。如果为一个 特定列定义了默认值,它会覆盖与域相关的默认值。继而,域默认值 会覆盖任何与底层数据类型相关的默认值。 ``CONSTRAINT constraint_name`` 一个约束的名称(可选)。如果没有指定,系统会生成一个名称。 ``NOT NULL`` 这个域的值通常不能为空值(但是看看下面的注释)。 ``NULL`` 这个域的值允许为空值。这是默认值。 这个子句只是为了与非标准 SQL 数据库相兼容而设计。在新的 应用中不鼓励使用它。 ``CHECK (expression``) ``CHECK``\ 子句指定该域的值必须满足的完整性 约束或者测试。每一个约束必须是一个产生布尔结果的表达式。 它应该使用关键词\ ``VALUE``\ 来引用要被测试的值。计算为 TRUE 或者 UNKNOWN 的表达式成功。如果该表达式产生一个 FALSE 结果,会报告一个错误并且该值不允许被转换成该域类型。 当前,\ ``CHECK``\ 表达式不能包含子查询,也不能 引用除\ ``VALUE``\ 之外的其他变量。 当一个域有多个\ ``CHECK``\ 约束,将按照其名字的 字母顺序测试它们(版本 9.5 之前的PostgreSQL 不遵循任何用于\ ``CHECK``\ 约束的特定触发顺序)。 .. container:: refsect1 :name: id-1.9.3.62.7 .. rubric:: 注解 :name: 注解 在把一个值转换成域类型时会检查域约束(特别是\ ``NOT NULL``\ )。 即使有一个这样的约束,有可能一个名义上属于该域类型的列也会被读成空值。 例如,如果在一次外连接查询中,属于该域的列出现在外连接的空值端。下面 是一个更精细的例子: .. code:: programlisting INSERT INTO tab (domcol) VALUES ((SELECT domcol FROM tab WHERE false)); 空的标量子-SELECT 将产生一个空值,它被认为是该域类型的值,因此不会 在其上应用任何进一步的约束检查,并且插入将会成功。 要避免这类问题很难,因为 SQL 的一般假设是空值也是每一种数据类型的合法值。 因此,最好的方法是设计一个允许空值的域约束,然后根据需要在该域类型的列上 应用列的\ ``NOT NULL``\ 约束。 PostgreSQL假定\ ``CHECK``\ 约束的条件是不可变的,也就是说,对于相同的输入值它们总会给出相同的结果。 仅在首次将值转换为域类型时,此假设检查\ ``CHECK``\ 约束的正确性,而不是在其他时候。 (这与处理表\ ``CHECK``\ 约束基本上相同,如 `第 5.4.1 节 `__\ 中所述。) 打破此假设的常见方法的一个示例是在 ``CHECK``\ 表达式中引用一个用户定义的函数,然后更改该函数的行为。 PostgreSQL不会禁止这样做,但是此间如果有域类型的存储值违反\ ``CHECK``\ 约束,它也不会注意到。这将导致后续数据库转储和重新加载失败。 处理此类更改的建议方法是删除约束(使用\ ``ALTER DOMAIN``\ ),调整函数定义,重新添加约束,然后根据存储的数据重新检查约束。 .. container:: refsect1 :name: id-1.9.3.62.8 .. rubric:: 示例 :name: 示例 这个例子创建\ ``us_postal_code``\ 数据类型并且把它用在 一个表定义中。一个正则表达式测试被用来验证值是否看起来像一个 合法的 US 邮政编码: .. code:: programlisting 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 ); .. container:: refsect1 :name: SQL-CREATEDOMAIN-COMPATIBILITY .. rubric:: 兼容性 :name: 兼容性 命令\ ``CREATE DOMAIN``\ 符合 SQL 标准。 .. container:: refsect1 :name: SQL-CREATEDOMAIN-SEE-ALSO .. rubric:: 另见 :name: 另见 `ALTER DOMAIN `__, `DROP DOMAIN `__