跳到主要内容

CREATE OPERATOR 到 CREATE TYPE

命令数:23 条。

CREATE OPERATOR​

CREATE OPERATOR --- 定义一个新的操作符

大纲

CREATE OPERATOR name (
{FUNCTION|PROCEDURE} = function_name
[, LEFTARG = left_type ] [, RIGHTARG = right_type ]
[, COMMUTATOR = com_op ] [, NEGATOR = neg_op ]
[, RESTRICT = res_proc ] [, JOIN = join_proc ]
[, HASHES ] [, MERGES ]
)

描述

CREATE OPERATOR定义一个新的操作符 name。定义操作符的用户会成为该操作符的拥有者。如果给出一个模式名,该操作符将被创建在指定的模式中。否则它会被创建在当前模式中。

操作符名称是最多NAMEDATALEN-1(默认为 63)个字符的序列,这些字符可以是:

+ - * / < > = ~ ! @ # % \^ & | \` ?

对名称的选择有一些限制:

• -- and /*不能出现在 操作符名称中,因为它们会被当做一段注释的开始。

• 多字符操作符名称不能以+或者- 结束,除非该名称也包含至少一个下列字符:

~ ! @ # % \^ & | \` ?

例如,@-是一个被允许的操作符名称,而 *-不是。这种限制允许系统解析 SQL兼容的命令而无需记号之间的空格。

• 将=>用作一个操作符名称已经不被推荐。在未来的发行中可能会被禁用。

在输入时!=会被映射为<>,因此这两个名字总是等效的。

必须至少定义LEFTARG和RIGHTARG中的一个。对于二元操作符,两者都必须被定义。对于右一元操作符,只应该定义 LEFTARG,而对于左一元操作符只应该定义 RIGHTARG。

function_name函数必须在之前已经用CREATE FUNCTION定义好,并且必须被定义为接受正确数量的指定类型的参数。

在CREATE OPERATOR的语法中,关键词FUNCTION和PROCEDURE是等效的,但不管哪种情况下被引用的函数都必须是一个函数而不是过程。这里对关键词PROCEDURE的是用是有历史原因的,现在已经被废弃。

其他子句指定可选的操作符优化子句。

要创建一个操作符,必须具有参数类型和返回类型上的USAGE 特权,以及底层函数上的EXECUTE特权。如果指定了一个交换子或者求反器操作符,必须拥有这些操作符。

参数

name

要定义的操作符的名称。允许使用的字符请见上文。名称可以被模式限定,例如CREATE OPERATOR myschema.+ (...)。如果 没有被模式限定,该操作符将被创建在当前模式中。

如果两个同一模式中的操作符在不同的数据类型上操作,它们可以具有相同的名称。这被称为重载。

function_name

用来实现这个操作符的函数。

left_type

这个操作符的左操作数(如果有)的数据类型。忽略这个选项可以表示一个左一元操作符。

right_type

这个操作符的右操作数(如果有)的数据类型。忽略这个选项可以表示一个右一元操作符。

com_op

这个操作符的交换子。

neg_op

这个操作符的求反器。

res_proc

用于这个操作符的限制选择度估计函数。

join_proc

用于这个操作符的连接选择度估算函数。

HASHES

表示这个操作符可以支持哈希连接。

MERGES

表示这个操作符可以支持归并连接。

要在com_op 或者其他可选参数中给出一个模式限定的操作符名称,请使用OPERATOR()语法,例如:

COMMUTATOR = OPERATOR(myschema.===) ,

注解

无法在CREATE OPERATOR中指定一个操作符的词法优先级,因为解析器的优先级行为是硬写在代码中的。

废弃的选项SORT1、SORT2、 LTCMP以及GTCMP以前被用来指定与支持归并连接的操作符相关的排序操作符的名称。现在不再需要它们了,因为 相关操作符的信息可以在 B-树的操作符族中找到。如果给出了这些选项 之一,它会被忽略(除非是为了隐式设置MERGES为真)。

使用DROP OPERATOR从数据库中删除用户定义的操作符。使用ALTER OPERATOR修改数据库中的操作符。

示例

下面的命令为数据类型box定义了一种新的操作符--面积相等:

CREATE OPERATOR === (
LEFTARG = box,
RIGHTARG = box,
FUNCTION = area_equal_function,
COMMUTATOR = ===,
NEGATOR = !==,
RESTRICT = area_restriction_function,
JOIN = area_join_function,
HASHES, MERGES
);

另见

ALTER OPERATOR, CREATE OPERATOR CLASS, DROP OPERATOR

CREATE OPERATOR CLASS​

CREATE OPERATOR CLASS --- 定义一个新的操作符类

大纲

CREATE OPERATOR CLASS name [ DEFAULT ] FOR TYPE data_type
USING index_method [ FAMILY family_name ] AS
{ OPERATOR strategy_number operator_name [ ( op_type, op_type ) ] [ FOR SEARCH | FOR ORDER BY sort_family_name ]
| FUNCTION support_number [ ( op_type [ , op_type ] ) ] function_name ( argument_type [, ...] )
| STORAGE storage_type
} [, ... ]

描述

CREATE OPERATOR CLASS创建新的操作符类。一个操作符类定义一种特殊的数据类型如何被用于一个索引。操作符类指定为该数据类型和索引方法扮演特殊角色或者"策略"的操作符。操作符类还指定当该操作符类被选择用于一个索引列时,索引方法要使用的支持函数。操作符类所使用的所有操作符和函数必须在操作符类被创建之前被定义好。

如果给出了一个模式名称,那么该操作符类会被创建在指定模式中。否则,它会被创建在当前模式中。同一模式中的两个操作符类只有在被用于不同的索引方法时才可以具有相同的名称。

定义操作符类的用户将成为其拥有者。当前,创建用户必须是超级用户(做出这种限制是因为错误的操作符类定义会让服务器混淆甚至崩溃)。

CREATE OPERATOR CLASS当前不会检查操作符 类定义是否包括该索引方法所要求的所有操作符和函数,也不会检查这些操作符和函数是否构成一个一致的集合。定义一个合法的操作符类是用户的责任。

相关的操作符类可以被组成操作符族。要把一个新的操作符类加入到一个现有的族中,可以在CREATE OPERATOR CLASS中指定FAMILY选项。如果没有这个选项,新的类会被放到一个同名的族中(如果族不存在会创建之)。

参数

name

要创建的操作符类的名称。该名称可以被模式限定。

DEFAULT

如果存在,该操作符类将成为其数据类型的默认操作符类。对一种特定的数据类型和索引方法至多有一个默认操作符类。

data_type

这个操作符类所用于的列数据类型。

index_method

这个操作符类所用于的索引方法的名称。

family_name

要把这个操作符类加入其中的已有操作符族的名称。如果没有指定,将使用一个同名操作符族(如果还不存在则创建之)。

strategy_number

用于一个与该操作符类相关联的操作符的索引方法策略号。

operator_name

一个与该操作符类相关联的操作符的名称(可以被模式限定)。

op_type

在一个OPERATOR子句中,这表示该操作符的操作数数据类型,或者用NONE来表示一个左一元或者右一元操作符。在操作数数据类型与该操作符的数据类型相同的一般情况下,操作数的数据类型可以被省略。

在一个FUNCTION子句中,这表示该函数要支持的操作数据类型,如果它与该函数的输入数据类型(对于 B-树比较函数和哈希 函数)或者操作符类的数据类型(对于 B-树排序支持函数和与B-树相同的的图像函数以及所有GiST、 SP-GiST、GIN 和 BRIN 操作符类中的函数)不同。这些默认值是正确的,并且 op_type因此不必 在FUNCTION子句中被指定,对于 B-树排序支持函数的情 况来说,这表示跨数据类型比较。

sort_family_name

一个现有btree操作符族的名称(可以是模式限定的),它描述与一种排序操作符相关联的排序顺序。

如果FOR SEARCH和FOR ORDER BY都没有被指定,那么FOR SEARCH是默认值。

support_number

用于一个与该操作符类相关联的函数的索引方法支持函数编号。

function_name

一个用于该操作符类的索引方法支持函数的函数名称(可以是模式限定的)。

argument_type

该函数的参数数据类型。

storage_type

实际存储在索引中的数据类型。通常这和列数据类型相同,但是有些索引方法(当前有GiST、GIN 和 BRIN)允许它们不同。除非索引方法允许使用不同的类型,STORAGE子句必须被省略。如果data_type列被指定为anyarray,那么storage_type可以被声明为anyelement 以指示索引条目是属于为每个特定索引创建的实际数组类型的元素类型的成员。

OPERATOR、FUNCTION和STORAGE 子句可以以任何顺序出现。

注解

因为索引机制在使用函数之前不检查它们的权限,将一个函数或者操作符包括在一个操作符类中相当于在其上授予公共执行权限。这对操作符类中很有用的函数来说通常不成问题。

操作符不应该用 SQL 函数定义。SQL 函数很有可能会被内联到调用查询中,这会妨碍优化器识别该查询匹配一个索引。

示例

下面的例子为数据类型_int4(int4数组)定义了一个 GiST 索引操作符。完整的例子请见intarray模块。

CREATE OPERATOR CLASS gist__int_ops
DEFAULT FOR TYPE _int4 USING gist AS
OPERATOR 3 &&,
OPERATOR 6 = (anyarray, anyarray),
OPERATOR 7 @>,
OPERATOR 8 <@,
OPERATOR 20 @@ (_int4, query_int),
FUNCTION 1 g_int_consistent (internal, _int4, smallint,
oid, internal),
FUNCTION 2 g_int_union (internal, internal),
FUNCTION 3 g_int_compress (internal),
FUNCTION 4 g_int_decompress (internal),
FUNCTION 5 g_int_penalty (internal, internal, internal),
FUNCTION 6 g_int_picksplit (internal, internal),
FUNCTION 7 g_int_same (_int4, _int4, internal);

另见

ALTER OPERATOR CLASS, DROP OPERATOR CLASS, CREATE OPERATOR FAMILY, ALTER OPERATOR FAMILY

CREATE OPERATOR FAMILY​

CREATE OPERATOR FAMILY --- 定义一个新的操作符族

大纲

CREATE OPERATOR FAMILY name USING index_method

描述

CREATE OPERATOR FAMILY创建一个新的操作符族。一个操作符族定义一个相关操作符类组成的集合,并且可能还包含一些额外的、与这些操作符类兼容但对于任何个体索引的功能不是至关重要的操作符和支持函数(对索引至关重要的操作符和函数应该被分组在相关的操作符类中,而不是"松散地"在操作符中。通常,单一数据类型操作符被限制在操作符类中,而跨数据类型操作符可以松散地存在于一个包含用于两种数据类型的操作符类的操作

符族中)。

新的操作符族初始时为空。应该通过发出后续的 CREATE OPERATOR CLASS命令来增加包含在其中的操作符类,还可以用可选的 ALTER OPERATOR FAMILY命令来增加"松散的"操作符和它们对应的支持函数。

如果给出一个模式名称,该操作符族会被创建在指定的模式中。否则,它会被创建在当前模式中。只有当同一个模式中的两个操作符族是用于不同的索引方法时,它们才能拥有相同的名字。

定义一个操作符族的用户将成为它的拥有者。当前,创建用户必须是超级用户(做出这样的限制是因为错误的操作符族会让服务器混淆甚至崩溃)。

参数

name

要创建的操作符族的名称。该名称可以被模式限定。

index_method

这个操作符族要用于的索引方法的名称。

另见

ALTER OPERATOR FAMILY, DROP OPERATOR FAMILY, CREATE OPERATOR CLASS, ALTER OPERATOR CLASS, DROP OPERATOR CLASS

CREATE POLICY​

CREATE POLICY --- 为一个表定义一条新的行级安全性策略

大纲

CREATE POLICY name ON table_name
[ AS { PERMISSIVE | RESTRICTIVE } ]
[ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
[ TO { role_name | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ]
[ USING ( using_expression ) ]
[ WITH CHECK ( check_expression ) ]

描述

CREATE POLICY为一个表定义一条行级安全性策略。注意为了应用已被创建的策略,在表上必须启用行级安全性(使用ALTER TABLE ... ENABLE ROW LEVEL SECURITY)。

一条策略授予权限以选择、插入、更新或者删除匹配相关策略表达式的行。 现有的表行会按照USING中指定的表达式进行检查,而将要通过INSERT或UPDATE创建的新行会按照WITH CHECK中指定的表达式进行检查。 当USING表达式对于一个给定行返回真时,该行对用户可见,而返回假或空时该行不可见。当一个WITH CHECK 表达式对一行返回真时,该行会被插入或更新,而如果返回假或空时会发生一个错误。

对于INSERT和 UPDATE语句,在BEFORE 触发器被引发后并且在任何数据修改真正发生之前,

WITH CHECK表达式会被强制。因此,一个BEFORE ROW触发器可以修改要被插入的数据,从而影响安全性策略检查的结果。WITH CHECK表达式 在任何其他约束之前被强制。

策略名称是针对每个表的。因此,一个策略名称可以被用于很多个不同的表 并且对于不同的表呈现适合于该表的定义。

策略可以被应用于特定的命令或者特定的角色。除非特别指定,新创建的策略的默认行为是适用于所有命令和角色。多个策略可以应用于单个命令,更多细节请见下文。

对同时具有USING和WITH CHECK 表达式(ALL和UPDATE)的策略, 如果没有定义WITH CHECK表达式,那么 USING表达式将被用于决定哪些行可见(普通 USING情况)以及允许哪些新行被增加( WITH CHECK情况)。

如果为一个表启用了行级安全性但是没有适用的策略存在,将假定为一种 "默认否定"策略,这样任何行都不可见也不可更新。

参数

name

要创建的策略的名称。这必须和该表上已有的任何其他策略名称相区分。

table_name

该策略适用的表的名称(可以被模式限定)。

PERMISSIVE

指定策略被创建为宽容性策略。适用于一个给定查询的所有宽容性策略将被使用布尔"OR"操作符组合在一起。通过创建宽容性策略,管理员可以在能被访问的记录集合中进行增加。策略默认是宽容性的。

RESTRICTIVE

指定策略被创建为限制性策略。适用于一个给定查询的所有限制性策略将被使用布尔"AND"操作符组合在一起。通过创建限制性策略,管理员可以减少能被访问的记录集合,因为每一条记录都必须通过所有的限制性策略。

注意在限制性策略真正能发挥作用减少访问之前,需要至少一条宽容性策略来授予对记录的访问。如果只有限制性策略存在,则没有记录能被访问。当宽容性和限制性策略混合存在时,只有当一个记录能通过至少一条宽容性策略以及所有的限制性策略时,该记录才是可访问的。

command

该策略适用的命令。合法的选项是 ALL、SELECT、INSERT、UPDATE 以及DELETE。ALL为默认。有关这些策略如何被应用的细节见下文。

role_name

该策略适用的角色。默认是PUBLIC,它将把策略应用到所有的角色。

using_expression

任意的SQL条件表达式(返回 boolean)。该条件表达式不能包含任何聚集或者窗口函数。如果行级安全性被启用,这个表达式将被增加到引用该表的查询。 让这个表达式返回真的行将可见。让这个表达式返回假或者空的任何行 将对用户不可见(在SELECT中)并且将对修改不可用( 在UPDATE或DELETE中)。这类行会被悄悄地禁止而不会报告错误。

check_expression

任意的SQL条件表达式(返回 boolean)。该条件表达式不能包含任何聚集或者窗口函数。如果行级安全性被启用,这个表达式将被用在该表上的 INSERT以及 UPDATE查询中。只有让该表达式计算为真的行才被允许。如果任何被插入的记录或者跟新后的记录导致该表达式计算为假或者空,则会抛出一个错误。注意 check_expression 是根据行的新内容而不是原始内容计算的。

针对每种命令的策略

ALL

为一条策略使用ALL表示它将适用于所有命令,不管命令的类型如何。如果存在一条ALL策略以及更多特定的策略,则ALL策略和那些策略会被应用。此外,ALL策略将同时适用于一个查询的选择端和修改端,如果只定义了一个USING表达式则将该USING表达式用于两种情况。

例如,如果发出一个UPDATE,那么ALL策略将同时影响UPDATE能更新哪些行(应用USING表达式)以及更新后的行是否被允许加入到表中(如果定义了WITH CHECK表达式,则应用之;否则使用USING表达式)。如果一条INSERT 或者UPDATE命令尝试增加行到表中,但行没有通过ALL策略的 WITH CHECK表达式,则整个语句将会中断。

SELECT

对一条策略使用SELECT表示它将适用于 SELECT查询,并且无论何时都要求该约束所在的关系上的SELECT权限。其结果是在一次 SELECT查询期间,只有该关系中那些通过了SELECT策略的记录才将被返回,并且查询要求 SELECT权限,例如 UPDATE也将只能看到那些 SELECT策略允许的行。一条 SELECT策略不能具有WITH CHECK表达式,因为它只适用于正在从关系中检索记录的情况。

INSERT

为一条策略使用INSERT表示它适用于 INSERT命令。没有通过这种策略的正在被插入的行会导致策略违背错误,并且整个INSERT命令将会中止。一条INSERT策略不能具有USING表达式,因为它只适用于正在向关系增加记录的情况。

注意在带有ON CONFLICT DO UPDATE的INSERT中,只有对通过 INSERT路径追加到关系的行才会检查 INSERT策略的WITH CHECK 表达式。

UPDATE

对策略使用UPDATE 意味着它将应用于UPDATE、SELECT FOR UPDATE和SELECT FOR SHARE命令,还有INSERT 命令的辅助性的ON CONFLICT DO UPDATE 子句。由于UPDATE 需要提取现有的记录并且用新修改的记录代替,故UPDATE 策略接受USING 表达式和WITH CHECK表达式。USING 表达式决定UPDATE 命令将能看到哪些要对其操作的记录,而WITH CHECK表达式定义哪些被修改的行允许存回到关系中。

任何更新后的值无法通过WITH CHECK表达式的行将会导致错误,并且整个命令将被中止。如果只指定了一个 USING子句,那么该子句将被用于 USING和WITH CHECK两种情况。

典型地,UPDATE命令也需要从待更新关系中的列读数据(例如在WHERE子句、RETURNING子句或在SET子句右侧的表达式中)。这种情况下,正被更新的关系上也需要SELECT权限,并且除了UPDATE策略外,也要应用适当的SELECT或者ALL策略。这样,除由UPDATE或ALL策略授权更新行之外,通过SELECT或ALL策略用也必须能访问正被更新的行。

当INSERT命令附加了ON CONFLICT DO UPDATE子句时,如果采用UPDATE路径,先以任何UPDATE策略的USING表达式检查待更新的行,然后以WITH CHECK表达式检查新修改的行。但要注意的是,不同于单独的UPDATE命令,如果现有的行不能通过USING表达式检查,则抛出错误(UPDATE路径永不会静默地避免)。

DELETE

为一条策略使用DELETE表示它适用于 DELETE命令。只有通过这条策略的行才将能被DELETE命令所看到。如果有的行不能通过该 DELETE策略的USING表达式,则它们可以通过SELECT看到但不能被删除。

大多数情况下,DELETE命令也需要从其所删除的关系中的列读取数据(例如在WHERE子句或RETURNING子句中)。这种情况下,在该关系上也需要SELECT权限,并且除了DELETE策略,也要应用适当的SELECT或ALL策略。这样,除由DELETE或ALL策略授权删除行之外,通过SELECT或ALL策略,用户也必须能访问正被删除的行。

DELETE策略不能具有WITH CHECK表达式,因为它只适用于正在从关系中删除记录的情况,所以没有新行需要检查。

按命令类型应用的策略

命令SELECT/ALL策略 · USING表达式INSERT/ALL策略 · WITH CHECK表达式UPDATE/ALL策略 · USING表达式UPDATE/ALL策略 · WITH CHECK表达式DELETE/ALL策略 · USING表达式
SELECT现有行------------
SELECT FOR UPDATE/SHARE现有行---现有行------
INSERT---新行---------
INSERT .. RETURNING新行新行---------
UPDATE现有&新行---现有行新行---
DELETE现有行---------现有行
ON CONFLICT DO UPDATE现有行&新行---现有行新行---

多重策略的应用

当多种不同命令类型的策略应用于相同命令(例如SELECT和UPDATE策略应用于UPDATE命令)时,用户就必须同时具有这两种类型的权限(例如从关系中选取行和更新的权限)。这样一种策略类型的表达式就与另一种策略类型的表达式通过使用AND操作符组合在一起。

当相同命令类型的多种策略应用于同一命令时,则必须至少有一个PERMISSIVE策略授权对该关系的访问,所有的RESTRICTIVE策略必须通过。这样,所有的PERMISSIVE策略表达式都用OR来组合,所有的RESTRICTIVE策略表达式都用AND来组合,而结果用AND来组合。如果没有PERMISSIVE策略,则拒绝访问。

要注意的是,出于组合多种策略的目的,将ALL策略视为与所应用的任何其他类型的策略具有相同的类型。

例如,在UPDATE命令中,SELECT和UPDATE两种权限都需要,如果每种类型都有多个适用的策略,则将之以下面的方式组合:

expression from RESTRICTIVE SELECT/ALL policy 1

AND

expression from RESTRICTIVE SELECT/ALL policy 2

AND

...

AND

(

expression from PERMISSIVE SELECT/ALL policy 1

OR

expression from PERMISSIVE SELECT/ALL policy 2

OR

...

)

AND

expression from RESTRICTIVE UPDATE/ALL policy 1

AND

expression from RESTRICTIVE UPDATE/ALL policy 2

AND

...

AND

(

expression from PERMISSIVE UPDATE/ALL policy 1

OR

expression from PERMISSIVE UPDATE/ALL policy 2

OR

...

)

注解

要为一个表创建或者修改策略,你必须是该表的拥有者。

虽然策略将被应用于针对数据库中表的显式查询上,但当系统正在执行内部引用完整性检查或者验证约束时不会应用它们。这意味着有间接的方法来决定一个给定的值是否存在。

一个例子是向一个作为主键或者拥有唯一约束的列中尝试插入重复值。如果插入失败则用户可以推导出该值已经存在(这个例子假设用户被策略允许插入他们看不到的记录)。 另一个例子是一个用户被允许向一个引用了其他表的表中插入,然而另一个表是隐藏表。通过用户向引用表中插入值可以判断存在性,成功表示该值存在于被引用表中。为了解决这些问题,应该仔细地制作 策略以完全阻止用户插入、删除或者更新那些可能指示他们不能看到的值的记录,或者使用生成的值(例如代理键)来代替具有外部含义的键。

通常,系统将在应用用户查询中出现的条件之前先强制由安全性策略施加的过滤条件,这是为了防止无意中把受保护的数据暴露给可能不可信 的用户定义函数。不过,被系统(或者系统管理员)标记为 LEAKPROOF的函数和操作符可以在策略表达式之前 被计算,因为它们已经被假定为可信。

因为策略表达式会被直接加到用户查询上,它们将使用运行整个查询的用户的权限运行。

因此,使用一条给定策略的用户必须能够访问表达式中引用的任何表或函数,否则在尝试查询启用了行级安全性的表时,他们将简单地收到一条没有权限的错误。不过,这不会改变视图的工作方式。就普通查询和视图来说,权限检查和视图所引用的表的策略将使用视图拥有者的权限以及任何适用于视图拥有者的策略。

另见

ALTER POLICY, DROP POLICY, ALTER TABLE

CREATE PROCEDURE​

CREATE PROCEDURE --- 定义一个新的过程

大纲

CREATE [ OR REPLACE ] PROCEDURE
name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ]
[, ...] ] )
{ LANGUAGE lang_name
| TRANSFORM { FOR TYPE type_name } [, ... ]
| [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
| SET configuration_parameter { TO value | = value | FROM CURRENT }
| AS 'definition'
| AS 'obj_file', 'link_symbol'
} ...

简介

CREATE PROCEDURE定义一个新的过程。CREATE OR REPLACE PROCEDURE将会创建一个新过程或者替换一个已有的定义。为了能够定义过程,用户必须具有所使用的语言上的USAGE特权。

如果这个命令中包括了一个方案名称,则该过程将被创建在该方案中。否则过程将被创建在当前的方案中。新过程的名称不能匹配同一方案中具有相同输入参数类型的任何现有过程或函数。不过,具有不同参数类型的过程和函数可以共享同一个名称(这被称为重载)。

要替换一个已有过程的当前定义,请使用CREATE OR REPLACE PROCEDURE。不能用这种方式更改过程的名称或者参数类型(如果尝试这样做,实际上会创建一个新的、不同的过程)。

当CREATE OR REPLACE PROCEDURE被用来替换一个现有的过程时,该过程的拥有关系和权限保持不变。所有其他的过程属性会被赋予这个命令中指定的或者暗示的值。必须拥有(包括成为拥有角色的成员)该过程才能替换它。

创建过程的用户将成为该过程的拥有者。

为了能够创建一个过程,用户必须具有参数类型上的USAGE特权。

参数

name

要创建的过程的名称(可以是被方案限定的)。

argmode

参数的模式可以是:IN、INOUT或者VARIADIC。如果省略,则默认为IN(当前对过程不支持OUT参数,可使用INOUT)。

argname

参数的名称。

argtype

过程的参数(如果有)的数据类型(可以是被方案限定的)。参数类型可以是基础类型、组合类型或者域类型,或者可以引用一个表列的类型。

根据具体的实现语言,还可能可以指定"伪类型",例如cstring。伪类型表示实际的参数类型没有完全确定,或者是位于普通SQL数据类型的集合之外。写上table_name.column_name%TYPE可以引用某个列的类型。使用这种特性有时可以让过程不受表定义改变的影响。

default_expr

没有指定参数时要被用作默认值的表达式。这个表达式必须符合该参数的参数类型。跟在有默认值的参数后面的输入参数也都必须有默认值。

lang_name

用于实现该过程的语言名称。它可以是sql、c、internal或者一种用户定义的过程语言的名称,例如plpgsql。将名称包裹在单引号内的方式已经被废弃,并且要求大小写匹配。

**TRANSFORM { FOR TYPE type_name } [, ... ] }**

列出对过程的调用应该应用哪些Transform。Transform负责在SQL类型和语言相关的数据类型之间进行转换,请参考CREATE TRANSFORM。过程语言实现通常采用硬编码的方式保存内建类型的知识,因此它们无需在这里列出。但如果一种过程语言实现不知道如何处理一种类型并且没有提供Transform,它将回退到默认的行为来转换数据类型,但是这依赖于其实现。

**[EXTERNAL] SECURITY INVOKER**
**[EXTERNAL] SECURITY DEFINER**

SECURITY INVOKER指示过程以调用它的用户的特权来执行。这是默认方式。SECURITY DEFINER指定过程以拥有它的用户的特权来执行。

为了符合SQL标注,允许使用EXTERNAL关键词,但它是可选的,因为和SQL中不同,这个特性适用于所有的过程而不仅仅是外部过程。

SECURITY DEFINER过程不能执行事务控制语句(例如COMMIT和ROLLBACK,具体取决于实现的语言)。

configuration_parameter

value

SET子句导致在进入该过程时指定的配置参数被设置为指定的值,并且在过程退出时恢复到之前的值。SET FROM CURRENT把CREATE PROCEDURE执行时该参数的当前值保存为在进入该过程时要应用的值。

如果对过程附加一个SET子句,那么在该过程中为同一个变量执行的SET LOCAL命令的效果就被限制于该过程:在过程退出时还是会恢复到该配置参数的以前的值。不过,一个普通的SET命令(没有LOCAL)会重载这个SET子句,很像它对一个之前的SET LOCAL命令所做的事情:这样一个命令的效果将持续到过程退出之后,除非当前事务被回滚。

如果对过程附加一个SET子句,则该过程不能执行事务控制语句(例

如COMMIT和ROLLBACK,具体取决于实现的语言)。

definition

一个定义该过程的字符串常量,其含义取决于语言。它可以是一个内部的过程名、一个对象文件的路径、一个SQL命令或者以一种过程语言编写的文本。

在编写过程的定义字符串时,使用美元引用(如 $tag$ … $tag$,可避免对单引号转义)而不是普通的单引号语法常常会很有帮助。如果没有美元引用,过程定义中的任何单引号或者反斜线必须以双写的方式进行转义。

obj_file, link_symbol

当C语言源码中的过程名与SQL过程的名称不同时,这种形式的AS子句被用于动态可装载的C语言过程。字符串obj_file是包含已编译好的C过程的共享库文件名,并且被按照LOAD命令的方式解析。字符串link_symbol是该过程的链接符号,也就是该过程在C语言源代码中的名称。如果链接符号被省略,则会被假定为与正在被定义的SQL过程的名称相同。

当重复的CREATE PROCEDURE调用引用同一个对象文件时,只会对每一个会话装载该文件一次。要卸载或者重新载入该文件(可能是在开发期间),应该开始一个新的会话。

注解

函数创建也适用于过程,更多细节请参考CREATE FUNCTION。

使用CALL来执行过程。

示例

CREATE PROCEDURE insert_data(a integer, b integer)
LANGUAGE SQL
AS \$\$
INSERT INTO tbl VALUES (a);
INSERT INTO tbl VALUES (b);
\$\$;
CALL insert_data(1, 2);

另见

ALTER PROCEDURE, DROP PROCEDURE, CALL, CREATE FUNCTION

CREATE PUBLICATION​

CREATE PUBLICATION --- 定义一个新的发布

大纲

CREATE PUBLICATION name
[ FOR TABLE [ ONLY ] table_name [ * ] [, ...]
| FOR ALL TABLES ]
[ WITH ( publication_parameter [= value] [, ... ] ) ]

描述

CREATE PUBLICATION向当前数据库添加一个新的发布。 发布的名称必须与当前数据库中任何现有发布的名称不同。

发布本质上是一组表,其数据更改旨在通过逻辑复制进行复制。

参数

name

新发布的名称。

FOR TABLE

指定要添加到发布的表的列表。如果在表名之前指定了ONLY, 那么只有该表被添加到发布中。如果没有指定ONLY, 则添加表及其所有后代表(如果有的话)。可选地,可以在表名之后指定 *以明确指示包含后代表。但是,这不适用于分区表。 分区表的分区始终被隐式视为发布的一部分,因此永远不会明确将其添加到发布中。

只有持久基表和分区表才能成为出版物的一部分。临时表,未记录表,外部表,物化视图和常规视图不能成为发布的一部分。

将分区表添加到发布时,其所有现有分区和将来分区都被隐式视为发布的一部分。因此,即使直接在分区上执行的操作也会通过其祖先所在的发布来发布。

FOR ALL TABLES

将发布标记为复制数据库中所有表的更改,包括在将来创建的表。

**WITH ( publication_parameter [= value] [, ... ] )**

该子句指定发布的可选参数。支持下列参数:

publish (string)

这个参数决定了哪些DML操作将由新的发布发布给订阅者。该值是用逗号分隔的操作列表。允许的操作是insert,update,delete和truncate。默认是发布所有的动作,所以这个选项的默认值是'insert, update, delete, truncate'。

publish_via_partition_root (boolean)

此参数确定是否会使用分区表的标识和模式而不是实际更改的单个分区的标识和模式来发布发布中包含的分区表(或其分区)中的更改。单个分区的标识和模式是默认设置。启用此功能可以将更改复制到非分区表或由一组不同的分区组成的分区表中。

如果启用此功能,则不会复制直接在分区上执行的TRUNCATE操作。

注意

如果既没有指定FOR TABLE,也没有指定FOR ALL TABLES,那么这个发布就是以一组空表开始的。这在稍后添加表格的情况下是有用的。

创建发布不会开始复制。它只为未来的订阅者定义一个分组和过滤逻辑。

要创建一个发布,调用者必须拥有当前数据库的CREATE权限。(当然,超级用户不需要这个检查。)

要将表添加到发布中,调用者必须拥有该表的所有权。FOR ALL TABLES 子句要求调用者是超级用户。

添加到发布UPDATE和/或DELETE 操作的发布的表必须已经定义了REPLICA IDENTITY。 否则将在这些表上禁止这些操作。

对于INSERT ... ON CONFLICT命令,发布将公布从命令实际产生的操作。因此,根据结果,它可以作为INSERT或UPDATE发布,也可以根本不发布。

COPY ... FROM命令是作为INSERT操作发布的。

不发布DDL操作。

示例

创建一个发布,发布两个表中所有更改布:

CREATE PUBLICATION mypublication FOR TABLE users, departments;

创建一个发布,发布所有表中的所有更改:

CREATE PUBLICATION alltables FOR ALL TABLES;

创建一个发布,只发布一个表中的INSERT操作:

CREATE PUBLICATION insert_only FOR TABLE mydata WITH (publish = 'insert');

CREATE ROLE​

CREATE ROLE --- 定义一个新的数据库角色

大纲

CREATE ROLE name [ [ WITH ] option [ ... ] ]

where option可以是:

SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT connlimit
| [ ENCRYPTED ] PASSWORD 'password' | PASSWORD NULL
| VALID UNTIL 'timestamp'
| IN ROLE role_name [, ...]
| IN GROUP role_name [, ...]
| ROLE role_name [, ...]
| ADMIN role_name [, ...]
| USER role_name [, ...]
| SYSID uid

描述

CREATE ROLE向数据库群集增加一个新的角色。一个角色是一个实体,它可以拥有数据库对象并且拥有数据库特权。根据一个角色如何被使用,它可以被考虑成一个"用户"、一个"组"或者两者。要使用这个命令,你必须具有CREATEROLE特权或者成为一个数据库超级用户。

注意角色是定义在数据库集簇层面上的,并且因此在集簇中的所有数据库中都可用。

参数

name

新角色的名称。

SUPERUSER

NOSUPERUSER

这些子句决定新角色是否是一个"超级用户",它可以越过数据库内的所有访问限制。

超级用户状态很危险并且只应该在确实需要时才用。要创建一个新超级用户,你必须自己是一个超级用户。如果没有指定,默认值是NOSUPERUSER。

CREATEDB

NOCREATEDB

这些子句定义一个角色创建数据库的能力。如果指定了CREATEDB,被定义的角色将被允许创建新的数据库。指定NOCREATEDB将否定一个角色创建数据库的能力。如果没有指定,默认值是NOCREATEDB。

NOCREATEROLE

这些子句决定一个角色是否被允许创建新的角色(也就是执行CREATE ROLE)。一个带有CREATEROLE特权的角色也能修改和删除其他角色。如果没有指定,默认值是NOCREATEROLE。

INHERIT

NOINHERIT

如果新的角色是其他角色的成员,这些子句决定新角色是否从那些角色中"继承"特权,把新角色作为成员的角色称为新角色的父角色。一个带有INHERIT属性的角色能够自动使用已经被授予给其直接或间接父角色的任何数据库特权。如果没有INHERIT,在另一个角色中的成员关系只会把SET ROLE的能力授予给那个其他角色,只有在这样做后那个其他角色的特权才可用。如果没有指定,默认值是INHERIT。

LOGIN

NOLOGIN

这些子句决定一个角色是否被允许登录,也就是在客户端连接期间该角色是否能被给定为初始会话认证名称。一个具有LOGIN属性的角色可以被考虑为一个用户。没有这个属性的角色对于管理数据库特权很有用,但是却不是用户这个词的通常意义。如果没有指定,默认值是NOLOGIN,不过当CREATE ROLE被通过CREATE USER调用时默认值会是LOGIN。

REPLICATION

NOREPLICATION

这些子句决定一个角色是否为复制角色。角色必须具有这个属性(或者成为一个超级用户)才能以复制模式(物理复制或者逻辑复制)连接到服务器以及创建或者删除复制槽。一个具有REPLICATION属性的角色是一个具有非常高特权的角色,并且只应被用于确实需要复制的角色上。如果没有指定,默认值是NOREPLICATION。您必须是超级用户才能创建具有REPLICATION属性的新角色。

BYPASSRLS

NOBYPASSRLS

这些子句决定是否一个角色可以绕过每一条行级安全性(RLS)策略。默认是NOBYPASSRLS。您必须是超级用户才能创建具有BYPASSRLS属性的新角色。

注意 pg_dump 将默认把row_security设置为OFF,以确保一个表的所有内容被转储出来。如果运行 pg_dump 的用户不具有适当的权限,将会返回一个错误。但是,超级用户和被转储表的拥有者总是可以绕过 RLS。

CONNECTION LIMIT connlimit

如果角色能登录,这指定该角色能建立多少并发连接。-1(默认值)表示无限制。注意这个限制仅针对于普通连接。预备事务和后台工作者连接都不受这一限制管辖。

**[ ENCRYPTED ] PASSWORD 'password'**

PASSWORD NULL

设置角色的口令(口令只对具有LOGIN属性的角色有用,但是不管怎样你还是可以为没有该属性的角色定义一个口令)。如果你没有计划使用口令认证,你可以忽略这个选项。如果没有指定口令,口令将被设置为空并且该用户的口令认证总是会失败。也可以用PASSWORD NULL显式地写出一个空口令。

注意:指定一个空字符串也将把口令设置为空!

口令总是以加密的方式存放在系统目录中。ENCRYPTED关键词没有实际效果,它只是为了向后兼容性而存在。加密的方法由配置参数password_encryption决定。如果当前的口令字符串已经是MD5加密或者SCRAM加密的格式,那么不管password_encryption的值是什么,口令字符串还是原样存储(因为系统无法解密以不同格式加密的口令字符串)。这

种方式允许在转储/恢复时重载加密的口令。

VALID UNTIL 'timestamp'

VALID UNTIL机制设置一个日期和时间,在该时间点之后角色的口令将会失效。如果这个子句被忽略,那么口令将总是有效。

IN ROLE role_name

IN ROLE子句列出一个或多个现有的角色,新角色将被立即作为新成员加入到这些角色中(注意没有选项可以把新角色作为一个管理员加入,需要用一个单独的GRANT命令来完成)。

IN GROUP role_name

IN GROUP是IN ROLE的一种已废弃的拼写方式。

ROLE role_name

ROLE子句列出一个或者多个现有角色,它们会被自动作为成员加入到新角色中(这实际上新角色变成了一个"组")。

ADMIN role_name

ADMIN子句与ROLE相似,但是被提及的角色被使用WITH ADMIN OPTION加入到新角色中,让它们能够把这个角色中的成员关系授予给其他人。

USER role_name

USER子句是ROLE子句的一个已废弃的拼写方式。

SYSID uid

SYSID子句会被忽略,但是会为了向后兼容,还是会接受它。

注解

使用ALTER ROLE来更改一个角色的属性,以及使用DROP ROLE来移除一个角色。所有用CREATE ROLE指定的属性可以被后来的ALTER ROLE命令所修改。

增加和移除组角色成员的最佳方式是使用GRANT和REVOKE。

VALID UNTIL子句只为一个口令而不是为一个角色本身定义了一个过期时间。特别地,当使用一个非基于口令认证的方法登录时,过期时间是不会被强制的。

INHERIT属性管理可授予特权(也就是对数据库对象和角色成员关系的访问特权)的继承性。它并不适用于由CREATE ROLE和ALTER ROLE设置的特殊角色属性。例如,作为具有CREATEDB特权的角色的一个成员,并不会立刻授予创建数据库的角色,即便INHERIT被设置也是如此,在创建一个数据库之前必须通过SET ROLE成为该角色。

要小心CREATE ROLE特权。对于一个CREATE ROLE角色的特权没有继承的概念。那意味着即使一个角色没有特定的特权但被允许创建其他角色,它可以轻易地创建与自身特权不同的另一个角色(除了创建具有超级用户特权的角色)。例如,如果角色"user"具有CREATEROLE特权但是没有CREATEDB特权,但是它能够创建一个带有CREATEDB特权的新角色。因此,可以把具

有CREATEROLE特权的角色看成是准超级用户角色。

系统包括一个程序createuser,它具有和CREATE ROLE相同的功能(事实上,它会调用这个命令),但是它可以从命令 shell 中运行。

CONNECTION LIMIT只被近似地强制,如果两个新会话在几乎相同时间被开始,而此时该角色只剩下刚好一个连接"槽",两者可能都将失败。还有,该限制从不对超级用户强制。

用这个命令指定一个非加密口令时必须加以注意。该命令将被以明文的形式传输到服务器,并且它也可能被记录在客户端命令历史或者服务器日志中。不过,命令createuser会传输加密的口令。还有,psql包含一个命令\password,它可以被用来安全地改变该口令。

例子

创建一个能登录但是没有口令的角色:

CREATE ROLE jonathan LOGIN;

创建一个有口令的角色:

CREATE USER davide WITH PASSWORD 'jw8s0F4';

(CREATE USER和CREATE ROLE完全相同,除了它带有LOGIN)。

创建一个角色,它的口令有效期截止到 2004 年底。在进入 2005 年第一秒时,该口令会失效。

CREATE ROLE miriam WITH LOGIN PASSWORD 'jw8s0F4' VALID UNTIL '2005-01-01';

创建一个能够创建数据库并且管理角色的角色:

CREATE ROLE admin WITH CREATEDB CREATEROLE;

参见

SET ROLE, ALTER ROLE, DROP ROLE, GRANT, REVOKE, createuser

CREATE RULE​

CREATE RULE --- 定义一条新的重写规则

大纲

CREATE [ OR REPLACE ] RULE name AS ON event
TO table_name [ WHERE condition ]
DO [ ALSO | INSTEAD ] { NOTHING | command | ( command ; command ... ) }

其中 event 可以是以下之一:

SELECT | INSERT | UPDATE | DELETE

描述

CREATE RULE定义一条应用于指定表或视图的新规则。CREATE OR REPLACE RULE将创建一条新规则或者替换同一个表上具有同一名称的现有规则。

规则系统允许我们定义针对数据库表中插入、更新或者删除动作上的替代动作。大约来说,当在一个给定表上执行给定命令时,一条规则会导致执行额外的命令。或者,INSTEAD规则可以用另一个命令替换给定的命令,或者导致一个命令根本不被执行。规则也被用来实现 SQL 视图。规则实际上是一种命令转换机制或者命令宏。这种转换会在命令的执行开始之前进行。如果你实际上想要为每一个物理行独立地触发一个操作,你可能更需要一个触发器而不是规则。

当前,ON SELECT规则必须是无条件 INSTEAD规则并且其动作必须由一个单一 SELECT命令构成。因此,一条 ON SELECT规则实际上把表变成了一个视图,它的可见内容是由该规则的SELECT命令返回,而不是直接存在该表中的内容(如果有)。不过,使用 CREATE VIEW命令还是要比创建一个真实表并且 在其上定义一条ON SELECT规则更好。

可以通过定义ON INSERT、ON UPDATE 以及ON DELETE规则(或者这些规则的任意子集)来创建可更新的视图,这些规则可以把视图上的更新动作替换为其他表上适当的更新动作。如果想要支持INSERT RETURNING等等,那么一定要在每一个这类规则中放上一个合适的RETURNING子句。

如果你尝试为复杂视图更新使用有条件的规则,有一点是很重要的:对于 你希望在该视图上允许的每一个动作,必须有一条INSTEAD规则。如果该规则是有条件的,或者不是INSTEAD,那么系统仍将拒绝尝试执行该更新动作, 因为它会认为在某些情况下它应该停止尝试在该视图的傀儡表上执行动作。如果你想处理有条件规则中的所有有用的情况,可以增加一条无条件的 DO INSTEAD NOTHING规则来确保系统理解它将 永远不会被调用来更新傀儡表。然后让有条件规则变成 非-INSTEAD。在它们适用的情况下,它们会加到默认的INSTEAD NOTHING动作(不过,当前这种方法不支持RETURNING查询)。

注意:足够简单的视图自动就是可更新的(见CREATE VIEW),它们不需要依靠用户创建的规则来变成可更新的。不过还是可以创建一条显式规则,自动更新转换通常比显式规则效率高。 另一种值得考虑的办法是使用INSTEAD OF触发器(见 CREATE TRIGGER)代替规则。

参数

name

要创建的规则的名称。它必须与同一个表上任何其他规则的名称相区分。同一个表上同一种事件类型的多条规则会按照其名称的字符顺序被应用。

event

时间是SELECT、INSERT、UPDATE或者 DELETE之一。注意包含ON CONFLICT子句的INSERT不能被用在具有INSERT或者 UPDATE规则的表上。那种情况下请考虑使用 可更新的视图。

table_name

规则适用的表或者视图的名称(可以是模式限定的)。

condition

任意的SQL条件表达式(返回 boolean)。该条件表达式不能引用除NEW以及 OLD之外的任何表,并且不能包含聚集函数。

INSTEAD

INSTEAD指示该命令应该取代原始命令被执行。

ALSO

ALSO指示应该在原始命令之外执行这些命令。

如果ALSO和INSTEAD都没有被指定,默认是ALSO。

command

组成规则动作的命令。可用的命令有SELECT、 INSERT、UPDATE、 DELETE或者NOTIFY。

在condition和 command中,名为 NEW和OLD的表可以被用来引用被引用表中的值。在ON INSERT和 ON UPDATE规则中,NEW被用来引用被插入或者更新的新行。在ON UPDATE和 ON DELETE规则中,OLD被用来引用被更新或者删除的现有行。

注解

要在表上创建或者修改规则,必须是表的拥有者。

在一条用于视图上INSERT、UPDATE 或者DELETE的规则中,可以增加一个RETURNING子句来发出视图的列。如果该规则被一个INSERT RETURNING、UPDATE RETURNING或者 DELETE RETURNING命令触发,这个子句将被用来计算输出。当规则被一个没有RETURNING的命令触发时,该规则的 RETURNING子句将被忽略。当前的实现只允许无条件 INSTEAD规则包含RETURNING。此外,用于同一事件的所有规则中至多只能有一个RETURNING子句(这确保了只有一个候选RETURNING子句被用来计算结果)。如果在任何可用规则中都没有RETURNING子句,视图上的RETURNING查询将被拒绝。避免循环规则非常重要。例如,尽管下面的两条规则定义都被系统所接受,SELECT命令将导致系统报告一个错误,因为会产生一条递归规则:

CREATE RULE "_RETURN" AS

ON SELECT TO t1

DO INSTEAD
SELECT * FROM t2;

1465

CREATE RULE
CREATE RULE "_RETURN" AS

ON SELECT TO t2

DO INSTEAD
SELECT * FROM t1;
SELECT * FROM t1;

当前,如果一个规则动作包含一个NOTIFY命令,该NOTIFY命令将被无条件执行,也就是说,即使该规则不被应用到任何行上,也会发出NOTIFY。 例如,在CREATE RULE notify_me AS ON UPDATE TO mytable DO ALSO NOTIFY mytable;

UPDATE mytable SET name = 'foo' WHERE id = 42;

中,UPDATE期间将发出一个 NOTIFY事件,不管是否有行匹配条件 id = 42。这是一种实现限制,它可能会在未来的发行中被修复。

另见

ALTER RULE, DROP RULE

CREATE SCHEMA​

CREATE SCHEMA --- 定义一个新模式

大纲

CREATE SCHEMA schema_name [ AUTHORIZATION role_specification ] [ schema_element [ ... ] ]
CREATE SCHEMA AUTHORIZATION role_specification [ schema_element [ ... ] ]
CREATE SCHEMA IF NOT EXISTS schema_name [ AUTHORIZATION role_specification ]
CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_specification

其中 role_specification 可以是:

user_name
| CURRENT_USER
| SESSION_USER

描述

CREATE SCHEMA输入一个新模式到当前数据库中。该模式名必须与当前数据库中任何现有模式的名称不同。

一个模式本质上是一个名字空间:它包含命令对象(表、数据类型、函数以及操作符),

对象可以与在其他模式中存在的对象重名。可以通过用模式名作为一个前缀 "限定"命名对象的名称来访问它们,或者通过把要求的模式包括 在搜索路径中来访问命名对象。

一个指定非限定对象名的 CREATE命令在当前模式(搜索路径中的第一个模式,由函数current_schema决定)中创建对象。

CREATE SCHEMA中可以选择包括子命令用以在新模式中创建对象。这些子命令实际被当做独立的在创建该模式后被发出的命令一样,除非使用AUTHORIZATION子句,所有被创建的对象都会 由该用户拥有。

参数

schema_name

要创建的一个模式名。如果省略,user_name将被用作模式名。该名称不能以pg_开始,因为这样的名称是用作系统模式的。

user_name

将拥有新模式的用户的角色名。如果省略,默认为执行该命令的用户。要创建由另一个角色拥有的角色,你必须是那个角色的一个直接或者间接成员, 或者是一个超级用户。

schema_element

要在该模式中创建的对象的定义 SQL 语句。当前,只有CREATE TABLE、CREATE VIEW、CREATE INDEX、CREATE SEQUENCE、CREATE TRIGGER以及GRANT被接受为 CREATE SCHEMA中的子句。其他类型的对象可以在模式被 创建之后用单独的命令创建。

IF NOT EXISTS

如果一个具有同名的模式已经存在,则什么也不做(不过发出一个提示)。 使用这个选项时不能包括 schema_element子命令。

注解

要创建一个模式,调用用户必须拥有当前数据库的CREATE 特权(当然,超级用户可以绕过这种检查)。

示例

创建一个模式:

CREATE SCHEMA myschema;

为用户joe创建一个模式,该模式也将被命名为 joe:

CREATE SCHEMA AUTHORIZATION joe;

创建一个被用户joe拥有的名为test的模式,除非已经有一个名为test的模式(不管joe是否拥有该已经存在的模式)。

CREATE SCHEMA IF NOT EXISTS test AUTHORIZATION joe;

创建一个模式并且在其中创建一个表和视图:

CREATE SCHEMA hollywood
CREATE TABLE films (title text, release date, awards text[])
CREATE VIEW winners AS
SELECT title, release FROM films WHERE awards IS NOT NULL;

注意子命令不以分号结束。

下面是达到相同结果的等效的方法:

CREATE SCHEMA hollywood;
CREATE TABLE hollywood.films (title text, release date, awards text[]);
CREATE VIEW hollywood.winners AS
SELECT title, release FROM hollywood.films WHERE awards IS NOT NULL;

另见

ALTER SCHEMA, DROP SCHEMA

CREATE SEQUENCE​

CREATE SEQUENCE --- 定义一个新的序列发生器

大纲

CREATE [ TEMPORARY | TEMP ] SEQUENCE [ IF NOT EXISTS ] name [ INCREMENT
[ BY ] increment ]
[ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
[ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]
[ OWNED BY { table_name.column_name | NONE } ]

描述

CREATE SEQUENCE创建一个新的序列数发生器。这涉及到用名称name创建并且初始化一个新的特殊的单行表。该发生器将由发出该命令的用户所拥有。

如果给出一个模式名称,则该序列将将被创建在指定的模式中。否则它会被 创建在当前模式中。临时序列存在于一个特殊的模式中,因此在创建临时序列时不能给出模式名。序列名称必须与同一模式中任何其他序列、表、索引、 视图或者外部表的名称不同。

在序列被创建后,可以使用函数 nextval、 currval以及 setval来操作该序列。

尽管无法直接更新一个序列,可以使用这样的查询:

SELECT * FROM name;

来检查一个序列的参数以及当前状态。特别地,序列的 last_value域显示被任意会话最后一次取得的值(当然,在被打印时该值可能已经过时了,因为可能有其他会话正在执行nextval调用)。

参数

TEMPORARY or TEMP

如果被指定,只会为这个会话创建序列对象,并且在会话退出时自动删除它。当临时序列存在时,已有的同名永久序列(在这个会话中) 会变得不可见,不过可以用模式限定的名称来引用同名永久序列。

IF NOT EXISTS

如果已经存在一个同名的关系时不要抛出错误。这种情况下会发出一个提示。注意这不保证现有的关系与即将创建的序列相似 --- 它甚至可能 都不是一个序列。

name

要创建的序列的名称(可以是模式限定的)。

data_type

可选的子句AS data_type 制定序列的数据类型。有效类型是 smallint、integer、和bigint。默认是bigint。 数据类型决定了序列的默认最小和最大值。

increment

可选的子句INCREMENT BY increment指定为了创建新值会把哪个值加到当前序列值上。

一个正值将会创造一个上升序列,负值会创造一个下降序列。默认值是1。

minvalue

NO MINVALUE

可选的子句MINVALUE minvalue决定一个序列能产生的最小值。如果没有提供这个子句或者指定了 NO MINVALUE,那么会使用默认值。升序序列的默认值为1。降序序列的默认值为数据类型的最小值。

maxvalue

NO MAXVALUE

可选的子句MAXVALUE maxvalue决定该序列的最大值。如果没有提供这个子句或者指定了 NO MAXVALUE,那么将会使用默认值。升序序列的默认值是数据类型的最大值。降序序列的默认值是-1。

start

可选的子句START WITH start 允许序列从任何地方开始。对于上升序列和下降序列来说,默认的开始值分别是 minvalue和 maxvalue。

cache

可选的子句CACHE cache指定要预分配多少个序列数并且把它们放在内存中以便快速访问。最小值为1(一次只生成 一个值,即没有缓存),默认值也是 1。

CYCLE

NO CYCLE

对于上升序列和下降序列,CYCLE选项允许序列在分别达到maxvalue和minvalue时回卷。如果达到该限制,下一个产生的数字将分别是minvalue和maxvalue。

如果指定了NO CYCLE,当序列到达其最大值后任何nextval调用将返回一个错误。如果CYCLE和NO CYCLE都没有被指定,则默认为NO CYCLE

OWNED BY table_name.column_name

OWNED BY NONE

OWNED BY选项导致序列被与一个特定的表列关联在一起,这样如果该列(或者整个表)被删除,该序列也将被自动删除。指定的表必须和序列具有相同的拥有者并且在同一个模式中。默认选项 OWNED BY NONE指定该序列不与某个列关联。

注解

使用DROP SEQUENCE移除一个序列。

序列是基于bigint算法的,因此范围是不能超过一个八字节整数的范围

(-9223372036854775808 到 9223372036854775807)。

由于nextval和setval调用绝不会回滚, 如果需要序数的"无间隙"分配,则不能使用序列对象。可以通过在一个只包含一个计数器的表上使用排他锁来构建无间隙的分配,但是这种方案比序列对象开销更大,特别是当有很多事务并发请求序数时。

如果对一个将由多个会话并发使用的序列对象使用了大于 1 的cache设置,可能会得到意想不到的结果。每个会话会在访问该序列对象时分配并且缓存后续的序列值,并且相应地增加该序列对象的last_value。然后,在该会话中下一次 nextval会做 cache-1,并且简单地返回预分配的值而不修改序列对象。因此,任何已分配但没有在会话中使用的数字将会在该会话结束时丢失,导致该序列中的"空洞"。

进一步,尽管多个会话能分配到不同的序列值,这些值可能会在所有会话都被考虑时生成出来。例如, cache的设置为 10,会话 A 可能储存值 1..10 并且返回nextval=1,然后会话 B 可能储存值 11..20 并且在 A 生成nextval=2 之前返回 nextval=11。因此,如果cache设置为 1,可以 安全地假设nextval值被顺序地生成。如果cache设置大于 1,就只能假定 nextval值都是可区分的,但不能保证它们被完全地顺序生成。还有,last_value将反映服务于任意会话的最后一个值,不管它是否已经被nextval返回过。另一个考虑是,在这样一个序列上执行的setval将不会通知 其他会话,直到它们用尽了任何已缓存的预分配值。

示例

创建一个称作serial的上升序列,从 101 开始:

CREATE SEQUENCE serial START 101;

从这个序列中选取下一个数字:

SELECT nextval('serial');
nextval
---------
101

再从这个序列中选取下一个数字:

SELECT nextval('serial');
nextval
---------
102

在一个INSERT命令中使用这个序列:

INSERT INTO distributors VALUES (nextval('serial'), 'nothing');

在一次COPY FROM后更新新列值:

BEGIN;
COPY distributors FROM 'input_file';
SELECT setval('serial', max(id)) FROM distributors;
END;

另见

ALTER SEQUENCE, DROP SEQUENCE

CREATE SERVER​

CREATE SERVER --- 定义一个新的外部服务器

大纲

CREATE SERVER [ IF NOT EXISTS ] server_name [ TYPE 'server_type' ] [ VERSION 'server_version' ]
FOREIGN DATA WRAPPER fdw_name
[ OPTIONS ( option 'value' [, ... ] ) ]

描述

CREATE SERVER定义一个新的外部服务器。 定义该服务器的用户会成为拥有者。

外部服务器通常包装了外部数据包装器用来访问一个外部数据源所需的 连接信息。额外的用户相关的连接信息可以通过用户映射的方式来指定。

服务器名称在数据库中必须唯一。

创建服务器要求所使用的外部数据包装器上的USAGE特权。

参数

IF NOT EXISTS

如果已经存在同名的服务器,不要抛出错误。在这种情况下发出一个通知。 请注意,不能保证现有服务器与要创建的服务器类似。

server_name

要创建的外部服务器的名称。

server_type

可选的服务器类型,可能对外部数据包装器有用。

server_version

可选的服务器版本,可能对外部数据包装器有用。

fdw_name

管理该服务器的外部数据包装器的名称。

**OPTIONS ( option 'value' [, ... ] )**

这个子句为服务器指定选项。这些选项通常定义该服务器的连接细节,但是实际的名称和值取决于该服务器的外部数据包装器。

注解

在使用dblink模块时,一个外部服务器的名称可以被用作dblink_connect函数的一个参数来指示连接参数。以这种方式使用外部服务器,需要在其上具有 USAGE特权。

示例

创建使用外部数据包装器oracle_fdw 的服务器myserver:

CREATE SERVER myserver FOREIGN DATA WRAPPER oracle_fdw OPTIONS (host 'foo', dbname 'foodb', port '1521');

另见

ALTER SERVER, DROP SERVER, CREATE FOREIGN DATA WRAPPER, CREATE FOREIGN TABLE, CREATE USER MAPPING

CREATE STATISTICS​

CREATE STATISTICS --- 定义扩展统计

大纲

CREATE STATISTICS [ IF NOT EXISTS ] statistics_name
[ ( statistics_kind [, ... ] ) ]
ON column_name, column_name [, ...]
FROM table_name

描述

CREATE STATISTICS将创建一个新的扩展统计对象,追踪指定表、外部表或物化视图的数据。该统计对象将在当前数据库中创建,被发出该命令的用户所有。

如果给定了模式名(比如,CREATE STATISTICS myschema.mystat ...), 那么在给定的模式中创建统计对象。否则在当前模式中创建。统计对象的名称必须与相同模式中的任何其他统计对象不同。

参数

IF NOT EXISTS

如果具有相同名称的统计对象已经存在,不会抛出一个错误,只会发出一个提示。请注意,这里只考虑统计对象的名称,不考虑其定义细节。

statistics_name

要创建的统计对象的名称(可以有模式限定)。

statistics_kind

在此统计对象中计算的统计种类。目前支持的种类是启用n-distinct统计的

ndistinct,启用功能依赖性统计的dependencies,以及启用最常见的值列表的mcv。如果省略该子句,则统计对象中将包含所有支持的统计类型。

column_name

被计算的统计信息包含的表格列的名称。至少必须给出两个列名,列名的顺序可以忽略。

table_name

包含计算统计信息的列的表的名称(可以是模式限定的)。

注意

你必须是表的所有者才能创建读取它的统计对象。不过,一旦创建,统计对象的所有权与基础表无关。

示例

用两个功能相关的列创建表t1,即第一列中的值的信息足以确定另一列中的值。然后,在这些列上构建函数依赖关系统计信息:

CREATE TABLE t1 (
a int,
b int
);
INSERT INTO t1 SELECT i/100, i/500
FROM generate_series(1,1000000) s(i);
ANALYZE t1;
-- 匹配行的数量将被大大低估:
EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0);
CREATE STATISTICS s1 (dependencies) ON a, b FROM t1;
ANALYZE t1;
-- 现在行计数估计会更准确:
EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0);

如果没有函数依赖性统计,规划器会认为两个WHERE条件是独立的,并且会将它们的选择性乘以一起,以致得到太小的行数估计。 通过这样的统计,规划器认识到WHERE条件是多余的,并且不会低估行数。

创建表t2与两个完全相关的列(包含相同的数据),并且在这些列上创建一个MCV列表:

CREATE TABLE t2 (
a int,
b int
);
INSERT INTO t2 SELECT mod(i,100), mod(i,100)
FROM generate_series(1,1000000) s(i);
CREATE STATISTICS s2 (mcv) ON a, b FROM t2;
ANALYZE t2;
-- valid combination (found in MCV)
EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 1);
-- invalid combination (not found in MCV)
EXPLAIN ANALYZE SELECT * FROM t2 WHERE (a = 1) AND (b = 2);

MCV列表为计划器提供了关于表中普遍出现的特定值的更详细的信息,以及表中未显示的值组合的选择性上限,允许它在这两种情况下产生更好的估计值。

又见

ALTER STATISTICS, DROP STATISTICS

CREATE SUBSCRIPTION​

CREATE SUBSCRIPTION --- 定义一个新的订阅

大纲

CREATE SUBSCRIPTION subscription_name
CONNECTION 'conninfo'
PUBLICATION publication_name [, ...]
[ WITH ( subscription_parameter [= value] [, ... ] ) ]

描述

CREATE SUBSCRIPTION为当前数据库添加一个新的订阅。订阅名称必须与数据库中任何现有的订阅不同。

订阅表示到发布者的复制连接。因此,此命令不仅在本地目录中添加定义, 还会在发布者上创建复制插槽。

在运行此命令的事务提交时,将启动逻辑复制工作器以复制新订阅的数据。

参数

subscription_name

新订阅的名称。

CONNECTION 'conninfo'

连接发布者的字符串。

PUBLICATION publication_name

要订阅的发布者上的发布名称。

**WITH ( subscription_parameter [= value] [, ... ] )**

该子句指定订阅的可选参数。支持的参数有:

copy_data (boolean)

指定在复制启动后是否应复制正在订阅的发布中的现有数据。默认值是true。

create_slot (boolean)

指定该命令是否要在发布者上创建复制槽。默认值是true。

enabled (boolean)

指定订阅是否应该主动复制,或者是否应该只是设置,但尚未启动。默认值

是true。

slot_name (string)

要使用的复制插槽的名称。默认行为是使用订阅名称作为插槽的名称。

当slot_name设置为NONE时, 将不会有复制槽与订阅关联。这在需要稍后手动设置复制槽的情况下会使用。这样的订阅必须同时enabled并且 create_slot设置为false。

synchronous_commit (enum)

该参数的值会覆盖synchronous_commit设置。默认值是off。

对于逻辑复制使用off是安全的:如果订阅者由于缺少同步而丢失事务,数据将从发布者再次发送。

进行同步逻辑复制时,不同的设置可能是合适的。逻辑复制工作者向发布者报告写入和刷新的位置,当使用同步复制时,发布者将等待实际刷新。这意味着,当订阅用于同步复制时,将订阅者的synchronous_commit设置为off 可能会增加发布服务器上COMMIT的延迟。在这种情况下,将synchronous_commit设置为 local或更高是有利的。

connect (boolean)

指定CREATE SUBSCRIPTION是否应该连接到发布者。将其设置为false将会改变默认值enabled、create_slot和copy_data为false。

不允许将connect设置为false的同时将 enabled、create_slot或copy_data 设置为true。

因为该选项设置为false时不会建立连接,因此表没有被订阅,所以当启用订阅后,不会复制任何内容。 需要运行ALTER SUBSCRIPTION ... REFRESH PUBLICATION才能订阅表。

注意

创建复制槽时(默认行为), CREATE SUBSCRIPTION不能在事务块内部执行。

如果复制插槽不是作为同一命令的一部分创建的,则创建连接到相同数据库集群的订阅(例如,在同一集群中的数据库之间进行复制或在同一个数据库中进行复制)只能成功否则,CREATE SUBSCRIPTION调用将挂起。要做到这一点,单独创建复制插槽(使用函数pg_create_logical_replication_slot 和插件名称pgoutput),并使用参数create_slot = false 创建订阅。这是一个实施限制,可能会在未来的版本中解除。

示例

创建一个到远程服务器的订阅,复制发布mypublication和insert_only中的表,并在提交时立即开始复制:

CREATE SUBSCRIPTION mysub
CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb'
PUBLICATION mypublication, insert_only;

创建一个到远程服务器的订阅,复制insert_only发布中的表,并且不开始复制直到稍后启用复制。

CREATE SUBSCRIPTION mysub
CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb'
PUBLICATION insert_only
WITH (enabled = false);

又见

ALTER SUBSCRIPTION, DROP SUBSCRIPTION, CREATE PUBLICATION, ALTER PUBLICATION

CREATE TABLE​

CREATE TABLE --- 定义一个新表

大纲

CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT
EXISTS ] table_name ( [
{ column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]
| table_constraint
| LIKE source_table [ like_option ... ] }
[, ... ]
] )
[ INHERITS ( parent_table [, ... ] ) ]
[ PARTITION BY { RANGE | LIST | HASH } ( { column_name | ( expression ) }
[ COLLATE collation ] [ opclass ] [, ... ] ) ]
[ USING method ]
[ WITH ( storage_parameter [= value] [, ... ] ) | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE tablespace_name ]
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT
EXISTS ] table_name
OF type_name [ (
{ column_name [ WITH OPTIONS ] [ column_constraint [ ... ] ]
| table_constraint }
[, ... ]
) ]
[ PARTITION BY { RANGE | LIST | HASH } ( { column_name | ( expression ) }
[ COLLATE collation ] [ opclass ] [, ... ] ) ]
[ USING method ]
[ WITH ( storage_parameter [= value] [, ... ] ) | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE tablespace_name ]
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT
EXISTS ] table_name
PARTITION OF parent_table [ (
{ column_name [ WITH OPTIONS ] [ column_constraint [ ... ] ]
| table_constraint }
[, ... ]
) ] { FOR VALUES partition_bound_spec | DEFAULT }
[ PARTITION BY { RANGE | LIST | HASH } ( { column_name | ( expression ) }
[ COLLATE collation ] [ opclass ] [, ... ] ) ]
[ USING method ]
[ WITH ( storage_parameter [= value] [, ... ] ) | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE tablespace_name ]

其中 column_constraint 是:

[ CONSTRAINT constraint_name ]
{ NOT NULL |
NULL |
CHECK ( expression ) [ NO INHERIT ] |
DEFAULT default_expr |
GENERATED ALWAYS AS ( generation_expr ) STORED |
GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ] |
UNIQUE index_parameters |
PRIMARY KEY index_parameters |
REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH
SIMPLE ]
[ ON DELETE referential_action ] [ ON UPDATE referential_action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

table_constraint 是:

[ CONSTRAINT constraint_name ]
{ CHECK ( expression ) [ NO INHERIT ] |
UNIQUE ( column_name [, ... ] ) index_parameters |
PRIMARY KEY ( column_name [, ... ] ) index_parameters |
EXCLUDE [ USING index_method ] ( exclude_element WITH operator
[, ... ] ) index_parameters [ WHERE ( predicate ) ] |
FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn
[, ... ] ) ]
[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE referential_action
] [ ON UPDATE referential_action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

like_option 是:

{ INCLUDING | EXCLUDING } { COMMENTS | CONSTRAINTS | DEFAULTS | GENERATED |
IDENTITY | INDEXES | STATISTICS | STORAGE | ALL }

partition_bound_spec 是:

IN ( partition_bound_expr [, ...] ) |
FROM ( { partition_bound_expr | MINVALUE | MAXVALUE } [, ...] )
TO ( { partition_bound_expr | MINVALUE | MAXVALUE } [, ...] ) |
WITH ( MODULUS numeric_literal, REMAINDER numeric_literal )

UNIQUE、PRIMARY KEY以及EXCLUDE约束中的index_parameters是:

[ INCLUDE ( column_name [, ... ] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) ]
[ USING INDEX TABLESPACE tablespace_name ]

一个EXCLUDE约束中的exclude_element是:

{ column_name | ( expression ) } [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]

描述

CREATE TABLE将在当前数据库中创建一个新的、初始为空的表。该表将由发出该命令的用户所拥有。

如果给定了一个模式名(例如CREATE TABLE myschema.mytable ...),那么该表被创建在指定的模式中。否则它被创建在当前模式中。临时表存在于一个特殊的模式中,因此在创建一个临时表时不能给定一个模式名。该表的名称必须与同一个模式中的任何其他表、序列、索引、视图或外部表的名称区分开。

CREATE TABLE也会自动地创建一个数据类型来表示对应于该表一行的组合类型。因此,表不能用同一个模式中任何已有数据类型的名称。

可选的约束子句指定一个插入或更新操作要成功,新的或更新过的行必须满足的约束(测试)。一个约束是一个 SQL 对象,它帮助以多种方式定义表中的合法值集合。

有两种方式来定义约束:表约束和列约束。一个列约束会作为列定义的一部分定义。一个约束定义不与一个特定列绑定,并且它可以包含多于一个列。每一个列约束也可以被写作一个表约束,列约束只是一种当约束只影响一列时方便书写的记号习惯。

要能创建一个表,你必须分别具有所有列类型或OF子句中类型的USAGE特权。

参数

TEMPORARY or TEMP

如果指定,该表被创建为一个临时表。临时表会被在会话结束时自动被删除,或者也可以选择在当前事务结束时删除(见下文的ON COMMIT)。当临时表存在时,已有的同名持久表将对于当前会话不可见,不过可以使用模式限定的名称进行引用。在一个临时表上创建的任何索引也自动地变为临时的。

自动清理守护进程不能访问并且因此也不能清理或分析临时表。由于这个原因,应该通过会话的 SQL 命令执行合适的清理和分析操作。例如,如果一个临时表将要被用于复杂的查询,最好在把它填充完毕后在其上运行ANALYZE。

可以选择将GLOBAL或LOCAL写在TEMPORARY或TEMP的前面。

UNLOGGED如果指定,该表被创建为一个不受日志记录的表。被写入到不做日志的表中的数据不会被写到预写式日志中,这让它们比普通表快非常多。不过,它们在崩溃时是不安全的:一个不做日志的表在一次崩溃或非干净关闭之后会被自动地截断。一个不做日志的表中的内容也不会被复制到后备服务器中。在一个不做日志的表上创建的任何索引也会自动地不被日志记录。

IF NOT EXISTS

如果一个同名关系已经存在,不要抛出一个错误。在这种情况下会发出一个提示。注意这不保证现有的关系是和将要被创建的表相似的东西。

table_name

要被创建的表名(可以选择用模式限定)。

OF type_name

创建一个类型化的表,它的结构取自于指定的组合类型(名字可以选择用模式限定)。

一个类型化的表和它的类型绑定在一起,例如如果类型被删除,该表也将被删除(用DROP TYPE ... CASCADE)。

当一个类型化的表被创建时,列的数据类型由底层的组合类型决定而没有在CREATE TABLE命令中直接指定。但是CREATE TABLE命令可以对表增加默认值和约束,并且可以指定存储参数。

column_name

列的名称会在新表中被建立.

data_type

列的数据类型. 这可以包括数组规格.

COLLATE collation

COLLATE子句为该列(必须是一种可排序数据类型)赋予一个排序规则。 如果没有指定,将使用该列数据类型的默认排序规则。

**INHERITS ( parent_table [, ... ] )**

可选的INHERITS子句指定一个表的列表,新表将从其中自动地继承所有列。父表可以是普通表或者外部表。

INHERITS的使用在新的子表和它的父表之间创建一种持久的关系。 对于父表的模式修改通常也会传播到子表,并且默认情况下子表的数据会被包括在对父表的扫描中。

如果在多个父表中存在同名的列,除非父表中每一个这种列的数据类型都能匹配,否则会报告一个错误。如果没有冲突,那么重复列会被融合来形成新表中的一个单一列。如果新表中的列名列表包含一个也是继承而来的列名,该数据类型必须也匹配继承的列,并且列定义会被融合成一个。如果新表显式地为列指定了任何默认值,这个默认值将覆盖来自该列继承声明中的默认值。否则,任何父表都必须为该列指定相同的默认值,或者会报告一个错误。

CHECK约束本质上也采用和列相同的方式被融合:如果多个父表或者新表定义中包含相同的命名CHECK约束, 这些约束必须全部具有相同的检查表达式,否则将报告一个错误。具有相同名称和表达式的约束将被融合成一份拷贝。一个父表中的被标记为NO INHERIT的约束将不会被考虑。注意新表中一个未命名的CHECK约束将永远不会被融合,因为那样总是会为它选择一个唯一的名字。列的STORAGE设置也会从父表复制过来。

如果父表中的列是标识列,那么该属性不会被继承。 如果需要,可以将子表中的列声明为标识列。

PARTITION BY { RANGE | LIST | HASH } ( { column_name | ( expression ) } [ opclass ] [, ...] )

可选的PARTITION BY子句指定了对表进行分区的策略。这样创建的表称为分区表。带括号的列或表达式的列表构成表的分区键。使用范围或哈希分区时,分区键可以包含多个列或表达式(最多32个),但对于列表分区,分区键必须由单个列或表达式组成。

范围和列表分区需要 btree 运算符类,而哈希分区需要哈希运算符类。如果没有运算符类被显式指定,将使用相应类型的默认运算符类; 如果不存在默认运算符类,则将引发错误。使用哈希分区时,所使用的运算符类必须实现支持功能。

分区表被分成多个子表(称为分区),它们是使用单独的CREATE TABLE命令创建的。分区表本身是空的。插入到表中的数据行将根据分区键中的列或表达式的值路由到分区。如果没有现有的分区与新行中的值匹配,则会报告错误。

分区表不支持EXCLUDE约束; 但是,你可以在各个分区上定义这些约束。

PARTITION OF parent_table { FOR VALUES partition_bound_spec | DEFAULT }

将表创建为指定父表的分区。该表建立时,可以使用FOR VALUES创建为特定值的分区,也可以使用DEFAULT创建默认分区。父表中存在的任何索引、 约束和用户定义的行级触发器都将克隆到新分区上。

partition_bound_spec 必须对应于父表的分区方法和分区键,并且必须不能与该父表的任何现有分区重叠。具有IN的形式用于列表分区,具有FROM和TO的形式用于范围分区,具有WITH的形式用于哈希分区。

partition_bound_expr是任何无变量表达式(不允许子查询、窗口函数、聚合函数和集返回函数)。它的数据类型必须与相应分区键列的数据类型相匹配。 表达式在表创建时只计算一次,因此它甚至可以包含易失性表达式,如CURRENT_TIMESTAMP。

在创建列表分区时,可以指定NULL来表示分区允许分区键列为空。但是,给定父表不能有多于一个这样的列表分区。无法为范围分区指定 NULL。

创建范围分区时,由FROM指定的下限是一个包含范围,而用TO指定的上限是排除范围。

也就是说,在FROM列表中指定的值是该分区的相应分区键列的有效值, 而TO列表中的值不是。例如给定PARTITION BY RANGE (x,y),分区范围 FROM (1, 2) TO (3, 4)允许x=1与任何y>=2,x=2与任何非空y,和x=3与任何y<4。

在创建范围分区以指示列值没有下限或上限时,可以使用特殊值MINVALUE 和MAXVALUE。

例如,使用FROM (MINVALUE) TO (10) 定义的分区允许任何小于10的值,并且使用FROM (10) TO (MAXVALUE) 定义的分区允许任何大于或等于10的值。

创建涉及多个列的范围分区时,将MAXVALUE作为下限的一部分并将 MINVALUE作为上限的一部分也是有意义的。例如,使用 FROM (0, MAXVALUE) TO (10, MAXVALUE) 定义

的分区允许第一个分区键列大于0且小于或等于10的任何行。类似地,使用FROM ('a', MINVALUE) TO ('b', MINVALUE)定义的分区允许第一个分区键列以"a"开头的任何行。

请注意,如果MINVALUE或MAXVALUE用于分区边界的一列,则必须为所有后续列使用相同的值。例如,(10, MINVALUE, 0) 不是有效的边界;你应该写(10, MINVALUE, MINVALUE)。

还要注意,某些元素类型,如timestamp,具有"无穷"的概念,这只是另一个可以存储的值。这与MINVALUE和MAXVALUE不同,它们不是可以存储的实际值,而是它们表示值无界的方式。MAXVALUE 可以被认为比任何其他值(包括"无穷")都大的值,MINVALUE 可以被认为是比任何其他值(包括"负无穷")都小的值。因此,范围FROM ('infinity') TO (MAXVALUE)不是空的范围;它只允许存储一个值---"infinity"。

如果指定了DEFAULT,则表将创建为父表的默认分区。此选项不适用于哈希分区表。不适合给定父级表的任何其他分区的分区键值将路由到默认分区。

当一个表已有DEFAULT 分区并且要对它添加新分区时,必须扫描默认分区以验证它不包含可能属于新分区的任何行。如果默认分区包含大量行,则速度可能会很慢。如果默认分区是外表或者它具有可证明的不可能包含能放置在新分区中的行的约束,则将略过扫描当创建哈希分区时,必须指定模数和余数。 模数必须是正整数,余数必须是小于模数的非负整数。通常情况下,当初始设置哈希分区表时,应选择一个与分区数相等的模数,并为每个表分配相同的模数和不同的余数(请参阅下方示例)。不过,并不要求每个分

区都具有相同的模数,只要求哈希分区表里面的分区中出现的每个模数都是下一个较大模数的因数。这允许以增量的方式增加分区数量而不需要一次移动所有数据。 例如,假设你有一个包含 8 个分区的哈希分区表,每个分区有模数8,但发现有必要将分区数增加到 16 个。您可以拆分其中一个模数-8分区,然后创建两个新的模数-16分区来覆盖键空间的相同部分(一个的余数等于被拆分的分区的余数,另一个的余数等于该值加8),而后用数据重新填充他们。然后,你可以对每一个余数-8分区重复此操作过程,直到没有剩余。 虽然这其中的每个步骤都可能会导致大量的数据移动操作,它仍然要好于建一个全新的表并一次移动全部数据。

分区必须与其所属的分区表的字段名和类型相同。对分区表字段名或类型的修改,将自动传播到所有分区。CHECK约束将自动被每一个分区继承,但是单独的分区可以指定额外的CHECK约束;与父表相同名称和条件的额外约束将被父表约束合并。可以为每个分区分别指定默认值。但是请注意,在通过分区表插入元组时不会应用分区的默认值。

插入分区表中的行将自动路由到正确的分区。如果不存在合适的分区,则会发生错误。

像TRUNCATE这样的操作通常会影响一个表及其所有继承子级,这些操作将级联到所有分区,但也可能在单个分区上执行。请注意,使用DROP TABLE 删除分区需要在父表上采用ACCESS EXCLUSIVE锁。

**LIKE source_table [ like_option ... ]**

LIKE指定新表将从哪一个表自动地复制所有的列名、数据类型以及它们的非空约束。

和INHERITS不同,新表和原始表在创建完成之后是完全分离的。对原始表的更改将不会被应用到新表,并且不可能在原始表的扫描中包括新表的数据。

同样与INHERITS不同,用LIKE拷贝的列和约束不会和相似的命名列及约束融合。如果显式指定了相同的名称或者在另一个LIKE子句中指定了相同的名称,将会发出一个错误。

可选的like_option子句指定要复制的原始表的附加属性。指定 INCLUDING 复制该属性,指定 EXCLUDING 忽略该属性。EXCLUDING为默认值。 如果对同一类型的对象指定了多个规范,则使用最后一个规范。可用的选项包括:

INCLUDING COMMENTS

复制的列、约束和索引的注释将被复制。默认行为是去除注释,从而导致新表中复制的列和约束没有注释。

INCLUDING CONSTRAINTS

CHECK约束将被复制。列约束和表约束之间没有区别。非空约束始终复制到新表。

INCLUDING DEFAULTS

复制列定义的默认表达式将被复制。否则,不会复制默认表达式,从而导致新表中复制的列具有空默认值。注意,复制调用数据库修改函数的默认值,例如nextval,可能在原始表和新表之间创建功能联系。

INCLUDING GENERATED

列定义的任何生成表达式将被复制。默认情况下,新列将是常规基本列。

INCLUDING IDENTITY

已复制列定义的任何标识规范都将被复制。为新表的每个标识列创建一个新序列,与与旧表关联的序列分开。

INCLUDING INDEXES

原始表上的索引、PRIMARY KEY、 UNIQUE和 EXCLUDE约束将被建立在新表上。根据默认规则选择新索引和约束的名称,而不考虑原始的命名。(此行为可避免新索引可能出现重复名称失败。)

INCLUDING STATISTICS

扩展统计信息将复制到新表。

INCLUDING STORAGE

已复制列定义的STORAGE设置将被复制。默认行为是排除STORAGE设置,从而导致新表中已复制列具有类型规定的默认设置。

INCLUDING ALL

INCLUDING ALL 是选择所有可用的单独选项的缩写形式。(它能被用于在INCLUDING ALL之后写单独的EXCLUDING子句,以选择部分指定选项之外的所有选项。)

LIKE子句也能被用来从视图、外部表或组合类型拷贝列定义。不适合的选项(例如来自视图的INCLUDING INDEXES)会被忽略。

CONSTRAINT constraint_name

一个列约束或表约束的可选名称。如果该约束被违背,约束名将会出现在错误消息中,这样类似列必须为正的约束名可以用来与客户端应用沟通有用的约束信息(指定包含空格的约束名时需要用到双引号)。如果没有指定约束名,系统将生成一个。

NOT NULL

该列不允许包含空值。

NULL

该列允许包含空值。这是默认情况。

这个子句只是提供与非标准 SQL 数据库的兼容。在新的应用中不推荐使用。

**CHECK ( expression ) [ NO INHERIT ]**

CHECK指定一个产生布尔结果的表达式,一个插入或更新操作要想成功,其中新的或被更新的行必须满足该表达式。计算出 TRUE 或 UNKNOWN 的表达式就会成功。只要任何一个插入或更新操作的行产生了 FALSE 结果,将报告一个错误异常并且插入或更新不会修改数据库。一个被作为列约束指定的检查约束只应该引用该列的值,而一个出现在表约束中的表达式可以引用多列。当前,CHECK表达式不能包含子查询,也不能引用当前行的列之外的变量。可以引用系统列tableoid,但不能引用其他系统列。

一个被标记为NO INHERIT的约束将不会传播到子表。

当一个表有多个CHECK约束时,检查完NOT NULL约束后,对于每一行会以它们名称的字母顺序来进行检查。

DEFAULT default_expr

DEFAULT子句为出现在其定义中的列赋予一个默认数据。该值是可以使用变量的表达式(特别是,不允许用对其他列的交叉引用)。子查询也是不允许的。默认值表达式的数据类型必须匹配列的数据类型。

默认值表达式将被用在任何没有为该列指定值的插入操作中。如果一列没有默认值,那么默认值为空值。

GENERATED ALWAYS AS ( generation_expr ) STORED

此子句将列创建为generated column。 列无法被写入,读取时将返回指定表达式的结果。

关键字STORED表示将在写入时计算列并将存储在磁盘上。

生成表达式可以引用表中的其他列,但不能引用其他生成的列。使用的任何函数和运算符都必须是不可改变的。不允许引用其他表。

**GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]**

该子句将列创建为标识列。 它将拥有一个隐式序列附加到它,并且新行中的列将自动从分配给它的序列中获取值。

子句ALWAYS和BY DEFAULT确定如何在 INSERT和UPDATE命令中明确处理用户指定的值。

在INSERT命令中,如果选择了ALWAYS,则仅当 INSERT 语句指定OVERRIDING SYSTEM VALUE时才接受用户指定的值。如果选择BY DEFAULT,则用户指定的值优先。 有关详细信息,请参阅INSERT。(在COPY命令中,无论此设置如何,始终使用用户指定的值。)

在UPDATE命令中,如果选择了ALWAYS,则将列更新为除DEFAULT之外的任何值都将被拒绝。如果选择BY DEFAULT,则该列可以正常更新。 (UPDATE命令没有OVERRIDING子句。)

可选的sequence_options子句可用于覆盖序列的选项。有关详细信息,请参见CREATE SEQUENCE。

UNIQUE (列约束)

UNIQUE ( column_name [, ... ] ) [ INCLUDE ( column_name [, ...]) ] (表约束)

UNIQUE约束指定一个表中的一列或多列组成的组包含唯一的值。唯一表约束的行为与列约束的行为相同,只是表约束能够跨越多列。

对于一个唯一约束的目的来说,空值不被认为是相等的。

每一个唯一表约束必须命名一个列的集合,并且它与该表上任何其他唯一或主键约束所命名的列集合都不相同(否则它将是一个被列举了两次的约束)。

在为多级分区层次结构建立唯一约束时,目标分区表的分区键中的所有列,以及那些由它派生的所有分区表,必须被包含在约束定义中。

添加唯一约束将自动在使用于约束的列或列组上创建唯一的btree索引。 可选子句INCLUDE在不强制唯一性的情况下向该索引添加一个或多个列。 请注意虽然约束在包含的列上是非强制的,但是它仍然依赖于它们。因此,这些列上的某些操作(例如DROP COLUMN)可能会导致级联约束和索引删除。

PRIMARY KEY (列约束)

PRIMARY KEY ( column_name [, ... ] ) [ INCLUDE ( column_name [, ...]) ] (表约束)

PRIMARY KEY约束指定表的一个或者多个列只能包含唯一(不重复)、非空的值。一个表上只能指定一个主键,可以作为列约束或表约束。

主键约束所涉及的列集合应该不同于同一个表上定义的任何唯一约束的列集合(否则,该唯一约束是多余的并且会被丢弃)。

PRIMARY KEY强制的数据约束可以看成是UNIQUE和NOT NULL的组合, 不过把一组列标识为主键也为模式设计提供了元数据,因为主键标识其他表可以依赖这一个列集合作为行的唯一标识符。

PRIMARY KEY 约束共享UNIQUE 约束放到分区表上时限制。

添加PRIMARY KEY约束将自动在用于约束的列或列组上创建唯一的 btree 索引。可选的INCLUDE 子句允许指定将被包含在索引的非-键部分中的列的列表。 虽然包含的列的唯一性是非强制的,但约束仍依赖于它们。 因此,这些包含的列上的某些操作(例如DROP COLUMN)可能会导致级联约束和索引删除。

EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] )
index_parameters [ WHERE ( predicate ) ]

EXCLUDE子句定一个排除约束,它保证如果任意两行在指定列或表达式上使用指定操作符进行比较,不是所有的比较都将会返回TRUE。如果所有指定的操作符都测试相等,这就等价于一个UNIQUE约束,尽管一个普通的唯一约束将更快。不过,排除约束能够指定比简单相等更通用的约束。例如,你可以使用&&操作符指定一个约束,要求表中没有两行包含相互覆盖的圆。

排除约束使用一个索引实现,这样每一个指定的操作符必须与用于索引访问方法index_method的一个适当的操作符类相关联。操作符被要求是交换的。每一个exclude_element可以选择性地指定一个操作符类或者顺序选项,这些在CREATE INDEX中有完整描述。

访问方法必须支持amgettuple,目前这意味着GIN无法使用。尽管允许,

但是在一个排除约束中使用 B-树或哈希索引没有意义,因为它无法做得比一个普通唯一索引更出色。因此在实践中访问方法将总是GiST或SP-GiST。

predicate允许你在该表的一个子集上指定一个排除约束。在内部这会创建一个部分索引。注意在为此周围的圆括号是必须的。

REFERENCES reftable [ ( refcolumn ) ] [ MATCH matchtype ] [ ON DELETE referential_action ] [ ON UPDATE referential_action ] (column constraint)
FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ]
[ MATCH matchtype ] [ ON DELETE referential_action ] [ ON UPDATE referential_action

] (表约束)

这些子句指定一个外键约束,它要求新表的一列或一个列的组必须只包含能匹配被引用表的某个行在被引用列上的值。 如果refcolumn列表被忽略,将使用reftable的主键。

被引用列必须是被引用表中一个非可延迟唯一约束或主键约束的列。用户必须在被引用的表(或整个表,或特定的引用列)上拥有REFERENCES权限。 增加的外键约束需要SHARE ROW EXCLUSIVE 锁定引用的表。注意外键约束不能在临时表和永久表之间定义。

被插入到引用列的一个值会使用给定的匹配类型与被引用表的值进行匹配。 有三种匹配类型:MATCH FULL、MATCH PARTIAL以及MATCH SIMPLE(这是默认值)。

MATCH FULL将不允许一个多列外键中的一列为空,除非所有外键列都是空;如果它们都是空,则不要求该行在被引用表中有一个匹配。MATCH SIMPLE允许任意外键列为空,如果任一为空,则不要求该行在被引用表中有一个匹配。MATCH PARTIAL现在还没有被实现(当然,NOT NULL约束能被应用在引用列上来组织这些情况发生)。

另外,当被引用列中的数据被改变时,在这个表的列中的数据上可以执行特定的动作。ON DELETE指定当被引用表中一个被引用行被删除时要执行的动作。同样,ON UPDATE指定当被引用表中一个被引用列被更新为新值时要执行的动作。如果该行被更新,但是被引用列并没有被实际改变,不会做任何动作。除了NO ACTION检查之外的引用动作不能被延迟,即便该约束被声明为可延迟的。对每一个子句可能有以下动作:

NO ACTION

产生一个错误指示删除或更新将会导致一个外键约束违背。如果该约束被延迟,并且仍存在引用行,这个错误将在约束检查时被产生。这是默认动作。

RESTRICT

产生一个错误指示删除或更新将会导致一个外键约束违背。这个动作与NO ACTION形同,不过该检查不是可延迟的。

CASCADE

删除任何引用被删除行的行,或者把引用列的值更新为被引用列的新值。

SET NULL

将引用列设置为空。

SET DEFAULT

设置引用列为它们的默认值(如果该默认值非空,在被引用表中必须有一行匹配该默认值,否则该操作将会失败)。

如果被引用列被频繁地更改,最好在引用列上加上一个索引,这样与外键约束相关的引用动作能够更高效地被执行。

DEFERRABLE

NOT DEFERRABLE

这个子句控制该约束是否能被延迟。一个不可延迟的约束将在每一次命令后立刻被检查。可延迟约束的检查将被推迟到事务结束时进行(使用SET CONSTRAINTS命令)。NOT DEFERRABLE是默认值。当前,只有UNIQUE、PRIMARY KEY、EXCLUDE以及REFERENCES(外键)约束接受这个子句。NOT NULL以及CHECK约束是不可延迟的。注意在包括ON CONFLICT DO UPDATE子句的INSERT语句中,可延迟约束不能被用作冲突裁判者。

INITIALLY IMMEDIATE

INITIALLY DEFERRED

如果一个约束是可延迟的,这个子句指定检查该约束的默认时间。如果该约束是INITIALLY IMMEDIATE,它会在每一个语句之后被检查。这是默认值。如果该约束是INITIALLY DEFERRED,它只会在事务结束时被检查。约束检查时间可以用SET CONSTRAINTS命令修改。

USING method

此可选子句指定用于存储新表内容的表访问方法;该方法需要的是类型TABLE的访问方法。

**WITH ( storage_parameter [= value] [, ... ] )**

这个子句为一个表或索引指定可选的存储参数,详见Storage Parameters 。 为了向后兼容性,表的WITH子句还可以包括OIDS=FALSE以便指定新表的行不应包含 OIDs (对象标识符),OIDS=TRUE不再受支持。

WITHOUT OIDS

这是向后兼容的语法,用于声明表WITHOUT OIDS,不再支持创建表WITH OIDS。

ON COMMIT

临时表在一个事务块结束时的行为由ON COMMIT控制。三种选项是:

PRESERVE ROWS

在事务结束时不采取特殊的动作。这是默认行为。

DELETE ROWS

在每一个事务块结束时将删除临时表中的所有行。 实质上,在每一次提交时会完成一次自动的TRUNCATE。 当应用于分区表上时,这不会级联到它的分区。

DROP

在当前事务块结束时将删除临时表。 当在分区表上使用时,这个操作会删除他的分区,而在具有继承子级的表上使用时,它将删除依赖的子级。

TABLESPACE tablespace_name

tablespace_name是新表要创建于其中的表空间名称。如果没有指定,将参

考default_tablespace,或者如果表是临时的则参考temp_tablespaces。 对于分区表,由于表本身不需要存储,指定表空间将 default_tablespace作为默认表空间覆盖,在未显式指定其他表空间时用于任何新创建的分区。

USING INDEX TABLESPACE tablespace_name

这个子句允许选择与一个UNIQUE、PRIMARY KEY或者EXCLUDE约束相关的索引将被创建在哪个表空间中。如果没有指定,将参考default_tablespace,或者如果表是临时的则参考temp_tablespaces。

存储参数

WITH子句能够为表或与一个UNIQUE、PRIMARY KEY或者EXCLUDE约束相关的索引指定存储参数。用于索引的存储参数已经在CREATE INDEX中介绍过。当前可用于表的存储参数在下文中列出。如下文所示,对于很多这类参数,都有一个名字带有toast.前缀的附加参数,它能被用来控制该表的二级TOAST表(如果存在)的行为。 如果一个表的参数值被设置但是相应的toast.参数没有被设置,那么 TOAST 表将使用该表的参数值。 不支持为分区表指定这些参数,但可以为单个叶子分区指定它们。

fillfactor (integer)

一个表的填充因子是一个 10 到 100 之间的百分数。100(完全填满)是默认值。当一个较小的填充因子被指定时,INSERT操作会把表页面只填满到指定的百分比,每个页面上剩余的空间被保留给该页上行的更新。这就让UPDATE有机会把一行的已更新版本放在与其原始版本相同的页面上,这比把它放在一个不同的页面上效率更高。对于一个项从来不会被更新的表来说,完全填满是最好的选择,但是在更新繁重的表上则较小的填充因子更合适。这个参数不能对 TOAST 表设置。

toast_tuple_target (integer)

在我们尝试压缩和/或将长列值移动到TOAST表中之前,toast_tuple_target指定需要的最小元组长度,也是在toasting开始时尝试减少长度的目标长度。这会影响标记为External(用于移动)、 Main(用于压缩)或 Extended(用于两者)的列,并且仅适用于新元组。对现有行没有影响。这仅影响标记为"外部"或"扩展"的列,并且仅适用于新元数 - 对现有行没有影响。 默认情况下此参数设置为允许每个块至少 4 个元组,默认块大小为 2040 字节。有效值介于 128 字节和(块大小-标头)之间,默认大小为8160 字节。更改此值对于非常短或非常长的行可能没有用处。请注意默认设置通常接近最佳状态,在某些情况下设置此参数可能会产生负面影响。 不能对TOAST表设置此参数。

parallel_workers (integer)

这个参数设置用于辅助并行扫描这个表的工作者数量。如果没有设置这个参数,系统将基于关系的尺寸来决定一个值。 规划者或使用并行扫描的实用程序选择的工作者数量可能会比较少,例如max_worker_processes的设置较小就是一种可能的原因。

autovacuum_enabled, toast.autovacuum_enabled (boolean)

为一个特定的表启用或者禁用自动清理守护进程。如果为真,自动清理守护进程,将中讨论的规则在这个表上执行自动的VACUUM或者ANALYZE操作。如果为假,这个表不会被自动清理,不过为了阻止事务 ID 回卷时还是会对它进行自动的清理。如果autovacuum参数为假,自动清理守护进程根

本就不会运行(除非为了阻止事务 ID 回卷),设置独立的表存储参数也不会覆盖这个设置。因此显式地将这个存储参数设置为true很少有大的意义,只有设置为false才更有用。

vacuum_index_cleanup, toast.vacuum_index_cleanup (boolean)

当VACUUM在此表上运行时启用或禁用索引清理。默认值为true。禁用索引清理可以显著加快VACUUM,但如果表修改很频繁,也可能导致索引严重膨胀。VACUUM的INDEX_CLEANUP参数,如果指定,将覆盖此选项的值。

vacuum_truncate, toast.vacuum_truncate (boolean)

启用或禁用vacuum以尝试截断此表末尾的任何空页。默认值为true。如

果true,VACUUM和autovacuum将执行截断,截断页的磁盘空间将返回到操作系统。 请注意,截断需要 ACCESS EXCLUSIVE在表上锁定。VACUUM的TRUNCATE参数,如果指定,覆盖此选项的值。

autovacuum_vacuum_threshold, toast.autovacuum_vacuum_threshold (integer)

autovacuum_vacuum_threshold参数对于每个表的值。

autovacuum_vacuum_scale_factor, toast.autovacuum_vacuum_scale_factor (floating

point)

autovacuum_vacuum_scale_factor参数对于每个表的值。

autovacuum_vacuum_insert_threshold, toast.autovacuum_vacuum_insert_threshold (integer)

autovacuum_vacuum_insert_threshold参数对于每个表的值。特殊值-1可用于禁用表上的插入为空。

autovacuum_vacuum_insert_scale_factor,

toast.autovacuum_vacuum_insert_scale_factor (float4)

autovacuum_vacuum_insert_scale_factor参数对于每个表的值。

autovacuum_analyze_threshold (integer)

autovacuum_analyze_threshold参数对于每个表的值。

autovacuum_analyze_scale_factor (floating point)

autovacuum_analyze_scale_factor参数对于每个表的值。

autovacuum_vacuum_cost_delay, toast.autovacuum_vacuum_cost_delay (floating point)

autovacuum_vacuum_cost_delay参数对于每个表的值。

autovacuum_vacuum_cost_limit, toast.autovacuum_vacuum_cost_limit (integer)

autovacuum_vacuum_cost_limit参数对于每个表的值。

autovacuum_freeze_min_age, toast.autovacuum_freeze_min_age (integer)

vacuum_freeze_min_age参数对于每个表的值。注意自动清理将忽略超过系统范围autovacuum_freeze_max_age参数一半的针对每个表的autovacuum_freeze_min_age参数。

autovacuum_freeze_max_age, toast.autovacuum_freeze_max_age (integer)

autovacuum_freeze_max_age参数对于每个表的值。注意自动清理将忽略超过系统范围参数(只能被设置得较小)一半的针对每个表的autovacuum_freeze_max_age参数。

autovacuum_freeze_table_age, toast.autovacuum_freeze_table_age (integer)

vacuum_freeze_table_age参数对于每个表的值。

autovacuum_multixact_freeze_min_age, toast.autovacuum_multixact_freeze_min_age

(integer)

vacuum_multixact_freeze_min_age参数对于每个表的值。注意自动清理将忽略超过系统范围autovacuum_multixact_freeze_max_age参数一半的针对每个表的autovacuum_multixact_freeze_min_age参数。

autovacuum_multixact_freeze_max_age, toast.autovacuum_multixact_freeze_max_age

(integer)

autovacuum_multixact_freeze_max_age参数对于每个表的值。注意自动清理将忽略超过系统范围参数(只能被设置得较小)一半的针对每个表的autovacuum_multixact_freeze_max_age参数。

autovacuum_multixact_freeze_table_age,

toast.autovacuum_multixact_freeze_table_age (integer)

vacuum_multixact_freeze_table_age参数对于每个表的值。

log_autovacuum_min_duration, toast.log_autovacuum_min_duration (integer)

log_autovacuum_min_duration参数对于每个表的值。

user_catalog_table (boolean)

声明该表是一个用于逻辑复制目的的额外的目录表。

注解

系统为每一个唯一约束和主键约束创建一个索引来强制唯一性。因此,没有必要显式地为主键列创建一个索引(详见CREATE INDEX)。

在当前的实现中,唯一约束和主键不会被继承。这使得继承和唯一约束的组合相当不正常。

一个表不能有超过 1600 列(实际上,由于元组长度限制,有效的限制通常更低)。

例子

创建表films和表distributors:

CREATE TABLE films (
code char(5) CONSTRAINT firstkey PRIMARY KEY,
title varchar(40) NOT NULL,
did integer NOT NULL,
date_prod date,
kind varchar(10),
len interval hour to minute
);
CREATE TABLE distributors (
did integer PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
name varchar(40) NOT NULL CHECK (name <> '')
);

创建有一个二维数组的表:

CREATE TABLE array_int (
vector int[][]);

为表films定义一个唯一表约束。唯一表约束能够被定义在表的一列或多列上:

CREATE TABLE films (
code char(5),
title varchar(40),
did integer,
date_prod date,
kind varchar(10),
len interval hour to minute,
CONSTRAINT production UNIQUE(date_prod)
);

定义一个列检查约束:

CREATE TABLE distributors (
did integer CHECK (did > 100),
name varchar(40)
);

定义一个表检查约束:

CREATE TABLE distributors (
did integer,
name varchar(40),
CONSTRAINT con1 CHECK (did > 100 AND name <> '')
);

为表films定义一个主键表约束:

CREATE TABLE films (
code char(5),
title varchar(40),
did integer,
date_prod date,
kind varchar(10),
len interval hour to minute,
CONSTRAINT code_title PRIMARY KEY(code,title)
);

为表distributors定义一个主键约束。下面的两个例子是等价的,第一个使用表约束语法,第二个使用列约束语法:

CREATE TABLE distributors (
did integer,
name varchar(40),
PRIMARY KEY(did)
);
CREATE TABLE distributors (
did integer PRIMARY KEY,
name varchar(40)
);

为列name赋予一个文字常量默认值,安排列did的默认值是从一个序列对象中选择下一个值产生,并且让modtime的默认值是该行被插入的时间:

CREATE TABLE distributors (
name varchar(40) DEFAULT 'Luso Films',
did integer DEFAULT nextval('distributors_serial'),
modtime timestamp DEFAULT current_timestamp
);

在表distributors上定义两个NOT NULL列约束,其中之一被显式给定了一个名称:

CREATE TABLE distributors (
did integer CONSTRAINT no_null NOT NULL,
name varchar(40) NOT NULL
);

为name列定义一个唯一约束:

CREATE TABLE distributors (
did integer,
name varchar(40) UNIQUE
);

同样的唯一约束用表约束指定:

CREATE TABLE distributors (
did integer,
name varchar(40),
UNIQUE(name)
);

创建相同的表,指定表和它的唯一索引指定70%的填充因子:

CREATE TABLE distributors (
did integer,
name varchar(40),
UNIQUE(name) WITH (fillfactor=70)
)
WITH (fillfactor=70);

创建表circles,带有一个排除约束阻止任意两个圆重叠:

CREATE TABLE circles (
c circle,
EXCLUDE USING gist (c WITH &&)
);

在表空间diskvol1中创建表cinemas:

CREATE TABLE cinemas (
id serial,
name text,
location text
) TABLESPACE diskvol1;

创建一个组合类型以及一个类型化的表:

CREATE TYPE employee_type AS (name text, salary numeric);
CREATE TABLE employees OF employee_type (
PRIMARY KEY (name),
salary WITH OPTIONS DEFAULT 1000
);

创建一个范围分区表:

CREATE TABLE measurement (
logdate date not null,
peaktemp int,
unitsales int
) PARTITION BY RANGE (logdate);

创建在分区键中具有多个列的范围分区表:

CREATE TABLE measurement_year_month (
logdate date not null,
peaktemp int,
unitsales int
) PARTITION BY RANGE (EXTRACT(YEAR FROM logdate), EXTRACT(MONTH FROM logdate));

创建列表分区表:

CREATE TABLE cities (
city_id bigserial not null,
name text not null,
population bigint
) PARTITION BY LIST (left(lower(name), 1));

建立哈希分区表:

CREATE TABLE orders (
order_id bigint not null,
cust_id bigint not null,
status text
) PARTITION BY HASH (order_id);

创建范围分区表的分区:

CREATE TABLE measurement_y2016m07
PARTITION OF measurement (
unitsales DEFAULT 0
) FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');

使用分区键中的多个列创建范围分区表的几个分区:

CREATE TABLE measurement_ym_older
PARTITION OF measurement_year_month
FOR VALUES FROM (MINVALUE, MINVALUE) TO (2016, 11);
CREATE TABLE measurement_ym_y2016m11
PARTITION OF measurement_year_month
FOR VALUES FROM (2016, 11) TO (2016, 12);
CREATE TABLE measurement_ym_y2016m12
PARTITION OF measurement_year_month
FOR VALUES FROM (2016, 12) TO (2017, 01);
CREATE TABLE measurement_ym_y2017m01
PARTITION OF measurement_year_month
FOR VALUES FROM (2017, 01) TO (2017, 02);

创建列表分区表的分区:

CREATE TABLE cities_ab
PARTITION OF cities (
CONSTRAINT city_id_nonzero CHECK (city_id != 0)
) FOR VALUES IN ('a', 'b');

创建本身是分区的列表分区表的分区,然后向其添加分区:

CREATE TABLE cities_ab
PARTITION OF cities (
CONSTRAINT city_id_nonzero CHECK (city_id != 0)
) FOR VALUES IN ('a', 'b') PARTITION BY RANGE (population);
CREATE TABLE cities_ab_10000_to_100000
PARTITION OF cities_ab FOR VALUES FROM (10000) TO (100000);

建立哈希分区表的分区:

CREATE TABLE orders_p1 PARTITION OF orders
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE orders_p2 PARTITION OF orders
FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE orders_p3 PARTITION OF orders
FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE orders_p4 PARTITION OF orders
FOR VALUES WITH (MODULUS 4, REMAINDER 3);

建立默认分区:

CREATE TABLE cities_partdef
PARTITION OF cities DEFAULT;
Compatibility

CREATE TABLE命令遵从SQL标准,除了以下例外。

临时表

尽管CREATE TEMPORARY TABLE的语法很像 SQL 标准的语法,但事实是并不相同。在标准中,临时表只需要被定义一次并且会自动地存在(从空内容开始)于需要它们的每一个会话中。系统要求每一个会话为每一个要用的临时表发出它自己的CREATE TEMPORARY TABLE命令。这允许不同的会话为不同的目的使用相同的临时表名,而标准的方法约束一个给定临时表名的所有实例都必须具有相同的表结构。

列检查约束

SQL标准指出CHECK列约束只能引用它们应用到的列,只有CHECK表约束能够引用多列。

EXCLUDE 约束

EXCLUDE约束类型是Halo的扩展语句。

NULL "约束"

NULL "约束"(实际上是一个非约束)是对SQL标准的扩展,它也被包括(以及对称的NOT NULL约束)在一些其他的数据库系统中以实现兼容性。因为它是任意列的默认值,它的存在就像噪声一样。

Constraint Naming

SQL标准规定在包含表或域的模式范围内表和域的约束必须具有唯一的名称。 Halo是比较宽松的:它只需要约束名称在附加到特定表或域的约束之间是唯一的。但是,对于基于索引的约束(UNIQUE,PRIMARY KEY, and EXCLUDEconstraints), 这个特别的自由度并不存在,因为关联的索引被命名为与约束相同的名称,并且索引名称在相同模式的所有关系中必须是唯一的。

继承

通过INHERITS子句的多继承是Halo的扩展语句。SQL:1999以及之后的标准使用一种不同的语法和不同的语义定义了单继承。

零列表

Halo允许创建一个没有列的表(例如CREATE TABLE foo();)。这是一个对于 SQL 标准的扩展,它不允许零列表。零列表本身并不是很有用,但是不允许它们会为ALTER TABLE DROP COLUMN带来奇怪的特殊情况,因此忽略这种规则限制看起来更加整洁。

多个标识列

Halo允许一个表拥有多个标识列。该标准指定一个表最多只能有一个标识列。这主要是为了给模式更改或迁移提供更大的灵活性。请注意,INSERT命令仅支持一个适用于整个语句的覆盖子句,因此不支持具有不同行为的多个标识列。

Generated Columns

STORED选项不是标准,但也用于其他 SQL 实现。SQL 标准不规定生成列的存储。

LIKE 子句

虽然SQL标准中有一个LIKE子句,但是Halo接受的LIKE子句比标准更丰富。

WITH子句

WITH子句是Halo的扩展语句,存储参数不在标准中。表空间概念不是标准的一部分。

类型化的表

类型化的表实现了 SQL 标准的一个子集。根据标准,一个类型化的表具有与底层组合类型相对应的列,以及其他的"自引用列"。Halo不显式支持自引用列。

PARTITION BY 子句

PARTITION BY子句是Halo的扩展语句。

PARTITION OF 子句

PARTITION OF子句是Halo的扩展语句。

参见

ALTER TABLE, DROP TABLE, CREATE TABLE AS, CREATE TABLESPACE, CREATE TYPE

CREATE TABLE AS​

CREATE TABLE AS --- 从一个查询的结果创建一个新表

大纲

CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] table_name
[ (column_name [, ...] ) ]
[ USING method ]
[ WITH ( storage_parameter [= value] [, ... ] ) | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE tablespace_name ]
AS query
[ WITH [ NO ] DATA ]

描述

CREATE TABLE AS创建一个表,并且用由一个SELECT命令计算出来的数据填充该表。该表的列具有和SELECT的输出列相关的名称和数据类型(不过可以通过给出一个显式的新列名列表来覆盖这些列名)。

CREATE TABLE AS和创建一个视图有些相似,但是实际上非常不同:它会创建一个新表并且只计算该查询一次用来初始填充新表。这个新表将不会跟踪该查询源表的后续变化。相反,一个视图只要被查询,它的定义SELECT 语句就会被重新计算。

参数

GLOBAL或者LOCAL

为兼容性而忽略。不推荐使用这些关键词,详见 CREATE TABLE。

TEMPORARY或者TEMP

如果被指定,该表会被创建为一个临时表。详见 CREATE TABLE。

UNLOGGED

如果被指定,该表会被创建为一个不做日志的表。详见 CREATE TABLE。

IF NOT EXISTS

如果已经存在一个同名的关系时不要抛出错误。这种情况下会发出一个 提示。详见CREATE TABLE。

table_name

要创建的表的名称(可以被模式限定)。

column_name

新表中一列的名称。如果没有提供列名,会从查询的输出列名中得到。

USING method

这个可选的子句指定了用于存储新表内容的表访问方法;该方法需要是一个类型TABLE的访问方法。如果没有指定这个选项,则选择新表的默认表访问方法。详见default_table_access_method。

**WITH ( storage_parameter [= value] [, ... ] )**

这个子句为新表指定可选的存储参数,详见CREATE TABLE中的 Storage Parameters。为了向后兼容,表的WITH子句也能包含OIDS=FALSE来指定新表的行将不包含OID(对象标识符)。OIDS=TRUE不再支持。

WITHOUT OIDS

这是向后兼容的语法,用于声明表WITHOUT OIDS,创建表WITH OIDS不再被支持。

ON COMMIT

临时表在事务块结束时的行为可以用ON COMMIT 控制。三个选项是:

PRESERVE ROWS

在事务结束时不采取特殊的动作。这是默认行为。

DELETE ROWS

在每一个事务块结束时临时表中的所有行都将被删除。本质上,在每次提交时会完成一次自动的TRUNCATE。

DROP

在当前事务块结束时将删掉临时表。

TABLESPACE tablespace_name

tablespace_name 是要在其中创建新表的表空间名称。如果没有指定,将会查询default_tablespace,临时表会查询 temp_tablespaces。

query

一个SELECT、TABLE或者VALUES 命令,或者是一个运行准备好的SELECT、 TABLE或者VALUES查询的EXECUTE命令。

**WITH [ NO ] DATA**

这个子句指定查询产生的数据是否应该被复制到新表中。如果不是,只有表结构会被复制。默认是复制数据。

注解

这个命令在功能上类似于SELECT INTO,但是它更好,因为不太可能被SELECT INTO语法的其他使用混淆。更进一步,CREATE TABLE AS提供了 SELECT INTO的功能的一个超集。

示例

创建一个新表films_recent,它只由表 films中最近的项组成:

CREATE TABLE films_recent AS
SELECT * FROM films WHERE date_prod >= '2002-01-01';

要完全地复制一个表,也可以使用TABLE命令的 简短形式:

CREATE TABLE films2 AS
TABLE films;

用一个预备语句创建一个新的临时表films_recent, 它仅由表films中最近的项组成,使用准备好的声明。新表将在提交时被丢弃:

PREPARE recentfilms(date) AS
SELECT * FROM films WHERE date_prod > \$1;
CREATE TEMP TABLE films_recent ON COMMIT DROP AS
EXECUTE recentfilms('2002-01-01');

另见

CREATE MATERIALIZED VIEW, CREATE TABLE, EXECUTE, SELECT, SELECT INTO, VALUES

CREATE TABLESPACE​

CREATE TABLESPACE --- 定义一个新的表空间

大纲

CREATE TABLESPACE tablespace_name
[ OWNER { new_owner | CURRENT_USER | SESSION_USER } ]
LOCATION 'directory'
[ WITH ( tablespace_option = value [, ... ] ) ]

描述

CREATE TABLESPACE注册一个新的集簇范围的表空间。表空间的名称必须与数据库集簇中现有的任何表空间不同。

表空间允许超级用户在文件系统上定义另一个位置,可以把包含数据库对象 (例如表和索引)的数据文件放在那里。

一个具有适当特权的用户可以把 tablespace_name传递给 CREATE DATABASE、CREATE TABLE、CREATE INDEX或者ADD CONSTRAINT 来让这些对象的数据文件存储在指定的表空间中。

警告:表空间不能独立于定义它的集簇使用。

参数

tablespace_name

The name of a tablespace to be created. The name cannot begin with pg_, as such names are reserved for system tablespaces.

user_name

将拥有该表空间的用户名。如果省略,默认为执行该命令的用户。只有超级用户能创建表空间,但是它们能把表空间的拥有权赋予给非超级用户。

directory

要被用于表空间的目录。该目录必需存在(CREATE TABLESPACE 将不创建它),应该为空,并且必须由系统用户拥有。该目录必须用一个绝对路径指定。

tablespace_option

要设置或者重置的表空间参数。当前,唯一可用的参数是

seq_page_cost、random_page_cost、 effective_io_concurrency以

及maintenance_io_concurrency。 为一个特定表空间设定这些值将覆盖规划器对该表空间中表页读取的 常规代价估计,和执行程序的预取行为,由同名的配置参数确定(见seq_page_cost、random_page_cost、

effective_io_concurrency、maintenance_io_concurrency)。 如果一个表空间位于一个比其他 I/O 子系统更慢或者更快的磁盘上,这些参数就能发挥作用。

注解

只有在支持符号链接的系统上才支持表空间。

CREATE TABLESPACE不能在一个事务块内被执行。

示例

要在文件系统位置/data/dbs创建表空间dbspace,请首先使用操作系统工具创建目录并设置正确的所有权:

mkdir /data/dbs

chown halo:halo /data/dbs

然后使用表空间创建命令:

CREATE TABLESPACE dbspace LOCATION '/data/dbs';

要创建由不同数据库用户拥有的表空间,可用类似这样的命令:

CREATE TABLESPACE indexspace OWNER genevieve LOCATION '/data/indexes';

另见

CREATE DATABASE, CREATE TABLE, CREATE INDEX, DROP TABLESPACE, ALTER TABLESPACE

CREATE TEXT SEARCH CONFIGURATION​

CREATE TEXT SEARCH CONFIGURATION --- 定义一个新的文本搜索配置

大纲

CREATE TEXT SEARCH CONFIGURATION name (
PARSER = parser_name |
COPY = source_config
)

描述

CREATE TEXT SEARCH CONFIGURATION 创建一个新的文本搜索配置。一个文本搜索配置指定一个文本搜索解析器(它能把字符串解析成记号),外加一些词典(可被用来决定哪些记号是搜索感兴趣的)。

如果只指定了解析器,那么新文本搜索配置最初没有从记号类型到词典的映射,并且因此将忽略所有词。后续的ALTER TEXT SEARCH CONFIGURATION命令必须被用来创建映射以让该配置变得可用。另一种方式是复制一个现有的文本搜索配置。

如果给定一个模式名称,则文本搜索配置会被创建在指定的模式中。否则它将会被创建在当前模式中。

定义一个文本搜索配置的用户会成为其拥有者。

参数

name

要创建的文本搜索配置的名称。该名称可以被模式限定。

parser_name

这个配置要使用的文本搜索解析器的名称。

source_config

要复制的已有文本搜索配置的名称。

注解

PARSER和COPY选项是互斥的,因为当一个已有的配置被复制时,它的解析器选择也会被复制。

另见

ALTER TEXT SEARCH CONFIGURATION, DROP TEXT SEARCH CONFIGURATION

CREATE TEXT SEARCH DICTIONARY​

CREATE TEXT SEARCH DICTIONARY --- 定义一个新的文本搜索字典

大纲

CREATE TEXT SEARCH DICTIONARY name (
TEMPLATE = template
[, option = value [, ... ]]
)

描述

CREATE TEXT SEARCH DICTIONARY创建一个 新的文本搜索字典。一个文本搜索字典指定一种识别搜索感兴趣或者不感兴趣的单词的方法。一个字典依赖于一个文本搜索模板,后者指定了实际执行该工作的函数。通常该字典提供一些控制该模板函数细节行为的选项。

如果给出了一个模式名称,那么该文本搜索字典会被创建在指定的模式中。 否则它会被创建在当前模式中。

定义文本搜索字典的用户将成为其拥有者。

参数

name

要创建的文本搜索字典的名称。该名称可以是模式限定的。

template

将定义这个字典基本行为的文本搜索模板的名称。

option

要为此字典设置的模板相关选项的名称。

value

用于模板相关选项的值。如果该值不是一个简单标识符或者数字,它必须被加引用(你可以按照你所希望的总是对它加上引用)。

选项可以以任意顺序出现。

示例

下面的例子命令创建了一个基于 Snowball 的字典,它使用了非标准的停用词列表。

CREATE TEXT SEARCH DICTIONARY my_russian (
template = snowball,
language = russian,
stopwords = myrussian
);

另见

ALTER TEXT SEARCH DICTIONARY, DROP TEXT SEARCH DICTIONARY

CREATE TEXT SEARCH PARSER​

CREATE TEXT SEARCH PARSER --- 定义一个新的文本搜索解析器

大纲

CREATE TEXT SEARCH PARSER name (
START = start_function ,
GETTOKEN = gettoken_function ,
END = end_function ,
LEXTYPES = lextypes_function
[, HEADLINE = headline_function ]
)

描述

CREATE TEXT SEARCH PARSER创建一个新的文本搜索解析器。一个文本搜索解析器定义把文本字符串分解成记号并且为记号分配类型(分类)的方法。一个解析器本身并不特别有用,但是必须与一些要用于搜索的文本搜索字典一起被绑定到一个文本搜索配置中。

如果给出了一个模式名称,那么文本搜索解析器将被创建在指定的模式中。 否则它会被创建在当前模式中。

只有超级用户才能使用 CREATE TEXT SEARCH PARSER(这是因为 错误的文本搜索定义可能会让服务器混淆甚至崩溃)。

参数

name

要创建的文本搜索解析器的名称。该名称可以是模式限定的。

start_function

用于该解析器的开始函数的名称。

gettoken_function

用于该解析器的取下一个记号的函数名称。

end_function

用于该解析器的结束函数的名称。

lextypes_function

用于该解析器的词法分析器函数(一个返回其产生的记号类型集合信息的函数)的名称。

headline_function

用于该解析器的标题函数(一个对记号集合进行综述的函数)的名称。

如有必要,函数的名称可以被模式限定。参数类型没有给出,因为函数的每个类型的参数列表无法被预先决定。除了标题函数之外, 所有函数都是必要的。

参数可以以任何顺序出现,而不是必须按照上面所展示的顺序。

另见

ALTER TEXT SEARCH PARSER, DROP TEXT SEARCH PARSER

CREATE TEXT SEARCH TEMPLATE​

CREATE TEXT SEARCH TEMPLATE --- 定义一种新的文本搜索模板

大纲

CREATE TEXT SEARCH TEMPLATE name (
[ INIT = init_function , ]
LEXIZE = lexize_function
)

描述

CREATE TEXT SEARCH TEMPLATE创建一个新的文本搜索模板。文本搜索模板定义实现文本搜索字典的函数。一个模板本身没什么用处,但是必须被实例化为一个字典来使用。字典通常指定要给予模板函数的参数。

如果给出了一个模式名,文本搜索模板会被创建在指定模式中。否则它会被 创建在当前模式中。

必须成为超级用户以使用 CREATE TEXT SEARCH TEMPLATE。做出这种限制是因为错误的模板定义会让服务器混淆甚至崩溃。将模板与字典分隔开来的原因是模板中封装了定义字典的"不安全"方面。在定义字典时可以被设置的参数对非特权用户是可以安全设置的,因此创建字典不需要拥有特权来操作。

参数

name

要创建的额文本搜索模板的名称。该名称可以被模式限定。

init_function

用于模板的初始化函数的名称。

lexize_function

用于模板的分词函数的名称。

如有必要,函数名称可以被模式限定。参数类型没有给出,因为每一类函数的参数列表是预先定义好的。分词函数是必需的,但是初始化函数是可选的。

参数可以以任何顺序出现,而不是只能按照上文的顺序。

另见

ALTER TEXT SEARCH TEMPLATE, DROP TEXT SEARCH TEMPLATE

CREATE TRANSFORM​

CREATE TRANSFORM --- 定义一个新的转换

大纲

CREATE [ OR REPLACE ] TRANSFORM FOR type_name LANGUAGE lang_name ( FROM SQL WITH FUNCTION from_sql_function_name [ (argument_type [, ...]) ],
TO SQL WITH FUNCTION to_sql_function_name [ (argument_type [, ...]) ]
);

简介

CREATE TRANSFORM定义一种新的转换。CREATE OR REPLACE TRANSFORM将 创建一种新的转换或者替换现有的定义。

一种转换指定了如何把一种数据类型适配到一种过程语言。例如,在用 PL/Python 编写一个使用hstore类型的函数时,PL/Python 没有关于如何在 Python 环境中表示hstore值的先验知识。语言的实现通常默认会使用文本表示,但是在一些时候这很不方便,例如有时可能用一个联合数组或者列表更合适。

一种转换指定了两个函数:

• 一个"from SQL"函数负责将类型从 SQL 环境转换到语言。这个函数将在该语言编写的一个函数的参数上调用。

• 一个"to SQL"函数负责将类型从语言转换到 SQL 环境。这个函数将在该语言编写的一个函数的返回值上调用。

没有必要同时提供这些函数。如果有一种没有被指定,将在必要时使用与语言相关的默认行为(为了完全阻止在一个方向上发生转换,你也可以写一个总是报错的转换函数)。

要创建一种转换,你必须拥有该类型并且具有该类型上的USAGE特权,拥有该语言上的USAGE特权,并且拥有 from-SQL 和 to-SQL 函数(如果 指定了)及其上的EXECUTE特权。

参数

type_name

该转换的数据类型的名称。

lang_name

该转换的语言的名称。

**from_sql_function_name[(argument_type [, ...])]**

将该类型从 SQL 环境转换到该语言的函数名。它必须接受一个 internal类型的参数并且返回类型internal。实参将是该转换所适用的类型,并且该函数也应该被写成认为它是那种类型(但是不允许声明一个返回internal但没有至少一个 internal类型参数的SQL层函数)。实际的返回值将与语言的实现相关。如果没有指定参数列表,则函数名在该模式中必须唯一。

**to_sql_function_name[(argument_type [, ...])]**

将该类型从语言转换到 SQL 环境的函数名。它必须接受一个 internal类型的参数并且返回该转换所适用的类型。实参值将与语言的实现相关。如果没有指定参数列表,则函数名在该模式中必须唯一。

注解

使用DROP TRANSFORM移除转换。

示例

要为类型hstore和语言 plpythonu创建一种转换,先搞定该类型和语言:

CREATE TYPE hstore ...;
CREATE EXTENSION plpythonu;

然后创建需要的函数:

CREATE FUNCTION hstore_to_plpython(val internal) RETURNS internal
LANGUAGE C STRICT IMMUTABLE
AS ...;
CREATE FUNCTION plpython_to_hstore(val internal) RETURNS hstore
LANGUAGE C STRICT IMMUTABLE
AS ...;

最后创建转换把它们连接起来:

CREATE TRANSFORM FOR hstore LANGUAGE plpythonu (
FROM SQL WITH FUNCTION hstore_to_plpython(internal),
TO SQL WITH FUNCTION plpython_to_hstore(internal)
);

实际上,这些命令将被包裹在扩展中。

contrib小节包含了一些提供转换的扩展,它们可以作为实际的例子。

另见

CREATE FUNCTION, CREATE LANGUAGE, CREATE TYPE, DROP TRANSFORM

CREATE TRIGGER​

CREATE TRIGGER --- 定义一个新触发器

大纲

CREATE [ CONSTRAINT ] TRIGGER name { BEFORE | AFTER | INSTEAD OF } { event
[ OR ... ] }
ON table_name
[ FROM referenced_table_name ]
[ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ]
[ REFERENCING { { OLD | NEW } TABLE [ AS ] transition_relation_name }
[ ... ] ]
[ FOR [ EACH ] { ROW | STATEMENT } ]
[ WHEN ( condition ) ]
EXECUTE { FUNCTION | PROCEDURE } function_name ( arguments )

这里的event可以是下列之一:

INSERT
UPDATE [ OF column_name [, ... ] ]
DELETE
TRUNCATE

描述

CREATE TRIGGER创建一个新触发器。该触发器将被关联到指定的表、视图或者外部表并且在表上发生特定操作时将执行指定的函数function_name。

该触发器可以被指定为在一行上尝试该操作之前触发(在约束被检查并且INSERT、UPDATE或者DELETE被尝试之前);也可以在该操作完成之后触发(在约束被检查并且INSERT、UPDATE或者DELETE完成之后);或者取代该操作(在对一个视图插入、更新或删除的情况中)。如果该触发器在事件之前触发或者取代事件,该触发器可以跳过对当前行的操作或者改变正在被插入的行(只对INSERT以及UPDATE操作)。如果该触发器在事件之后触

发,所有更改(包括其他触发器的效果)对该触发器"可见"。

一个被标记为FOR EACH ROW的触发器会对该操作修改的每一行都调用一次。例如,一个影响 10 行的DELETE将导致在目标关系上的任何ON DELETE触发器被独立调用 10 次,也就是为每一个被删除的行调用一次。与此相反,一个被标记为FOR EACH STATEMENT的触发器只会为任何给定的操作执行一次,不管该操作修改多少行(特别地,一个修改零行的操作将仍会导致任何可用的FOR EACH STATEMENT触发器被执行)。

被指定为要触发INSTEAD OF触发器事件的触发器必须被标记为FOR EACH ROW,并且只能被定义在视图上。一个视图上的BEFORE和AFTER触发器必须被标记为FOR EACH STATEMENT。

此外,触发器可以被定义成为TRUNCATE触发,但只能是FOR EACH STATEMENT。

下面的表格总结了哪些触发器类型可以被用在表、视图和外部表上:

何时事件行级语句级
BEFOREINSERT / UPDATE / DELETE表和外部表表、视图和外部表
BEFORETRUNCATE---表
AFTERINSERT / UPDATE / DELETE表和外部表表、视图和外部表
AFTERTRUNCATE---表
INSTEAD OFINSERT / UPDATE / DELETE视图---
INSTEAD OFTRUNCATE------

还有,一个触发器定义可以指定一个布尔的WHEN条件,它将被测试来看看该触发器是否应该被触发。在行级触发器中,WHEN条件可以检查该行的列的新旧值。语句级触发器也可以有WHEN条件,尽管该特性对于它们不是很有用(因为条件不能引用表中的任何值)。

如果有多个同种触发器被定义为相同事件触发,它们将按照名称的字母表顺序被触发。当CONSTRAINT选项被指定,这个命令会创建一个约束触发器。这和一个常规触发器相同,不过触发该触发器的时机可以使用SET CONSTRAINTS调整。约束触发器必须是表上的AFTER ROW触发器。它们可以在导致触发器事件的语句末尾被引发或者在包含该语句的事务末尾被引发。在后一种情况中,它们被称作是被延迟。一个待处理的延迟触发器的引发也可以使用SET CONSTRAINTS立即强制发生。当约束触发器实现的约束被违背时,约束触发器应该抛出一个异常。

REFERENCING选项启用对传递关系的收集,传递关系是包括被当前SQL语句插入、删除或者修改的行的行集合。这个特性让触发器能看到该语句做的事情的全局视图,而不是一次只看到一行。仅对非约束触发器的AFTER触发器允许这个选项。此外,如果触发器是一个UPDATE触发器,则它不能指定column_name列表。OLD TABLE仅可以被指定一次,并且只能为在UPDATE或DELETE事件上引发的触发器指定,它创建的传递关系包含有该语句更新或删除的所有行的前映像。类似地,NEW TABLE仅可以被指定一次,并且只能为在UPDATE或INSERT事件上引发的触发器指定,它创建的传递关系包含有该语句更新或插入的所有行的后映像。

SELECT不修改任何行,因此你无法创建SELECT触发器。规则和视图可以为需要SELECT触发器的问题提供可行的解决方案。

参数

name

给新触发器的名称。这必须与同一个表上的任何其他触发器相区别。名称不能是模式限定的 --- 该触发器会继承它所在表的模式。对于一个约束触发器,这也是使用SET CONSTRAINTS修改触发器行为时要用到的名字。

BEFORE

AFTER

INSTEAD OF

决定该函数是要在事件之前、之后被调用还是会取代该事件。一个约束触发器也能被指定为AFTER。

event

INSERT、UPDATE、DELETE或者TRUNCATE之一,这指定了将要引发该触发器的事件。多个事件可以用OR指定,要求传递关系的时候除外。

对于UPDATE事件,可以使用下面的语法指定一个列的列表:

UPDATE OF column_name1 [, column_name2 ... ]

只有当至少一个被列出的列出现在UPDATE命令的更新目标中时,或者如果列出的列之一是生成的列,而且依赖的列是UPDATE的目标,该触发器才会触发。

INSTEAD OF UPDATE事件不允许列的列表。在请求传递关系时,也不能指定列的列表。

table_name

要使用该触发器的表、视图或外部表的名称(可能是模式限定的)。

referenced_table_name

约束引用的另一个表的名称(可能是模式限定的)。这个选项被用于外键约束并且不推荐用于一般的目的。这只能为约束触发器指定。

DEFERRABLE

NOT DEFERRABLE

INITIALLY IMMEDIATE

INITIALLY DEFERRED

该触发器的默认时机。这些约束选项的细节可参考CREATE TABLE文档。这只能为约束触发器指定。

REFERENCING

这个关键词紧接在一个或者两个关系名的声明之前,这些关系提供对触发语句的传递关系的访问。

OLD TABLE

NEW TABLE

这个子句指示接下来的关系名是用于前映像传递关系还是后映像传递关系。

transition_relation_name

在该触发器中这个传递关系要使用的(未限定)名称。

FOR EACH ROW

FOR EACH STATEMENT

这指定该触发器函数是应该为该触发器事件影响的每一行被引发一次,还是只为每个SQL 语句被引发一次。如果都没有被指定,FOR EACH STATEMENT会是默认值。约束触发器只能被指定为FOR EACH ROW。

condition

一个决定该触发器函数是否将被实际执行的布尔表达式。如果指定了WHEN,只有condition返回true时才会调用该函数。在FOR EACH ROW触发器中,WHEN条件可以分别写OLD.column_name或者NEW.column_name来引用列的新旧行值。当然,INSERT触发器不能引用OLD并且DELETE触发器不能引用NEW。

INSTEAD OF触发器不支持WHEN条件。

当前,WHEN表达式不能包含子查询。

注意对于约束触发器,对于WHEN条件的计算不会被延迟,而是直接在行更新操作被执行之后立刻发生。如果该条件计算得不到真,那么该触发器就不会被放在延迟执行的队列中。

function_name

一个用户提供的函数,它被声明为不用参数并且返回类型trigger,当触发器引发时会执行该函数。

在CREATE TRIGGER的语法中,关键词FUNCTION和PROCEDURE是等效的,但是任何情况下被引用的函数必须是一个函数而不是过程。这里,关键词PROCEDURE的使用是有历史原因的并且已经被废弃。

arguments

一个可选的逗号分隔的参数列表,它在该触发器被执行时会被提供给该函数。参数是字符串常量。简单的名称和数字常量也可以被写在这里,但是它们将全部被转换成字符串。请检查该触发器函数的实现语言的描述来找出在函数内部如何访问这些参数,这可能与普通函数参数不同。

注解

要在一个表上创建一个触发器,用户必须具有该表上的TRIGGER特权。用户还必须具有在触发器函数上的EXECUTE特权。

使用DROP TRIGGER移除一个触发器。

当一个列相关的触发器(使用UPDATE OF column_name语法定义的触发器)的列被列为UPDATE命令的SET列表目标时,它会被触发。即便该触发器没有被引发,一个列的值也可能改变,因为BEFORE UPDATE触发器对行内容所作的改变不会被考虑。相反,一个诸如UPDATE ... SET x = x ...的命令将引发一个位于列x上的触发器,即便该列的值没有改变。

有一些内置的触发函数可用于解决常见问题,而无需编写您自己的触发代码。

在一个BEFORE触发器中,WHEN条件正好在函数被或者将被执行之前被计算,因此使用WHEN与在触发器函数的开始测试同一个条件没有实质上的区别。特别注意该条件看到的NEW行是当前值,虽然可能已被早前的触发器所修改。还有,一个BEFORE触发器的WHEN条件不允许检查NEW行的系统列(例如ctid),因为那些列还没有被设置。

在一个AFTER触发器中,WHEN条件正好在行更新发生之后被计算,并且它决定一个事件是否要被放入队列以便在语句的末尾引发该触发器。因此当一个AFTER触发器的WHEN条件不返回真时,没有必要把一个事件放入队列或者在语句末尾重新取得该行。如果触发器只需要为一些行被引发,就能够显著地加快修改很多行的语句的速度。

在一些情况下,单一的SQL命令可能会引发多种触发器。例如,一个带有ON CONFLICT DO UPDATE子句的INSERT可能同时导致插入和更新操作,因此它将根据需要引发这两种触发器。提供给触发器的传递关系与它们的事件类型有关,因此INSERT触发器将只看到被插入的行,而UPDATE触发器将只看到被更新的行。

由外键强制动作导致的行更新或删除(例如ON UPDATE CASCADE或ON DELETE SET NULL)被当做导致它们的SQL命令的一部分。受影响的表上的相关触发器将被引发,这样就提供了另一种方法让SQL命令引发不直接匹配其类型的触发器。在简单的情况中,请求传递关系的触发器将在一个传递关系中看到由原始SQL命令在其表中做出的所有改变。不过,有些情况中一个请求传递关系的AFTER ROW触发器的存在将导致由单个SQL命令触发的外键强制动作被分成多步,每一步都有其自己的传递关系。在这种情况下,没创建一个传递关系集合都会引发存在的所有语句级触发器,确保那些触发器能够在一个传递关系中看到每个受影响的行一次,并且只看到一次。

只有当视图上的动作被一个行级INSTEAD OF触发器处理时才会引发视图上的语句级触发器。

如果动作被一个INSTEAD规则处理,那么该语句发出的任何语句都会代替提及该视图的原始语句执行,这样将被引发的触发器是替换语句中提及的表上的那些触发器。类似地,如果视图是自动可更新的,则该动作将被处理为把该语句自动重写成在视图基表上的一个动作,这样基表的语句级触发器就是要被引发的。

在分区表上创建一个行级触发器将导致在它所有的现有分区上创建相同的触发器,并且以后创建或者挂接的任何分区也将包含一个相同的触发器。 如果该分区与其父分区分离,则触发器将被删除。分区表上的触发器只能是AFTER。

修改分区表或者带有继承子表的表会引发挂接到显式提及表的语句级触发器,但不会引发其分区或子表的语句级触发器。相反,行级触发器会在受影响的分区或子表上引发,即便它们在查询中没有被明确提及。如果一个语句级触发器用REFERENCING子句定义有传递关系,则来自所有受影响分区或子表中的行的前后映像都是可见的。在继承子表的情况中,行映像仅包括该触发器所附属的表中存在的列。当前,不能在分区或继承子表上定义带有传递关系的行级触发器。

例子

只要表accounts的一行即将要被更新时会执行函数check_account_update:

CREATE TRIGGER check_update
BEFORE UPDATE ON accounts
FOR EACH ROW
EXECUTE FUNCTION check_account_update();

下面的例子与上面一个例子相同,但是只在UPDATE命令指定要更新balance列时才执行该函数:

CREATE TRIGGER check_update
BEFORE UPDATE OF balance ON accounts
FOR EACH ROW
EXECUTE FUNCTION check_account_update();

这种形式只有列balance具有真正被改变的值时才执行该函数:

CREATE TRIGGER check_update
BEFORE UPDATE ON accounts
FOR EACH ROW
WHEN (OLD.balance IS DISTINCT FROM NEW.balance)
EXECUTE FUNCTION check_account_update();

调用一个函数来记录accounts的更新,但是只在有东西被改变时才调用:

CREATE TRIGGER log_update
AFTER UPDATE ON accounts
FOR EACH ROW
WHEN (OLD.* IS DISTINCT FROM NEW.*)
EXECUTE FUNCTION log_account_update();

为每一个要插入到视图底层表中的行执行函数view_insert_row:

CREATE TRIGGER view_insert
INSTEAD OF INSERT ON my_view
FOR EACH ROW
EXECUTE FUNCTION view_insert_row();

为每个语句执行函数check_transfer_balances_to_zero以确认transfer的行不会有净值增加:

CREATE TRIGGER transfer_insert
AFTER INSERT ON transfer
REFERENCING NEW TABLE AS inserted
FOR EACH STATEMENT
EXECUTE FUNCTION check_transfer_balances_to_zero();

为每一行执行函数check_matching_pairs以确认(同一个语句)同时对匹配对做了更改 :

CREATE TRIGGER paired_items_update
AFTER UPDATE ON paired_items
REFERENCING NEW TABLE AS newtab OLD TABLE AS oldtab
FOR EACH ROW
EXECUTE FUNCTION check_matching_pairs();

参见

ALTER TRIGGER, DROP TRIGGER, CREATE FUNCTION, SET CONSTRAINTS

CREATE TYPE​

CREATE TYPE --- 定义一种新的数据类型

大纲

CREATE TYPE name AS
( [ attribute_name data_type [ COLLATE collation ] [, ... ] ] )
CREATE TYPE name AS ENUM
( [ 'label' [, ... ] ] )
CREATE TYPE name AS RANGE (
SUBTYPE = subtype
[ , SUBTYPE_OPCLASS = subtype_operator_class ]
[ , COLLATION = collation ]
[ , CANONICAL = canonical_function ]
[ , SUBTYPE_DIFF = subtype_diff_function ]
)
CREATE TYPE name (
INPUT = input_function,
OUTPUT = output_function
[ , RECEIVE = receive_function ]
[ , SEND = send_function ]
[ , TYPMOD_IN = type_modifier_input_function ]
[ , TYPMOD_OUT = type_modifier_output_function ]
[ , ANALYZE = analyze_function ]
[ , INTERNALLENGTH = { internallength | VARIABLE } ]
[ , PASSEDBYVALUE ]
[ , ALIGNMENT = alignment ]
[ , STORAGE = storage ]
[ , LIKE = like_type ]
[ , CATEGORY = category ]
[ , PREFERRED = preferred ]
[ , DEFAULT = default ]
[ , ELEMENT = element ]
[ , DELIMITER = delimiter ]
[ , COLLATABLE = collatable ]
)
CREATE TYPE name

描述

CREATE TYPE在当前数据库中注册一种新的数据类型。定义数据类型的用户将成为它的拥有者。

如果给定一个模式名,那么该类型将被创建在指定的模式中。否则它会被 创建在当前模式中。类型名称必须与同一个模式中任何现有的类型或者域 相区别(因为表具有相关的数据类型,类型名称也必须与同一个模式中任何现有表的名字不同)。

如上面的语法所示,有五种形式的CREATE TYPE。 它们分别创建组合类型、枚举类型、范围类型、基础类型或者 shell 类型。下文将依次讨论前四种形式。shell 类型仅仅是一种用于后面要定义的类型的占位符,通过发出一个不带除类型名之外其 他参数的CREATE TYPE命令可以创建这种类型。在创建范围类型和基础类型时,需要 shell 类型作为一种向前引用。

组合类型

第一种形式的CREATE TYPE创建组合类型。组合类型由一个属性名和数据类型的列表指定。

如果属性的数据类型是可排序的,也可以指定该属性的排序规则。组合类型本质上和表的行类型相同,但是如果只想定义一种类型,使用 CREATE TYPE避免了创建一个实际的表。单独的组合类型也是很有用的,例如可以作为函数的参数或者返回类型。

为了能够创建组合类型,必须拥有在其所有属性类型上的 USAGE特权。

枚举类型

这种形式的 CREATE TYPE创建枚举类型。枚举类型需要一个带引号

的标签构成的列表,每一个标签长度必须不超过64字节。 可以创建具有零个标签的枚举类型,但是在使用ALTER TYPE 添加至少一个标签之前,不能使用这种类型来保存值。

范围类型

范围类型的subtype可以 是任何带有一个相关的 B 树操作符类(用来决定该范围类型值的顺序)的类型。通常,子类型的默认 B 树操作符类被用来决定顺序。要使用一种非默认操作符类,可以用 subtype_opclass指定它 的名字。如果子类型是可排序的并且希望在该范围的顺序中使用一种非默认的 排序规则,可以用collation选项来指定。可选的canonical函数 必须接受一个所定义的范围类型的参数,并且返回同样类型的一个值。在适 用时,它被用来把范围值转换成一种规范的形式。

创建一个 canonical函数有点棘 手,因为必须在声明范围类型之前定义它。要这样做,必须首先创建一种 shell 类型,它是一种没有属性只有名称和拥有者的占位符类型。这可以通过发出不带额外参数的命令CREATE TYPE name来完成。然后可以使用该 shell 类型作为参数和结果来声明该函数,并且最终用同样的名称来声明范围类型。这会自动用一种合法的范围类型替换 shell 类型项。

可选的subtype_diff函数 必须接受两个subtype类型的值作为参数,并且返回一个double precision值表示两个给定值之间的差别。虽然这是可选的,但是提供这个函数会让该范围类型列上 GiST 索引效率更高。

基础类型

第四种形式的CREATE TYPE创建一种新的基本类型(标量类型)。为了创建一种新的基本类型,你必须是一个超级用户(做这种限制的原因是一种错误的类型定义可能让服务器混淆甚至崩溃)。

参数可以以任意顺序出现(而不仅是按照上面所示的顺序),并且大部分是可选的。在定义类型前,必须注册两个或者更多函数(使用 CREATE FUNCTION)。支持函数input_function以及 output_function 是必需的,而函数receive_function、send_function、type_modifier_input_function、 type_modifier_output_function和

analyze_function 是可选的。通常来说这些函数必须是用 C 或者另外一种低层语言编写的。

input_function将类型的外部文本表达转换成为该类型定义的操作符和函数所使用的内部表达。output_function 执行反向的转换。输入函数可以被声明为有一个cstring 类型的参数,或者有三个类型分别为cstring、 oid、integer的参数。第一个参数是以 C 字符串存在的输入文本,第二个参数是该类型自身的 OID(对于 数组类型则是其元素类型的 OID),第三个参数是目标列的 typmod(如果知道,不知道则将传递 -1)。输入函数必须返回一个该数据类型本身的值。通常,一个输入函数应该被声明为 STRICT。如果不是这样,在读到一个 NULL 输入值时,调用它时第一个参数会是 NULL。在这种情况下,该函数必须仍然返回NULL,除非它发生了错误( 这种情况主要是想支持域输入函数,它们可能需要拒绝 NULL 输入)。 输出函数必须被声明为有一个新数据类型的参数。输出函数必须返回类型 cstring。

对于 NULL 值不会调用输出函数。

T可选的receive_function 会把类型的外部二进制表达转换成内部表达。如果没有提供这个函数,该类型不能参与到二进制输入中。二进制表达转换成内部形式代价更低,然而却更容易移植(例如,标准的整数数据类型使用网络字节序作为外部二进制表达,而内部表达是机器本地的字节序)。接收函数应该执行 足够的检查以确保该值是有效的。接收函数可以被声明为有一个 internal类型的参数,或者有三个类型分别为 internal、oid、integer

的参数。第一个参数是一个指向StringInfo缓冲区的指针,其中保存着接收到的字节串。

其余可选的参数和文本输入函数的相同。接收函数必须返回一个该数据类型本身的值。通常,一个接收函数应该被声明为 STRICT。如果不是这样,在读到一个 NULL 输入值时,调用它时第一个参数会是 NULL。在这种情况下,该函数必须仍然返回 NULL,除非它发生了错误(这种情况主要是想支持域接收函数,它们可能需要拒绝NULL 输入)。类似地,可选的 send_function将内部表达转换成外部二进制表达。如果没有提供这个函数,该类型将不能参与到二进制输出中。发送函数必须被声明为有一个新数据类型的参数。发送函数必须返回类型bytea。对于 NULL 值不会调用发送函数。

到这里你应该在疑惑输入和输出函数是如何能被声明为具有新类型的结果或参数的?因为必须在创建新类型之前创建这两个函数。这个问题的答案是,新类型应该首先被定义为一种shell type, 它是一种占位符类型,除了名称和拥有者之外它没有其他属性。这可以通过不带额外参数的命令CREATE TYPE name做到。然后用 C 写的 I/O 函数可以被定义为引用这种 shell type。最后,用带有完整定义的 CREATE TYPE把该 shell type 替换为一个完全的、合法的类型定义,之后新类型就可以正常使用了。

如果该类型支持修饰符(附加在类型声明上的可选约束,例如 char(5)或

者numeric(30,2)),则需要可选的 type_modifier_input_function 以

及type_modifier_output_function。系统允许用户定义的类型有一个或者多个简单常量或者标识符作为修饰符。不过,为了存储在系统目录中,该信息必须能被打包到一个非负整数值中。所声明的修饰符会被以cstring数组的形式传递给type_modifier_input_function。它必须检查该值的合法性(如果值错误就抛出一个错误),如果值正确,要返回 一个非负integer值,它将被存储在"typmod"列中。如果类型没有 type_modifier_input_function 则类型修饰符将被拒绝。

type_modifier_output_function 把内部的整数 typmod 值转换回正确的形式用于用户显示。它必须返回一个 cstring值,该值就是追加到类型名称后的字符串。例如 numeric的函数可能会返回(30,2)。如果默认的显示格式就是只把存储的 typmod 整数值放在圆括号内,则允许省略 type_modifier_output_function。

可选的analyze_function 为该数据类型的列执行与类型相关的统计信息收集。默认情况下,如果该类型有一个默认的B-树操作符类,ANALYZE将尝试用类型的"equals"和"less-than"操作符来收集统计信息。这种行为对于非标量类型并不合适,因此可以通过指定一个自定义分析函数来覆盖这种行为。分析函数必须被声明为有一个类型为internal的参 数,并且返回一个boolean结果。分析函数的详细API请见src/ include/commands/vacuum.h。

虽然只有 I/O 函数和其他为该类型创建的函数才知道新类型的内部表达的细节,但是内部表达的一些属性必须被向系统注册。其中最重要的是 internallength。基本数据类型可以是定长的(这种情况下 internallength是一个正 整数)或者是变长的(把internallength设置为 VARIABLE,在内部通过把typlen设置为 -1 表示)。所有变长类型的内部表达都必须以一个 4 字节整数开始,它给出了这个值的总长度,长度域常常是被编码过的,直接接受它是不明智的)。

可选的标志PASSEDBYVALUE表示这种数据类型的值需要被传值而不是传引用。传值的类型必须是定长的,并且它们的内部表达不能超过Datum类型(某些机器上是 4 字节,其他机器上是 8 字节)的尺寸。

alignment参数指定数据类型的存储对齐要求。允许的值等同于以 1、2、4 或 8 字节边界对齐。注意变长类型的 alignment 参数必须至少为 4,因为它们需要包含一个 int4作为它们的第一个组成部分。

storage参数允许为变长数据类型选择存储策略(对定长类型只允许 plain)。plain指定该类型的数 据将总是被存储在线内并且不会被压缩。extended 指定系统将首先尝试压缩一个长的数据值,并且将在数据仍然太长的情况下把值移出主表行。external允许值被移出主表,但是系统将不会尝试对它进行压缩。main允许压缩,但是不鼓励把值移出主表(如果没有其他办法让行的大小变得合适,具有这种存储策略的数据项仍将被移出主表,但比起extended以及external项来,这种存储策略的数据项会被优先考虑保留在主表中)。

除plain之外所有的 storage值都暗示该数据类型的函数能处理被TOAST 过的值。指定的值仅仅是决定一种可 TOAST 数据类型的列的默认 TOAST存储策略,用户可以使用ALTER TABLE SET STORAGE为列选取其他策略。

like_type参数提供了另一种方法来指定一种数据类型的基本表达属性:从某种现有的类型中拷贝。internallength、 passedbyvalue、 alignment和 storage的值会从指定的类型中复制而来(也可以通过在LIKE子句中指定这些属性的值来覆盖复制过来的值,不过通常并不这么做)。当新类型的低层 实现是以一种现有的类型为"载体"时,用这种方式指定表达特别有用。

category和 preferred参数可以被用来帮助控制在混淆的情况下应用哪一种隐式造型。每一种数据类型都属于一个用单个 ASCII 字符命名的分类,并且每一种类型可以是其所属分类中的"首选"。当有助于解决重载函数或操作符时,解析器将优先 造型到首选类型(但是只能从同类的其他类型造型)。对于没有隐式造型到任意其他类型或者从任意其他类型造型的类型,让这些设置保持默认即可。不过,对于一组具有隐式造型的相关类型,把它们都标记为属于同一个类别并且选择一种或两种"最常用"的类型

作为该类别的首选通常是很有用的。在把一种用户定义的类型增加到一个现有的内建类别(例如数字或者字符串 类型)中时,category参数特别用。不过,也可以创建新的全部是用户定义类型的类别。对这样的类别,可选择除大写字母之外的任何 ASCII 字符。

如果用户希望该数据类型的列被默认为某种非空值,可以指定一个默认值。 默认值可以

用DEFAULT关键词指定(这样一个默认值可以被附加到一个特定列的显式DEFAULT子句覆盖)。

要指定一种类型是数组,用ELEMENT关键词指定该数组元素的类型。例如,要定义一个 4 字节整数的数组(int4),应指定ELEMENT = int4。更多有关数组类型的细节请见下文。

要指定在这种类型数组的外部表达中分隔值的定界符,可以把delimiter设置为一个特定字符。默认的定界符是逗号(,)。注意定界符是与数组元素类型相 关的,而不是数组类型本身相关。

如果可选的布尔参数 collatable为真,这种类型的列定义和表达式可能通过使用COLLATE子句携带有排序规则信息。在该类型上操作的函数的实现负责真正利用这些信息,仅把类型标记为可排序的并不会让它们自动地去使用这类信息。

数组类型

只要一种用户定义的类型被创建,系统会自动地创建一种相关的数组类型,其名称由元素类型的名称前面加上一个下划线组成,并且如果长度超过NAMEDATALEN字节会自动地被截断(如果这样生成的名称与一种现有类型的名称冲突,该过程将会重复直到找到一个不冲突的名字)。这种隐式创建的数组类型是变长的并且使用内建的输入和输出函数(array_in以及array_out)。该数组类型会追随其元素类型的拥有者或所在模式的任何更改,并且在元素类型被删除时也被删除。

如果系统会自动地创建正确的数组类型,你可能会很合情合理地问为什么 会有一个ELEMENT选项。使用ELEMENT唯一有用的情况是:当你在创建一种定长类型,它正好在内部是一个多个相同东西的数组,并且除了计划给该类型提供的整体操作之外,你想要允许用下标来直接访问这些东西。例如,类型point被表示 为两个浮点数,可以使用point[0]以及point[1] 来访问它们。注意,这种功能只适用于内部形式正好是一个相同定长域序列的定长类型。可用下标访问的变长类型必须具有 array_in以及array_out使用的一般化的内部表达。由于历史原因(即很明显是错的,但现在改已经太晚了),定长数组类型的下标是从零开始的,而不是像变长数组那样。

参数

name

要创建的类型的名称(可以被模式限定)。

attribute_name

组合类型的一个属性(列)的名称。

data_type

要成为组合类型的一个列的现有数据类型的名称。

collation

要关联到组合类型的一列或者范围类型的现有排序规则的名称。

label

一个字符串,它表达与枚举类型的一个值相关的文本标签。

subtype

范围类型的元素类型的名称,范围类型表示的范围属于该类型。

subtype_operator_class

用于 subtype 的 B 树操作符类的名称。

canonical_function

范围类型的规范化函数的名称。

subtype_diff_function

用于 subtype 的差函数的名称。

input_function

将数据从类型的外部文本形式转换为内部形式的函数名。

output_function

将数据从类型的内部形式转换为外部文本形式的函数名。

receive_function

将数据从类型的外部二进制形式转换成内部形式的函数名。

send_function

将数据从类型的内部形式转换为外部二进制形式的函数名。

type_modifier_input_function

将类型的修饰符数组转换为内部形式的函数名。

type_modifier_output_function

将类型的修饰符的内部形式转换为外部文本形式的函数名。

analyze_function

为该数据类型执行统计分析的函数名。

internallength

一个数字常量,它指定新类型的内部表达的字节长度。默认的假设是它是变长的。

alignment

该数据类型的存储对齐需求。如果被指定,它必须是 char、int2、 int4或者double。

默认是 int4。

storage

该数据类型的存储策略。如果被指定,必须是 plain、external、 extended或者main。

默认是plain。

like_type

与新类型具有相同表达的现有数据类型的名称。会从这个类型中复制 internallength、passedbyvalue、alignment以及 storage的值(除非在这个CREATE TYPE命令的其他地方用显式说明覆盖)。

category

这种类型的分类码(一个 ASCII 字符)。默认是"用户定义类型"的'U'。其他的标准分类码可见表 51.63 。为了创建自定义分类,你也可以选择其他 ASCII 字符。

preferred

如果这种类型是其类型分类中的优先类型则为真,否则为假。默认为假。在一个现有类型分类中创建一种新的优先类型要非常小心,因为这可能会导致行为上令人惊奇的改变。

default

数据类型的默认值。如果被省略,默认值是空。

element

被创建的类型是一个数组,这指定了数组元素的类型。

delimiter

在由这种类型组成的数组中值之间的定界符。

collatable

如果这个类型的操作可以使用排序规则信息,则为真。默认为假。

注解

由于一旦数据类型被创建,对该数据类型的使用就没有限制,创建一种基本类型或者范围类型就等同于在类型定义中提到的函数上授予公共执行权限。对于在类型定义中有用的函数来说这通常不是问题。但是如果设计一种类型时要求在转换到外部形式或者从外部形式转换时使用"秘密"信息,你就应该三思而后行。因此类型名称的长度限制比其他名称还要少一个字符。虽然现在这仍然是通常情况,但如果名称达到最大长度或者与其他下划线开头的用户类型名称冲突,数组类型的名称也可以不同于这种规则。因此依靠这种习惯编写代码现在已经不适用了。现在,可以使用 pg_type.typarray来定位与给定类型相关 的数组类型。

建议避免使用以下划线开始的类型名和表名。虽然服务器会改变生成的数组 类型名称以避免与用户给定的名称冲突,仍然有混淆的风险,特别是对旧的 客户端软件来说,它们可能会假定以下划线开始的类型名总是表示数组。

创建一种新基本类型的方法是先创建它的输入函数。系统首先把新数据类型的名称看做是输入函数的返回类型。在这种情况下 shell type 会被隐式地创建,并且能在剩余的 I/O 函数的定义中引用。这种方法现在仍然有效,但是已经被弃用并且可能会在未来的某个发行中被禁止。还有,为了避免由于函数定义中的打字错误导致 shell type弄乱系统目录,当输入函数用 C 编写时,将只能用这种方法创建一种 shell type。

示例

这个例子创建了一种组合类型并且将其用在了一个函数定义中:

CREATE TYPE compfoo AS (f1 int, f2 text);
CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS \$\$
SELECT fooid, fooname FROM foo
\$\$ LANGUAGE SQL;

这个例子创建了一个枚举类型并且将其用在一个表定义中:

CREATE TYPE bug_status AS ENUM ('new', 'open', 'closed');
CREATE TABLE bug (
id serial,
description text,
status bug_status
);

这个例子创建了一个范围类型:

CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);

这个例子创建了基本数据类型box然后将它用在一个表定义中:

CREATE TYPE box;
CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ;
CREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ;
CREATE TYPE box (
INTERNALLENGTH = 16,
INPUT = my_box_in_function,
OUTPUT = my_box_out_function
);
CREATE TABLE myboxes (
id integer,
description box
);

如果box的内部结构是四个 float4元素的一个数组,我们可能会使用:

CREATE TYPE box (
INTERNALLENGTH = 16,
INPUT = my_box_in_function,
OUTPUT = my_box_out_function,
ELEMENT = float4
);

这将允许用下标来访问一个 box 值的组件编号。否则该类型的行为和前面的一样。

这个例子创建了一个大对象类型并且将它用在了一个表定义中:

CREATE TYPE bigobj (
INPUT = lo_filein, OUTPUT = lo_fileout,
INTERNALLENGTH = VARIABLE
);
CREATE TABLE big_objs (
id integer,
obj bigobj
);

另见

ALTER TYPE, CREATE DOMAIN, CREATE FUNCTION, DROP TYPE