PostgreSQL 13.1 中文入门教程 PostgreSQL CREATE TABLE

2024-02-25 开发教程 PostgreSQL 13.1 中文入门教程 匿名 3

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特权。

参数

TEMPORARYor TEMP

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

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

可以选择将GLOBALLOCAL写在TEMPORARYTEMP的前面。这当前在PostgreSQL中没有区别并且已被废弃,见本文中的​Compatibility。

UNLOGGED

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

IF NOT EXISTS

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

table_name

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

OF type_name

创建一个类型化的表,它的结构取自于指定的组合类型(名字可以选择用模式限定)。一个类型化的表和它的类型绑定在一起,例如如果类型被删除,该表也将被删除(用DROP TYPE ... CASCADE)。

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

column_name

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

data_type

列的数据类型. 这可以包括数组 规格. 有关PostgreSQL支持数据类型的详细信息, 请参考第 8 章.

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个,但在构建 PostgreSQL时可以更改此限制), 但对于列表分区,分区键必须由单个列或表达式组成。

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

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

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

有关表分区的更多讨论,请参阅第 5.11 节

PARTITION OF parent_table{ FOR VALUES partition_bound_spec| DEFAULT }

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

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

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

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

创建范围分区时,由FROM指定的下限是一个包含范围, 而用TO指定的上限是排除范围。也就是说, 在FROM列表中指定的值是该分区的相应分区键列的有效值, 而TO列表中的值不是。请注意, 必须根据按行比较的规则来理解此语句(第 9.24.5 节)。 例如,给定PARTITION BY RANGE (x,y),分区范围 FROM (1, 2) TO (3, 4)允许x=1与任何y>=2x=2与任何非空 y,和x=3与任何y<4

在创建范围分区以指示列值没有下限或上限时,可以使用特殊值MINVALUEMAXVALUE。例如,使用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"开头的任何行。

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

还要注意,某些元素类型,如timestamp,具有“无穷”的概念, 这只是另一个可以存储的值。这与MINVALUEMAXVALUE不同, 它们不是可以存储的实际值,而是它们表示值无界的方式。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 KEYUNIQUEEXCLUDE约束将被建立在新表上。 根据默认规则选择新索引和约束的名称,而不考虑原始的命名。(此行为可避免新索引可能出现重复名称失败。)

INCLUDING STATISTICS

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

INCLUDING STORAGE

已复制列定义的STORAGE设置将被复制。 默认行为是排除STORAGE设置,从而导致新表中已复制列具有类型规定的默认设置。 关于STORAGE设置的更多信息,参见第 68.2 节。

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表达式不能包含子查询,也不能引用当前行的列之外的变量(参见 第 5.4.1 节)。可以引用系统列tableoid,但不能引用其他系统列。

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

当一个表有多个CHECK约束时,检查完NOT NULL约束后,对于每一行会以它们名称的字母表顺序来进行检查(版本 9.5 之前的PostgreSQL对于CHECK约束不遵从任何特定的引发顺序)。

DEFAULT default_expr

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

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

GENERATED ALWAYS AS ( generation_expr) STORED

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

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

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

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

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

子句ALWAYSBY DEFAULT确定如何在 INSERTUPDATE命令中明确处理用户指定的值。

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强制的数据约束可以看成是UNIQUENOT NULL的组合, 不过把一组列标识为主键也为模式设计提供了元数据,因为主键标识其他表可以依赖这一个列集合作为行的唯一标识符。

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

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

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

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

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

中有完整描述。

访问方法必须支持amgettuple(见第 61 章),目前这意味着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 FULLMATCH 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是默认值。当前,只有 UNIQUEPRIMARY KEYEXCLUDE以及REFERENCES(外键)约束接受这个子句。NOT NULL以及CHECK约束是不可延迟的。注意在包括ON CONFLICT DO UPDATE子句的 INSERT语句中,可延迟约束不能被用作冲突裁判者。

INITIALLY IMMEDIATE
INITIALLY DEFERRED

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

命令修改。

USING method

此可选子句指定用于存储新表内容的表访问方法;该方法需要的是类型TABLE的访问方法。详见 第 60 章 。 如果未指定此选项,则为新表选择默认表访问方法。详见default_table_access_method。

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

这个子句为一个表或索引指定可选的存储参数,详见本文中的存储参数 。 为了向后兼容性,表的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

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

存储参数

WITH子句能够为表或与一个UNIQUEPRIMARY KEY或者EXCLUDE约束相关的索引指定存储参数。 用于索引的存储参数已经在CREATE INDEX中介绍过。 当前可用于表的存储参数在下文中列出。 如下文所示,对于很多这类参数,都有一个名字带有toast.前缀的附加参数,它能被用来控制该表的二级TOAST表(如果存在)的行为(关于 TOAST 详见第 68.2 节)。 如果一个表的参数值被设置但是相应的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)

为一个特定的表启用或者禁用自动清理守护进程。如果为真,自动清理守护进程将遵照第 24.1.6 节中讨论的规则在这个表上执行自动的VACUUM或者ANALYZE操作。如果为假,这个表不会被自动清理,不过为了阻止事务 ID 回卷时还是会对它进行自动的清理。有关回卷阻止请见第 24.1.5 节。如果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。 如果trueVACUUM和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)

声明该表是一个用于逻辑复制目的的额外的目录表。详见第 48.6.2 节。不能对 TOAST 表设置这个参数。

注解

PostgreSQL为每一个唯一约束和主键约束创建一个索引来强制唯一性。因此,没有必要显式地为主键列创建一个索引(详见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 标准的语法,但事实是并不相同。在标准中,临时表只需要被定义一次并且会自动地存在(从空内容开始)于需要它们的每一个会话中。PostgreSQL则要求每一个会话为每一个要用的临时表发出它自己的CREATE TEMPORARY TABLE命令。这允许不同的会话为不同的目的使用相同的临时表名,而标准的方法约束一个给定临时表名的所有实例都必须具有相同的表结构。

标准中对于临时表行为的定义被广泛地忽略了。PostgreSQL在这一点上的行为和多种其他 SQL 数据库是相似的。

SQL 标准也区分全局和局部临时表,其中一个局部临时表为每一个会话中的每一个 SQL 模块具有一个独立的内容集合,但是它的定义仍然是多个会话共享的。因为PostgreSQL不支持 SQL 模块,这种区别与PostgreSQL无关。

为了兼容性目的,PostgreSQL将在临时表声明中接受GLOBALLOCAL关键词,但是它们当前没有效果。我们不鼓励使用这些关键词,因为未来版本的PostgreSQL可能采用一种更兼容标准的(对它们含义的)解释。

临时表的ON COMMIT子句也和 SQL 标准相似,但是有一些不同。如果忽略ON COMMIT子句,SQL 指定默认行为是ON COMMIT DELETE ROWS。但是,PostgreSQL中的默认行为是ON COMMIT PRESERVE ROWS。SQL 中不存在ON COMMIT DROP选项。

非延迟唯一性约束

但一个UNIQUEPRIMARY KEY约束是非可延迟的,只要一个行被插入或修改,PostgreSQL就会立即检查唯一性。SQL 标准指出只有在语句结束时才应该强制唯一性。当一个单一命令更新多个键值时,这两者是不同的。要得到兼容标准的行为,将该约束声明为DEFERRABLE但是不延迟(即 INITIALLY IMMEDIATE)。注意这可能要显著地慢于立即唯一性检查。

列检查约束

SQL 标准指出CHECK列约束只能引用它们应用到的列,只有CHECK表约束能够引用多列。PostgreSQL并没有强制这个限制,它同样处理列检查约束和表检查约束。

EXCLUDE约束

EXCLUDE约束类型是一种PostgreSQL扩展。

NULL“约束”

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

Constraint Naming

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

当前,PostgreSQL没有记录NOT NULL约束的名称, 因此它们不受唯一性限制的影响。这在将来的版本中可能会改变。

继承

通过INHERITS子句的多继承是一种PostgreSQL的语言扩展。SQL:1999 以及之后的标准使用一种不同的语法和不同的语义定义了单继承。SQL:1999-风格的继承还没有被PostgreSQL。

零列表

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

多个标识列

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

Generated Columns

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

LIKE子句

虽然 SQL 标准中有一个LIKE子句,但是PostgreSQL接受的很多LIKE子句选项却不在标准中,并且有些标准中的选项也没有被PostgreSQL实现。

WITH子句

WITH子句是一个PostgreSQL扩展,存储参数不在标准中。

表空间

PostgreSQL的表空间概念不是标准的一部分。因此,子句TABLESPACEUSING INDEX TABLESPACE是扩展。

类型化的表

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

PARTITION BY子句

PARTITION BY子句是PostgreSQL的一个扩展。

PARTITION OF子句

PARTITION OF子句PostgreSQL的一个扩展。

参见

ALTER TABLE

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