Tip

CREATE TABLE

CREATE TABLE —定义一个新表

Synopsis

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 ] [, ... ] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | 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 ] [, ... ] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | 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 ] [, ... ] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE tablespace_name ]

where column_constraint is:

[ CONSTRAINT constraint_name ]
{ NOT NULL |
  NULL |
  CHECK ( expression ) [ NO INHERIT ] |
  DEFAULT default_expr |
  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 action ] [ ON UPDATE action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

and table_constraint is:

[ 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 action ] [ ON UPDATE action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

and like_option is:

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

and partition_bound_spec is:

IN ( { numeric_literal | string_literal | TRUE | FALSE | NULL } [, ...] ) |
FROM ( { numeric_literal | string_literal | TRUE | FALSE | MINVALUE | MAXVALUE } [, ...] )
  TO ( { numeric_literal | string_literal | TRUE | FALSE | MINVALUE | MAXVALUE } [, ...] ) |
WITH ( MODULUS numeric_literal, REMAINDER numeric_literal )

index_parameters in UNIQUE, PRIMARY KEY, and EXCLUDE constraints are:

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

exclude_element in an EXCLUDE constraint is:

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

Description

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

如果指定了架构名称(例如CREATE TABLE myschema.mytable ...),则会在指定的架构中创建表。否则,它将在当前架构中创建。临时表存在于特殊的架构中,因此在创建临时表时无法给出架构名称。该表的名称必须与同一架构中任何其他表,序列,索引,视图或外部表的名称不同。

CREATE TABLE还会自动创建一个数据类型,该数据类型表示与表的一行相对应的复合类型。因此,表不能与同一模式中的任何现有数据类型具有相同的名称。

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

有两种定义约束的方法:表约束和列约束。列约束被定义为列定义的一部分。表约束定义不限于特定的列,它可以包含多个列。每个列约束也可以写为表约束。当列约束仅影响一列时,列约束仅是一种使用上的符号方便。

为了能够创建表,您必须分别对所有列类型或OF子句中的类型具有USAGE特权。

Parameters

  • TEMPORARYTEMP
    • 如果指定,该表将被创建为临时表。临时表将在会话结束时或当前事务结束时自动删除(请参见下面的ON COMMIT)。临时表存在时,具有相同名称的现有永久表在当前会话中不可见,除非使用架构限定名称引用它们。在临时表上创建的所有索引也会自动成为临时索引。

autovacuum daemon无法访问,因此无法清理或分析临时表。因此,应通过会话 SQL 命令执行适当的清理和分析操作。例如,如果要在复杂查询中使用临时表,则在填充后在临时表上运行ANALYZE是明智的。

可以选择在TEMPORARYTEMP之前写入GLOBALLOCAL。目前,这在 PostgreSQL 中没有区别,不建议使用;参见Compatibility

  • UNLOGGED

    • 如果指定,该表将创建为未记录表。写入未记录表的数据不会写入预写日志(请参见Chapter 30),这使得它们比普通表快得多。但是,它们不是崩溃安全的:崩溃或异常关闭后,未记录的表会自动被截断。未记录表的内容也不会复制到备用服务器。在未记录表上创建的所有索引也会自动取消记录。
  • IF NOT EXISTS

    • 如果已经存在同名关系,则不要抛出错误。在这种情况下发出通知。请注意,不能保证现有关系类似于将要创建的关系。
  • table_name

    • 要创建的表的名称(可选的模式限定)。
  • OF type_name

    • 创建一个* typeed table *,它从指定的复合类型(名称(可选,模式限定))获取其结构。有类型的表与其类型相关联。例如,如果类型被删除(带有DROP TYPE ... CASCADE),表将被删除。

创建类型表时,列的数据类型由基础复合类型确定,而不由CREATE TABLE命令指定。但是CREATE TABLE命令可以向表中添加默认值和约束,并可以指定存储参数。

  • column_name

    • 要在新表中创建的列的名称。
  • data_type

    • 列的数据类型。这可以包括数组说明符。有关 PostgreSQL 支持的数据类型的更多信息,请参考Chapter 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子句指定对表进行分区的策略。这样创建的表称为* partitioned 表。列或表达式的带括号的列表构成表的分区键*。使用范围分区或哈希分区时,分区键可以包括多个列或表达式(最多 32 个,但是在构建 PostgreSQL 时可以更改此限制),但是对于列表分区,分区键必须由单个列或表达式组成。

范围和列表分区需要 btree 运算符类,而哈希分区需要哈希运算符类。如果未明确指定运算符类别,则将使用适当类型的默认运算符类别;否则,将使用默认运算符类别。如果不存在默认的运算符类,将引发错误。使用散列分区时,使用的运算符类必须实现支持功能 2(有关详细信息,请参见Section 38.15.3)。

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

分区表不支持EXCLUDE约束;但是,您可以在单个分区上定义这些约束。另外,虽然可以在分区表上定义PRIMARY KEY约束,但尚不支持创建引用分区表的外键。

有关表分区的更多讨论,请参见Section 5.10

  • PARTITION OF parent_table { FOR VALUES partition_bound_spec | DEFAULT }
    • 创建表作为指定父表的“分区”。该表既可以使用FOR VALUES创建为特定值的分区,也可以使用DEFAULT创建为默认分区。父表中存在的所有索引,约束和用户定义的行级触发器都将克隆到新分区上。
  • partition_bound_spec *必须与父表的分区方法和分区键相对应,并且不得与该父表的任何现有分区重叠。具有IN的形式用于列表分区,具有FROMTO的形式用于范围分区,具有WITH的形式用于哈希分区。

  • partition_bound_spec *中指定的每个值都是 LiteralsNULLMINVALUEMAXVALUE。每个 Literals 值必须是可转换为相应分区键列的类型的数字常量,或者是该类型的有效 Importing 的字符串 Literals。

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

创建范围分区时,用FROM指定的下限是一个包含边界,而用TO指定的上限是一个排他边界。也就是说,在FROM列表中指定的值是此分区的相应分区键列的有效值,而在TO列表中的值不是。请注意,必须根据行比较规则(Section 9.23.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)不是空范围;它只允许存储一个值-“无穷大”。

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

当表具有现有的DEFAULT分区并向其添加新分区时,必须扫描默认分区以验证其不包含任何正确属于新分区的行。如果默认分区包含大量行,这可能会很慢。如果默认分区是一个外部表,或者如果它具有一个约束,证明它不能包含应放在新分区中的行,则将跳过扫描。

创建哈希分区时,必须指定模数和余数。模数必须为正整数,其余部分必须为小于模数的非负整数。通常,在最初设置哈希分区表时,应选择等于分区数的模数,并为每个表分配相同的模数和不同的余数(请参见下面的示例)。但是,不需要每个分区都具有相同的模量,仅要求哈希散列表的各分区之间出现的每个模量是下一个更大模量的因素即可。这允许分区数量逐渐增加,而无需一次移动所有数据。例如,假设您有一个具有 8 个分区的哈希分区表,每个分区的模数为 8,但是发现有必要将分区数增加到 16.您可以分离一个 8 模数的分区,创建两个新模数-16 个分区覆盖键空间的相同部分(一个分区的剩余数等于分离分区的其余部分,另一个分区的剩余数等于该值加上 8),并用数据重新填充它们。然后,您可以为每个模数 8 分区重复此操作(也许以后再进行一次),直到没有剩余为止。尽管这可能仍然需要在每个步骤中进行大量的数据移动,但是比必须创建一个新表并立即移动所有数据要好。

分区必须具有与其所属分区表相同的列名和类型。如果将父级指定为WITH OIDS,则所有分区都必须具有 OID;否则,所有分区都必须具有 OID。父级的 OID 列将被所有分区继承,就像其他任何列一样。修改分区表的列名或类型,或添加或删除 OID 列,将自动传播到所有分区。每个分区都会自动继承CHECK约束,但是单个分区可以指定其他CHECK约束;具有与父级中相同名称和条件的其他约束将与父级约束合并。可以为每个分区分别指定默认值。但是请注意,通过分区表插入 Tuples 时,不会应用分区的默认值。

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

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

  • LIKE source_table [ like_option ... ]

    • LIKE子句指定一个表,新表将从该表中自动复制所有列名,其数据类型及其非空约束。

INHERITS不同,新表和原始表在创建完成后完全解耦。对原始表的更改将不会应用于新表,并且无法在原始表的扫描中包括新表的数据。

仅当指定INCLUDING DEFAULTS时,才会复制复制的列定义的默认表达式。默认行为是排除默认表达式,导致新表中复制的列具有空默认值。请注意,复制默认值会调用数据库修改功能,例如nextval,可能会在原始表和新表之间创建功能链接。

仅当指定INCLUDING IDENTITY时,才会复制复制的列定义的任何标识规范。为新表的每个标识列创建一个新序列,该序列与与旧表关联的序列分开。

非空约束始终会复制到新表中。仅当指定INCLUDING CONSTRAINTS时,才会复制CHECK约束。列约束和表约束之间没有区别。

如果指定了INCLUDING STATISTICS,则扩展统计信息将复制到新表中。

仅当指定INCLUDING INDEXES时,才会在新表上创建原始表的索引PRIMARY KEYUNIQUEEXCLUDE约束。不论原始名称如何命名,都会根据默认规则选择新索引和约束的名称。 (此行为避免了新索引可能出现的重复名称错误.)

仅当指定INCLUDING STORAGE时,才会复制复制的列定义的STORAGE设置。默认行为是排除STORAGE设置,导致新表中复制的列具有特定于类型的默认设置。有关STORAGE设置的更多信息,请参见Section 68.2

仅当指定INCLUDING COMMENTS时,才会复制复制的列,约束和索引的 Comments。默认行为是排除 Comments,导致新表中复制的列和约束没有 Comments。

INCLUDING ALLINCLUDING COMMENTS INCLUDING CONSTRAINTS INCLUDING DEFAULTS INCLUDING IDENTITY INCLUDING INDEXES INCLUDING STATISTICS INCLUDING STORAGE的缩写形式。

请注意,与INHERITS不同,由LIKE复制的列和约束不会与名称相似的列和约束合并。如果显式指定了相同的名称,或在另一个LIKE子句中指定了名称,则将指示错误。

LIKE子句还可用于从视图,外部表或组合类型中复制列定义。不适用的选项(例如,视图中的INCLUDING INDEXES)将被忽略。

  • CONSTRAINT constraint_name

    • 列或表约束的可选名称。如果违反了约束,则约束名称将出现在错误消息中,因此可以使用诸如col must be positive之类的约束名称来将有用的约束信息传达给 Client 端应用程序。 (需要双引号指定包含空格的约束名称.)如果未指定约束名称,则系统将生成一个名称。
  • NOT NULL

    • 该列不允许包含空值。
  • NULL

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

提供此子句仅是为了与非标准 SQL 数据库兼容。不建议在新应用程序中使用它。

  • CHECK ( expression ) [ NO INHERIT ]

    • CHECK子句指定一个生成布尔结果的表达式,新的或更新的行必须满足这些条件,插入或更新操作才能成功。评估为 TRUE 或 UNKNOWN 的表达式成功。如果插入或更新操作的任何行都产生 FALSE 结果,则会引发错误异常,并且插入或更新不会更改数据库。指定为列约束的检查约束应仅引用该列的值,而出现在表约束中的表达式可以引用多个列。

当前,CHECK表达式不能包含子查询,也不能引用当前行的列以外的变量(请参见Section 5.3.1)。可以引用系统列tableoid,但不能引用任何其他系统列。

标有NO INHERIT的约束将不会传播到子表。

当一个表具有多个CHECK约束时,将在检查NOT NULL约束后按名称的字母 Sequences 对每一行进行测试。 (对于CHECK约束,PostgreSQL 9.5 之前的版本不遵循任何特定的触发 Sequences.)

  • DEFAULT default_expr

    • DEFAULT子句为出现在其列定义中的列分配默认数据值。该值是任何无变量的表达式(不允许对当前表中的其他列进行子查询和交叉引用)。默认表达式的数据类型必须与列的数据类型匹配。

默认表达式将在未为列指定值的任何插入操作中使用。如果列没有默认值,则默认值为 null。

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

    • 此子句将列创建为* identity column *。它将附加一个隐式序列,并且新行中的列将自动具有分配给它的序列中的值。

子句ALWAYSBY DEFAULT确定如何在INSERT语句中给序列值优先于用户指定的值。如果指定了ALWAYS,则仅当INSERT语句指定OVERRIDING SYSTEM VALUE时才接受用户指定的值。如果指定BY DEFAULT,则用户指定的值优先。有关详情,请参见INSERT。 (在COPY命令中,无论此设置如何,始终使用用户指定的值.)

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

  • UNIQUE(列约束)
    UNIQUE ( column_name [, ... ] ) INCLUDE(* +166+ * [,...])

    • UNIQUE约束指定表的一组一个或多个列只能包含唯一值。唯一表约束的行为与列约束的行为相同,但具有跨多个列的附加功能。

出于唯一约束的目的,空值不视为相等。

每个唯一表约束必须命名一组列,该列与为该表定义的任何其他唯一或主键约束所命名的列不同。 (否则,它将是相同的约束两次列出.)

为多级分区层次结构构建唯一约束时,目标分区表的分区键中的所有列以及其所有后代分区表的列都必须包含在约束定义中。

添加唯一约束将在约束中使用的列或一组列上自动创建唯一的 btree 索引。可选子句INCLUDE向该索引添加了一个或多个不强制执行唯一性的列。请注意,尽管未对包含的列强制实施约束,但仍取决于它们。因此,对这些列的某些操作(例如DROP COLUMN)可能会导致级联约束和索引删除。

  • PRIMARY KEY(列约束)
    PRIMARY KEY ( column_name [, ... ] ) INCLUDE(* +172+ * [,...])

    • PRIMARY KEY约束指定表的一列或多列只能包含唯一(非重复)非 null 值。只能为一个表指定一个主键,无论是作为列约束还是表约束。

主键约束应命名一组与由同一张表定义的唯一约束所命名的列不同的一组列。 (否则,唯一约束是多余的,将被丢弃.)

PRIMARY KEY强制执行与UNIQUENOT 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约束,尽管普通的唯一约束会更快。但是,排除约束可以指定比简单等式更笼统的约束。例如,您可以使用&&运算符指定一个约束,使得表中的任何两行都不能包含重叠的圆(请参见Section 8.8)。

排除约束是使用索引实现的,因此对于索引访问方法* index_method ,每个指定的运算符都必须与一个适当的运算符类(请参见Section 11.10)相关联。运算符必须是可交换的。每个 exclude_element *可以选择指定操作员类别和/或 Order 选项;这些在CREATE INDEX下有完整描述。

访问方法必须支持amgettuple(请参见Chapter 61);目前,这意味着无法使用 GIN。尽管允许使用,但将 B 树或哈希索引与排除约束一起使用几乎没有意义,因为这无异于普通的唯一约束不能做得更好。因此,实际上,访问方法将始终是 GiST 或 SP-GiST。

  • predicate *允许您在表的子集上指定排除约束;在内部创建一个局部索引。请注意,谓词周围需要括号。
  • REFERENCES reftable [ ( refcolumn ) ] [ MATCH matchtype ] [ ON DELETE action ] [ ON UPDATE action ](列约束)
    FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ] [ MATCH matchtype ] [ ON DELETE action ] [ ON UPDATE action ](表格约束)

    • 这些子句指定外键约束,这要求新表的一组一列或多列必须仅包含与被引用表的某行的被引用列中的值匹配的值。如果省略* refcolumn 列表,则使用 reftable *的主键。引用的列必须是引用表中不可延迟的唯一或主键约束的列。用户必须对被引用的表(整个表或特定的被引用的列)具有REFERENCES权限。外键约束的添加要求在引用表上具有SHARE ROW EXCLUSIVE锁。注意,不能在临时表和永久表之间定义外键约束。还要注意,虽然可以在分区表上定义外键,但不能声明引用分区表的外键。

使用给定的匹配类型,将插入到引用列中的值与引用表和引用列的值进行匹配。共有三种匹配类型:MATCH FULLMATCH PARTIALMATCH SIMPLE(这是默认值)。 MATCH FULL不允许多列外键的一列为空,除非所有外键列都为空;否则,否则为 0.如果它们全为空,则不需要该行在引用表中具有匹配项。 MATCH SIMPLE允许任何外键列为空;如果它们中的任何一个为 null,则不需要该行在引用表中具有匹配项。 MATCH PARTIAL尚未实现。 (当然,可以将NOT NULL约束应用于引用列,以防止出现这些情况.)

另外,当更改引用列中的数据时,将对该表的列中的数据执行某些操作。 ON DELETE子句指定在删除引用表中的引用行时要执行的操作。同样,ON UPDATE子句指定在将引用表中的引用列更新为新值时执行的操作。如果该行已更新,但所引用的列实际上未更改,则不会执行任何操作。即使NO ACTION检查没有被声明为可延迟,也不能延迟引用动作。每个子句有以下可能的操作:

  • NO ACTION

    • 产生一个错误,指示删除或更新将导致违反外键约束。如果推迟约束,则如果仍然存在任何引用行,则会在约束检查时产生此错误。这是默认操作。

    • RESTRICT

      • 产生一个错误,指示删除或更新将导致违反外键约束。除支票不可延期外,其他与NO ACTION相同。
    • CASCADE

      • 删除引用已删除行的所有行,或将引用列的值分别更新为被引用列的新值。
    • SET NULL

      • 将引用列设置为 null。
    • SET DEFAULT

      • 将引用列设置为其默认值。 (如果默认值不为 null,则引用表中必须存在与默认值匹配的行,否则该操作将失败.)

如果引用列频繁更改,向索引列添加索引可能是明智的选择,这样可以更有效地执行与外键约束关联的引用动作。

  • DEFERRABLE
    NOT DEFERRABLE

    • 这控制是否可以推迟约束。每个命令之后,将立即检查不可延迟的约束。可以推迟检查约束,直到事务结束(使用SET CONSTRAINTS命令)。 NOT DEFERRABLE是默认值。当前,只有UNIQUEPRIMARY KEYEXCLUDEREFERENCES(外键)约束接受此子句。 NOT NULLCHECK约束不可延期。请注意,可延迟约束不能用作包含ON CONFLICT DO UPDATE子句的INSERT语句中的冲突仲裁程序。
  • INITIALLY IMMEDIATE
    INITIALLY DEFERRED

    • 如果约束是可延迟的,则此子句指定检查约束的默认时间。如果约束是INITIALLY IMMEDIATE,则在每个语句之后对其进行检查。这是默认值。如果约束为INITIALLY DEFERRED,则仅在事务结束时进行检查。约束检查时间可以使用SET CONSTRAINTS命令更改。
  • WITH ( storage_parameter [= value] [, ... ] )

    • 此子句为表或索引指定可选的存储参数。有关更多信息,请参见Storage Parameters。表的WITH子句还可以包含OIDS=TRUE(或仅包含OIDS)以指定新表的行应具有为其分配的 OID(对象标识符),或OIDS=FALSE可以指定该行不应具有 OID。如果未指定OIDS,则默认设置取决于default_with_oids配置参数。 (如果新表继承自具有 OID 的任何表,那么即使命令说OIDS=FALSE,也将强制OIDS=TRUE.)

如果指定或隐含了OIDS=FALSE,则新表不存储 OID,并且不会为插入其中的行分配任何 OID。通常认为这是值得的,因为这将减少 OID 消耗,从而推迟 32 位 OID 计数器的环绕。一旦计数器回绕,就不再可以认为 OID 是唯一的,这使 OID 的用途大大减少。此外,从表中排除 OID 可以将表存储在磁盘上所需的空间每行减少 4 个字节(在大多数计算机上),从而略微提高了性能。

要在创建表后从表中删除 OID,请使用ALTER TABLE

  • WITH OIDS
    WITHOUT OIDS

    • 这些是分别等于WITH (OIDS)WITH (OIDS=FALSE)的过时语法。如果希望同时提供OIDS设置和存储参数,则必须使用WITH ( ... )语法;往上看。
  • ON COMMIT

    • 可以使用ON COMMIT来控制事务块末尾的临时表的行为。这三个选项是:
  • PRESERVE ROWS

    • Transaction 结束时不会采取任何特殊措施。这是默认行为。

    • DELETE ROWS

      • 临时表中的所有行将在每个事务块的末尾删除。本质上,每次提交都会自动执行TRUNCATE。在分区表上使用时,它不会级联到其分区。
    • DROP

      • 临时表将在当前事务块的末尾删除。在分区表上使用时,此操作将删除其分区;在具有继承子级的表上使用时,此操作将删除从属子级。
  • TABLESPACE tablespace_name

      • tablespace_name *是要在其中创建新表的表空间的名称。如果未指定,则查询default_tablespace,如果表是临时的,则查询temp_tablespaces
  • USING INDEX TABLESPACE tablespace_name

    • 此子句允许选择将在其中创建与UNIQUEPRIMARY KEYEXCLUDE约束相关联的索引的表空间。如果未指定,则查询default_tablespace,如果表是临时的,则查询temp_tablespaces

Storage Parameters

WITH子句可以为表以及与UNIQUEPRIMARY KEYEXCLUDE约束相关联的索引指定存储参数。索引的存储参数记录在CREATE INDEX中。下面列出了当前可用于表的存储参数。如图所示,对于其中的许多参数,还有一个附加名称,其名称以toast.为前缀,该参数控制表的辅助 TOAST 表的行为(如果有的话)(有关 TOAST 的更多信息,请参见Section 68.2)。如果设置了表参数值,但未设置等效的toast.参数,则 TOAST 表将使用表的参数值。不支持为分区表指定这些参数,但是您可以为单个叶分区指定它们。

  • fillfactor ( integer )

    • 表格的填充因子是 10 到 100 之间的百分比。默认值为 100(完全打包)。如果指定较小的填充因子,则INSERT个操作仅将表页面打包到指定的百分比;每个页面上的剩余空间都保留用于更新该页面上的行。这使UPDATE有机会将行的更新副本与原始副本放置在同一页面上,这比将其放置在另一页面上更为有效。对于永远不会更新其条目的表,最好进行完全打包,但在更新频繁的表中,较小的填充因子是合适的。不能为 TOAST 表设置此参数。
  • toast_tuple_target ( integer )

    • toast_tuple_target 指定在尝试将长列值移入 TOAST 表之前所需的最小 Tuples 长度,也是目标长度,一旦尝试开始烘烤,我们就尝试将长度减小到以下长度。这只会影响标记为“外部”或“扩展”的列,并且仅适用于新的 Tuples-对现有行没有影响。默认情况下,此参数设置为每个块至少允许 4 个 Tuples,默认情况下,块大小为 2040 字节。有效值介于 128 字节和(块大小-Headers)之间,默认为 8160 字节。更改此值对于非常短或非常长的行可能没有用。请注意,默认设置通常接近最佳值,并且在某些情况下设置此参数可能会产生负面影响。不能为 TOAST 表设置此参数。
  • parallel_workers ( integer )

    • 这设置了应用于辅助对该表进行并行扫描的工作程序数。如果未设置,则系统将根据关系大小确定一个值。计划者或使用并行扫描的 Util 语句选择的实际 Worker 数量可能会更少,例如由于设置了max_worker_processes
  • autovacuum_enabled , toast.autovacuum_enabled ( boolean )

    • 启用或禁用特定表的 autovacuum 守护程序。如果为 true,则 autovacuum 守护程序将按照Section 24.1.6中讨论的规则在此表上执行VACUUM和/或ANALYZE自动操作。如果为 false,则此表将不会自动清空,除非要防止事务 ID 绕回。有关防止回绕的更多信息,请参见Section 24.1.5。请注意,如果autovacuum参数为 false,则 autovacuum 守护程序将根本不运行(为了防止事务 ID 绕回)。设置单个表的存储参数不会覆盖该参数。因此,将此存储参数显式设置为true,仅将其设置为false几乎没有意义。
  • autovacuum_vacuum_threshold , toast.autovacuum_vacuum_threshold ( integer )

  • autovacuum_vacuum_scale_factor , toast.autovacuum_vacuum_scale_factor ( floating point )

  • autovacuum_analyze_threshold ( integer )

  • autovacuum_analyze_scale_factor ( floating point )

  • autovacuum_vacuum_cost_delay , toast.autovacuum_vacuum_cost_delay ( integer )

  • autovacuum_vacuum_cost_limit , toast.autovacuum_vacuum_cost_limit ( integer )

  • autovacuum_freeze_min_age , toast.autovacuum_freeze_min_age ( integer )

  • 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 )

  • autovacuum_multixact_freeze_min_age , toast.autovacuum_multixact_freeze_min_age ( integer )

  • 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 )

  • log_autovacuum_min_duration , toast.log_autovacuum_min_duration ( integer )

  • user_catalog_table ( boolean )

    • 将该表声明为附加目录表,以进行逻辑复制。有关详情,请参见Section 49.6.2。不能为 TOAST 表设置此参数。

Notes

不建议在新应用程序中使用 OID:在可能的情况下,最好使用 Identity 列或其他序列生成器作为表的主键。但是,如果您的应用程序确实使用 OID 来标识表的特定行,则建议在该表的oid列上创建唯一约束,以确保即使在计数器换行后,表中的 OID 的确也可以唯一地标识行。 。避免假设 OID 在表之间是唯一的;如果您需要整个数据库范围内的唯一标识符,请结合使用tableoid和行 OID。

Tip

对于没有主键的表,不建议使用OIDS=FALSE,因为既没有 OID 也没有唯一的数据键,则很难识别特定的行。

PostgreSQL 自动为每个唯一性约束和主键约束创建索引以强制唯一性。因此,没有必要为主键列显式创建索引。 (有关更多信息,请参见CREATE INDEX。)

唯一约束和主键在当前实现中不继承。这使得继承和唯一约束的组合相当不起作用。

一个表不能超过 1600 列。 (实际上,由于 Tuples 长度限制,有效限制通常较低.)

Examples

创建表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列分配 Literals 常量默认值,通过选择序列对象的下一个值来安排要生成的第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 标准,但以下列出了 exception。

Temporary Tables

尽管CREATE TEMPORARY TABLE的语法与 SQL 标准的语法相似,但效果并不相同。在标准中,临时表仅定义一次,并在每个需要它们的会话中自动存在(从空内容开始)。 PostgreSQL 而是要求每个会话为要使用的每个临时表发出自己的CREATE TEMPORARY TABLE命令。这允许不同的会话出于不同的目的而使用相同的临时表名称,而标准的方法将给定临时表名称的所有实例约束为具有相同的表结构。

该标准对临时表的行为的定义被广泛忽略。 PostgreSQL 在这一点上的行为类似于其他几个 SQL 数据库的行为。

SQL 标准还区分了全局临时表和本地临时表,尽管每个会话中每个 SQL 模块的定义仍然在各个会话之间共享,但本地临时表具有一组单独的内容。由于 PostgreSQL 不支持 SQL 模块,因此该区别在 PostgreSQL 中不相关。

出于兼容性考虑,PostgreSQL 将在临时表声明中接受GLOBALLOCAL关键字,但它们目前无效。不鼓励使用这些关键字,因为 PostgreSQL 的 Future 版本可能会对其含义进行更符合标准的解释。

临时表的ON COMMIT子句也类似于 SQL 标准,但有一些区别。如果省略ON COMMIT子句,则 SQL 指定默认行为为ON COMMIT DELETE ROWS。但是,PostgreSQL 中的默认行为是ON COMMIT PRESERVE ROWSON COMMIT DROP选项在 SQL 中不存在。

非递延唯一性约束

UNIQUEPRIMARY KEY约束不可延迟时,无论何时插入或修改行,PostgreSQL 都会立即检查其唯一性。 SQL 标准指出,唯一性应仅在语句末尾执行;例如,当一个命令更新多个键值时,这会有所不同。要获得符合标准的行为,请将约束声明为DEFERRABLE,但不要将其延迟(即INITIALLY IMMEDIATE)。请注意,这比立即唯一性检查要慢得多。

列检查约束

SQL 标准说CHECK列约束只能引用它们应用于的列;只有CHECK表约束可以引用多个列。 PostgreSQL 不强制执行此限制。它对待列和表检查约束都一样。

EXCLUDE Constraint

EXCLUDE约束类型是 PostgreSQL 扩展。

NULL "Constraint"

NULL“约束”(实际上是一个非约束)是对 SQL 标准的 PostgreSQL 扩展,为了与某些其他数据库系统兼容(并与NOT NULL约束对称)而包括了该扩展。由于它是任何列的默认值,因此它的存在仅仅是噪声。

Constraint Naming

SQL 标准说,表和域约束必须具有在包含表或域的架构上唯一的名称。 PostgreSQL 比较宽松:它只要求约束名称在附加到特定表或域的约束上是唯一的。但是,由于基于索引的约束(UNIQUEPRIMARY KEYEXCLUDE约束)不存在这种额外的自由,因为关联的索引的命名与约束相同,并且索引名称在同一架构内的所有关系中必须唯一。

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

Inheritance

通过INHERITS子句的多重继承是 PostgreSQL 语言的扩展。 SQL:1999 及更高版本使用不同的语法和语义定义了单个继承。 PostgreSQL 尚不支持 SQL:1999 样式的继承。

Zero-column Tables

PostgreSQL 允许创建没有列的表(例如CREATE TABLE foo();)。这是 SQL 标准的扩展,不允许使用零列表。零列表本身并不是很有用,但是不允许使用零列表会产生ALTER TABLE DROP COLUMN的特殊情况,因此忽略此规范限制似乎更为干净。

多个身份列

PostgreSQL 允许一个表具有多个标识列。该标准指定一个表最多可以包含一个标识列。放宽这主要是为了给模式更改或迁移提供更大的灵 Active。请注意,INSERT命令仅支持一个应用于整个语句的重写子句,因此,不能很好地支持具有不同行为的多个标识列。

LIKE Clause

尽管 SQL 标准中存在LIKE子句,但 PostgreSQL 接受的许多选项都不在标准中,并且 PostgreSQL 并未实现某些标准的选项。

WITH Clause

WITH子句是 PostgreSQL 扩展;存储参数和 OID 都不在标准中。

Tablespaces

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

Typed Tables

类型化表实现 SQL 标准的子集。根据该标准,类型化表具有与基础复合类型相对应的列以及另一列,即“自引用列”。 PostgreSQL 不明确支持这些自引用列,但是使用 OID 功能可以达到相同的效果。

PARTITION BY 条款

PARTITION BY子句是 PostgreSQL 扩展。

PARTITION OF 子句

PARTITION OF子句是 PostgreSQL 扩展。

See Also

ALTER TABLE, DROP TABLE, 创建表为, CREATE TABLESPACE, CREATE TYPE