PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

CREATE TABLE

CREATE TABLE — 定义一个新表

Synopsis

CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] table_name ( [
  { column_name data_type [ STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN | DEFAULT } ] [ COMPRESSION compression_method ] [ 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 ]

where column_constraint is:

[ CONSTRAINT constraint_name ]
{ NOT NULL [ NO INHERIT ]  |
  NULL |
  CHECK ( expression ) [ NO INHERIT ] |
  DEFAULT default_expr |
  GENERATED ALWAYS AS ( generation_expr ) [ STORED | VIRTUAL ] |
  GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ] |
  UNIQUE [ NULLS [ NOT ] DISTINCT ] 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 ] [ ENFORCED | NOT ENFORCED ]

and table_constraint is:

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

and like_option is:

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

and partition_bound_spec is:

IN ( partition_bound_expr [, ...] ) |
FROM ( { partition_bound_expr | MINVALUE | MAXVALUE } [, ...] )
  TO ( { partition_bound_expr | 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 ) } [ COLLATE collation ] [ opclass [ ( opclass_parameter = value [, ... ] ) ] ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]

referential_action in a FOREIGN KEY/REFERENCES constraint is:

{ NO ACTION | RESTRICT | CASCADE | SET NULL [ ( column_name [, ... ] ) ] | SET DEFAULT [ ( column_name [, ... ] ) ] }

描述

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

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

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

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

定义约束有两种方式:表约束和列约束。列约束被定义为列定义的一部分。表约束的定义不与特定的列绑定,它可以涵盖多列。每一个列约束也都可以写成表约束;当约束仅影响一列时,列约束只是一种记号上的便利写法。

要能够创建表,你必须拥有 USAGE 特权,分别对应于所有列类型或者 OF 子句中的类型。

参数

TEMPORARY or TEMP #

如果指定了该选项,表将被创建为临时表。临时表会在会话结束时被自动删除,或者也可以选择在当前事务结束时被删除(参见下文的 ON COMMIT)。默认的 search_path 首先包含临时模式,因此在临时表存在期间,新计划不会选择同名的已有永久表,除非这些表以模式限定的名称被引用。在临时表上创建的任何索引也会自动成为临时索引。

自动清理守护进程无法访问临时表,因此也无法对临时表进行清理或分析。出于这个原因,应当通过会话中的 SQL 命令来执行相应的清理和分析操作。例如,如果某个临时表将被用于复杂查询,那么在该表填充数据之后对其运行 ANALYZE 是明智的做法。

可以选择把 GLOBAL 或 LOCAL 写在 TEMPORARY 或 TEMP 之前。目前这在 PostgreSQL 中没有任何区别,并且已被弃用;参见下文的 Compatibility。

UNLOGGED #

如果指定了该选项,表将被创建为非日志表。写入非日志表的数据不会写入预写式日志(见 Chapter 28),这使得它们比普通表快得多。但是,它们并不具备崩溃安全性:在崩溃或非正常关机之后,非日志表会被自动截断。非日志表的内容也不会被复制到后备服务器。在非日志表上创建的任何索引也会自动成为非日志索引。

如果指定了该选项,与该非日志表一起创建的所有序列(用于标识列或 serial 列)也将被创建为非日志的。

分区表不支持这种形式。

IF NOT EXISTS #

如果同名关系已经存在,则不抛出错误。在这种情况下会发出一个通知。请注意,这并不能保证已有的关系与原本要创建的关系有任何相似之处。

table_name #

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

OF type_name #

创建一个类型化表,它的结构取自指定的独立复合类型(即使用 CREATE TYPE 创建的类型),不过它同样会生成一个新的复合类型。该表将依赖于被引用的类型,这意味着对该类型的级联修改和删除操作将会传播到该表。

类型化表的列名和数据类型总是与它所派生自的类型相同,因此你不能指定额外的列。但是 CREATE TABLE 命令可以为该表添加默认值和约束,也可以指定存储参数。

column_name #

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

data_type #

该列的数据类型。其中可以包含数组说明符。有关 PostgreSQL 所支持数据类型的更多信息,请参阅 Chapter 8。

COLLATE collation #

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

STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN | DEFAULT } #

这种形式设置该列的存储模式。它控制该列是内联保存还是保存在辅助的 TOAST 表中,以及数据是否应当被压缩。PLAIN 必须用于像 integer 这样的定长值,它是内联的、不压缩的。MAIN 用于内联的、可压缩的数据。EXTERNAL 用于外部的、不压缩的数据,而 EXTENDED 用于外部的、可压缩的数据。写 DEFAULT 会将该列的存储模式设置为其数据类型的默认模式。EXTENDED 是大多数支持非 PLAIN 存储的数据类型的默认值。使用 EXTERNAL 会让对超大 text 和 bytea 值的子串操作运行得更快,代价是增加存储空间。更多信息请参见 Section 66.2。

COMPRESSION compression_method #

COMPRESSION 子句设置该列的压缩方法。只有变宽数据类型才支持压缩,并且仅当该列的存储模式为 main 或 extended 时才会使用压缩。(有关列存储模式的信息,请参见 ALTER TABLE。)为分区表设置此属性没有直接效果,因为这类表自身没有存储,但所配置的值会被新建的分区继承。支持的压缩方法有 pglz 和 lz4。(lz4 仅当使用 --with-lz4 构建 PostgreSQL 时才可用。)此外,compression_method 可以为 default,用于显式指定默认行为,即在插入数据时查询 default_toast_compression 设置来确定要使用的方法。

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(详见 Section 36.16.3)。

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

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

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 列表中指定的值则不是。请注意,这一陈述必须按照逐行比较的规则(Section 9.25.5)来理解。例如,给定 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) 并不是空范围;它恰好只允许存储一个值 — “无穷大”。

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

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

创建哈希分区时,必须指定模数和余数。模数必须是正整数,余数必须是小于模数的非负整数。通常,在最初设置哈希分区表时,你应当选择等于分区数的模数,并为每个表指定相同的模数和不同的余数(参见下文的示例)。但是,并不要求每个分区都具有相同的模数,只要求哈希分区表的各分区中出现的每一个模数都是下一个更大模数的因子。这样就可以逐步增加分区的数量,而不需要一次性移动所有数据。例如,假设你有一个包含 8 个分区的哈希分区表,每个分区的模数都是 8,但你觉得有必要把分区数增加到 16。你可以分离其中一个模数为 8 的分区,创建两个新的模数为 16 的分区来覆盖键空间中相同的部分(其中一个的余数等于被分离分区的余数,另一个的余数等于该值加 8),并用数据重新填充它们。然后,你可以对每个模数为 8 的分区重复此操作 -- 也许是在之后的某个时间 -- 直到不再剩下这样的分区为止。虽然这样做在每一步中可能仍然涉及大量的数据移动,但它仍然比必须创建一个全新的表并一次性移动所有数据要好。

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

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

像 TRUNCATE 这样通常会影响表及其所有继承子表的操作,会级联到所有分区,但也可以在单个分区上执行。

请注意,使用 PARTITION OF 创建分区需要在父分区表上获取 ACCESS EXCLUSIVE 锁。同样,用 DROP TABLE 删除分区也需要在父表上获取 ACCESS EXCLUSIVE 锁。可以使用 ALTER TABLE ATTACH/DETACH PARTITION 以较弱的锁来执行这些操作,从而减少对分区表上并发操作的干扰。

LIKE source_table [ like_option ... ] #

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

与 INHERITS 不同,创建完成后,新表与原表是完全解耦的。对原表的更改不会被应用到新表,也无法在扫描原表时包含新表的数据。

同样与 INHERITS 不同的是,由 LIKE 复制的列和约束不会与名称相似的列和约束合并。如果显式地或者在另一个 LIKE 子句中指定了相同的名称,则会发出错误。

可选的 like_option 子句指定要复制原表的哪些额外属性。指定 INCLUDING 表示复制该属性,指定 EXCLUDING 表示省略该属性。默认为 EXCLUDING。如果对同一类对象做了多次指定,将使用最后一次的指定。可用的选项有:

INCLUDING COMMENTS #

被复制的列、检查约束、非空约束、索引以及扩展统计信息上的注释将会被复制。默认行为是排除注释,因此新表中对应的对象将没有任何注释。

INCLUDING COMPRESSION #

列的压缩方法将被复制。默认行为是排除压缩方法,这会使列使用默认的压缩方法。

INCLUDING CONSTRAINTS #

CHECK 约束将被复制。列约束和表约束之间不作区分。非空约束总是会被复制到新表。

INCLUDING DEFAULTS #

被复制的列定义的默认表达式将被复制。否则,默认表达式不会被复制,这会导致新表中被复制的列使用空默认值。请注意,复制那些调用数据库修改函数(如 nextval)的默认值,可能会在原表和新表之间建立功能上的关联。

INCLUDING GENERATED #

被复制的列定义的生成表达式以及存储/虚拟的选择都将被复制。默认情况下,新列将是普通的基础列。

INCLUDING IDENTITY #

被复制的列定义的标识属性也将被复制。会为新表的每一个标识列创建一个新序列,它与旧表关联的序列是相互独立的。

INCLUDING INDEXES #

原表上的索引以及 PRIMARY KEY、UNIQUE 和 EXCLUDE 约束将在新表上创建。新索引和约束的名称将按照默认规则选取,而不管原对象是如何命名的。(这种行为避免了新索引可能出现的重名失败。)

INCLUDING STATISTICS #

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

INCLUDING STORAGE #

被复制的列定义的 STORAGE 设置将被复制。默认行为是排除 STORAGE 设置,这会使新表中被复制的列使用其类型特定的默认设置。有关 STORAGE 设置的更多信息,请参见 Section 66.2。

INCLUDING ALL #

INCLUDING ALL 是一种选择所有可用单独选项的简写形式。(单独写出 EXCLUDING 子句、放在 INCLUDING ALL 之后,以选择除某些特定选项之外的全部选项,可能会很有用。)

LIKE 子句也可以用于从视图、外部表或复合类型复制列定义。不适用的选项(例如,对视图使用 INCLUDING INDEXES)会被忽略。

CONSTRAINT constraint_name #

列约束或表约束的可选名称。如果违反了约束,错误消息中会包含约束名,因此像 col must be positive 这样的约束名可以用来向客户端应用程序传达有用的约束信息。(指定包含空格的约束名时需要使用双引号。)如果没有指定约束名,系统会生成一个名称。

NOT NULL [ NO INHERIT ] #

该列不允许包含空值。

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

NULL #

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

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

CHECK ( expression ) [ NO INHERIT ] #

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

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

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

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

DEFAULT default_expr #

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

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

GENERATED ALWAYS AS ( generation_expr ) [ STORED | VIRTUAL ] #

此子句将该列创建为生成列。该列不能被写入,读取时将返回指定表达式的结果。

指定 VIRTUAL 时,该列将在读取时被计算,并且不占用任何存储。指定 STORED 时,该列将在写入时被计算并存储到磁盘上。默认值是 VIRTUAL。

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

虚拟生成列不能使用用户定义的类型,并且虚拟生成列的生成表达式不得引用用户定义的函数或类型,也就是说,它只能使用内建的函数或类型。这条限制也间接适用,例如适用于作为操作符或类型转换基础的函数或类型。(存储生成列不存在此限制。)

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

此子句将该列创建为标识列。它将附带一个隐式序列,并且在插入的新行中,该列将自动被赋予来自该序列的值。这样的列隐含 NOT NULL。

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

在 INSERT 命令中,如果选择了 ALWAYS,只有当 INSERT 语句指定了 OVERRIDING SYSTEM VALUE 时才会接受用户指定的值。如果选择了 BY DEFAULT,则用户指定的值优先。详见 INSERT。(在 COPY 命令中,无论此设置如何,总是使用用户指定的值。)

在 UPDATE 命令中,如果选择了 ALWAYS,将该列更新为 DEFAULT 以外任何值的操作都会被拒绝。如果选择了 BY DEFAULT,该列可以正常更新。(OVERRIDING 子句在 UPDATE 命令中并不存在。)

可选的 sequence_options 子句可用于覆盖序列的参数。可用选项包括 CREATE SEQUENCE 中所示的那些,另外还有 SEQUENCE NAME name、LOGGED 和 UNLOGGED,它们允许选择序列的名称和持久性级别。如果没有 SEQUENCE NAME,系统会为该序列选择一个未使用的名称。如果没有 LOGGED 或 UNLOGGED,该序列将具有与表相同的持久性级别。

UNIQUE [ NULLS [ NOT ] DISTINCT ] (column constraint)
UNIQUE [ NULLS [ NOT ] DISTINCT ] ( column_name [, ... ] [, column_name WITHOUT OVERLAPS ] ) [ INCLUDE ( column_name [, ...]) ] (table constraint) #

UNIQUE 约束规定表中的一组(一个或多个)列只能包含唯一的值。唯一表约束的行为与唯一列约束相同,但额外具有跨越多列的能力。因此,该约束强制要求任意两行在这些列中至少有一列上必须不同。

如果为最后一列指定了 WITHOUT OVERLAPS 选项,则对该列检查的是重叠而不是相等。在这种情况下,只要重复值在 WITHOUT OVERLAPS 列上不重叠,约束的其他列就允许出现重复。(如果该列是日期或时间戳的范围,这有时被称为时态键,但 PostgreSQL 允许对任何基础类型使用范围。)实际上,这样的约束是通过 EXCLUDE 约束而不是 UNIQUE 约束来实施的。例如,UNIQUE (id, valid_at WITHOUT OVERLAPS) 的行为就像 EXCLUDE USING GIST (id WITH =, valid_at WITH &&) 一样。WITHOUT OVERLAPS 列必须具有范围或多范围类型。不允许使用空范围/多范围。约束中非 WITHOUT OVERLAPS 的列可以是任何能在 GiST 索引中进行相等比较的类型。默认情况下只支持范围类型,但你可以通过添加 btree_gist 扩展来使用其他类型(这是使用此特性的预期方式)。

就唯一约束而言,空值不被视为相等,除非指定了 NULLS NOT DISTINCT。

每个唯一约束所指定的列集合应当不同于为该表定义的任何其他唯一约束或主键约束所指定的列集合。(否则,冗余的唯一约束将被丢弃。)

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

添加唯一约束会自动在约束所用的列或列组上创建一个唯一的 btree 索引。但如果约束包含 WITHOUT OVERLAPS 子句,则会使用 GiST 索引。创建的索引与唯一约束同名。

可选的 INCLUDE 子句会向该索引添加一个或多个仅作为“载荷”的列:不对它们强制唯一性,并且不能基于这些列来搜索索引。但是,可以通过仅索引扫描来检索它们。请注意,尽管约束不在被包含的列上实施,但它仍然依赖于这些列。因此,对这些列的某些操作(例如 DROP COLUMN)可能会导致约束和索引被级联删除。

PRIMARY KEY (column constraint)
PRIMARY KEY ( column_name [, ... ] [, column_name WITHOUT OVERLAPS ] ) [ INCLUDE ( column_name [, ...]) ] (table constraint) #

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

主键约束所指定的列集合应当不同于为同一个表定义的任何唯一约束所指定的列集合。(否则,该唯一约束是冗余的,将被丢弃。)

PRIMARY KEY 强制实施的数据约束与 UNIQUE 和 NOT NULL 的组合相同。但是,将一组列标识为主键还提供了关于模式设计的元数据,因为主键意味着其他表可以依赖这组列作为行的唯一标识符。

放在分区表上时,PRIMARY KEY 约束具有前文针对 UNIQUE 约束所述的相同限制。

添加 PRIMARY KEY 约束会自动在约束所用的列或列组上创建一个唯一的 btree 索引,如果指定了 WITHOUT OVERLAPS,则创建 GiST 索引。

可选的 INCLUDE 子句会向该索引添加一个或多个仅作为“载荷”的列:不对它们强制唯一性,并且不能基于这些列来搜索索引。但是,可以通过仅索引扫描来检索它们。请注意,尽管约束不在被包含的列上实施,但它仍然依赖于这些列。因此,对这些列的某些操作(例如 DROP COLUMN)可能会导致约束和索引被级联删除。

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

EXCLUDE 子句定义一个排除约束,它保证如果使用指定的操作符对任意两行在指定的列或表达式上进行比较,这些比较不会全部返回 TRUE。如果所有指定的操作符都是测试相等性,这就相当于一个 UNIQUE 约束,不过普通的唯一约束会更快。但是,排除约束可以指定比简单相等更一般的约束。例如,你可以指定一个约束,规定表中任何两行都不能包含重叠的圆(参见 Section 8.8),方法是使用 && 操作符。这些操作符必须是可交换的。

排除约束是通过一个与约束同名的索引来实现的,因此每个指定的操作符都必须与一个适当的操作符类(参见 Section 11.10)相关联,该操作符类对应于索引访问方法 index_method。每个 exclude_element 定义索引的一个列,因此它可以选择性地指定排序规则、操作符类、操作符类参数和/或排序选项;这些内容在 CREATE INDEX 中有完整的描述。

访问方法必须支持 amgettuple(参见 Chapter 63);目前这意味着不能使用 GIN。虽然允许,但在排除约束中使用 B-tree 或哈希索引没有什么意义,因为它能做的事情,普通唯一约束都能做得更好。所以在实践中,访问方法总是 GiST 或 SP-GiST。

predicate 允许你在表的一个子集上指定排除约束;在内部这会创建一个部分索引。请注意,谓词两边必须加上圆括号。

为多级分区层次结构建立排除约束时,目标分区表的分区键中的所有列,以及其所有后代分区表的分区键中的所有列,都必须包含在约束定义中。此外,这些列必须使用相等操作符进行比较。这些限制确保可能发生冲突的行会位于同一个分区中。该约束还可以引用不属于任何分区键的其他列,这些列可以使用任何适当的操作符进行比较。

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

这些子句指定一个外键约束,它要求新表中的一组(一个或多个)列只能包含与被引用表的某一行中被引用列的值相匹配的值。如果省略了 refcolumn 列表,则使用 reftable 的主键。否则,refcolumn 列表必须引用非可延迟的唯一约束或主键约束的列,或者是非部分唯一索引的列。

如果最后一列被标记为 PERIOD,它将以特殊的方式处理。非 PERIOD 列会进行相等比较(并且其中至少必须有一列),而 PERIOD 列则不会。相反,如果被引用表具有匹配的记录(基于键中非 PERIOD 的部分),且其组合的 PERIOD 值完全覆盖了引用记录的值,则认为该约束得到满足。换言之,引用在其整个存续期间都必须有一个被引用对象。该列必须是范围或多范围类型。此外,被引用表必须具有一个用 WITHOUT OVERLAPS 声明的主键或唯一约束。最后,如果外键带有 PERIOD column_name 规定,那么相应的 refcolumn(如果存在)也必须被标记为 PERIOD。如果省略了 refcolumn 子句,从而选择了 reftable 的主键约束,那么该主键的最后一列必须被标记为 WITHOUT OVERLAPS。

对于每一对引用列和被引用列,如果它们是可排序的数据类型,那么它们的排序规则必须都是确定性的,或者两者完全相同。这确保了两个列具有一致的相等概念。

用户必须对被引用表拥有 REFERENCES 权限(可以是整个表,也可以是特定的被引用列)。添加外键约束需要在被引用表上获取 SHARE ROW EXCLUSIVE 锁。请注意,不能在临时表和永久表之间定义外键约束。

插入到引用列中的值会使用给定的匹配类型与被引用表和被引用列的值进行匹配。有三种匹配类型:MATCH FULL、MATCH PARTIAL 和 MATCH SIMPLE(默认值)。MATCH FULL 不允许多列外键中的某一列为空,除非所有外键列都为空;如果它们全为空,则不要求该行在被引用表中具有匹配行。MATCH SIMPLE 允许外键的任何一列为空;如果其中有任何一列为空,则不要求该行在被引用表中具有匹配行。MATCH PARTIAL 尚未实现。(当然,可以对引用列应用 NOT NULL 约束来防止出现这些情况。)

此外,当被引用列中的数据发生变化时,会对本表列中的数据执行某些动作。ON DELETE 子句指定当被引用表中的被引用行被删除时要执行的动作。同样,ON UPDATE 子句指定当被引用表中的被引用列被更新为新值时要执行的动作。如果行被更新,但被引用列实际上没有变化,则不执行任何动作。即使约束是可延迟的,引用动作也会作为数据修改命令的一部分被执行。每个子句可以指定以下动作:

NO ACTION #

如果删除或更新会造成外键约束违反,则产生一个错误。如果约束是可延迟的,那么在约束检查时若仍存在引用行,则会产生该错误。这是默认动作。

RESTRICT #

如果要删除或更新的行与引用表中的某一行匹配,则产生错误。即使操作之后的状态不会违反外键约束,这也会阻止该操作。特别是,它会阻止将被引用行更新为不同但比较结果相等的值。(但它不会阻止将列更新为相同值的“无操作”更新。)

对于时态外键,不支持此选项。

CASCADE #

删除引用了被删除行的所有行,或者分别将引用列的值更新为被引用列的新值。

对于时态外键,不支持此选项。

SET NULL [ ( column_name [, ... ] ) ] #

将所有引用列或引用列的指定子集设置为空。只能为 ON DELETE 操作指定列的子集。

对于时态外键,不支持此选项。

SET DEFAULT [ ( column_name [, ... ] ) ] #

将所有引用列或引用列的指定子集设置为它们的默认值。只能为 ON DELETE 操作指定列的子集。(如果默认值不是空,则被引用表中必须存在与这些默认值匹配的行,否则操作将失败。)

对于时态外键,不支持此选项。

如果被引用列被频繁修改,最好为引用列添加一个索引,以便能更高效地执行与外键约束相关联的引用操作。

DEFERRABLE
NOT DEFERRABLE #

这控制约束是否可以延迟。不可延迟的约束会在每条命令之后立即被检查。可延迟约束的检查可以推迟到事务结束时进行(使用 SET CONSTRAINTS 命令)。默认值是 NOT DEFERRABLE。目前,只有 UNIQUE、PRIMARY KEY、EXCLUDE 和 REFERENCES(外键)约束接受此子句。NOT NULL 和 CHECK 约束是不可延迟的。请注意,可延迟约束不能在 INSERT 语句(包含 ON CONFLICT 子句)中用作冲突仲裁者。

INITIALLY IMMEDIATE
INITIALLY DEFERRED #

如果约束是可延迟的,此子句指定检查约束的默认时间。如果约束是 INITIALLY IMMEDIATE,它会在每条语句之后被检查。这是默认行为。如果约束是 INITIALLY DEFERRED,则只在事务结束时检查它。可以使用 SET CONSTRAINTS 命令来更改约束的检查时间。

ENFORCED
NOT ENFORCED #

当约束为 ENFORCED 时,数据库系统将通过在适当的时间(在每条语句之后或在事务结束时,视情况而定)检查约束,来确保约束得到满足。这是默认行为。如果约束为 NOT ENFORCED,数据库系统将不会检查约束。此时,确保约束得到满足就由应用程序代码负责。在不会影响结果正确性的优化决策中,数据库系统可能仍然会假定数据实际上满足该约束。

如果在运行时实际检查约束的代价太高,NOT ENFORCED 约束可以作为文档说明发挥作用。

目前只有外键约束和 CHECK 约束支持此选项。

USING method #

此可选子句指定用于存储新表内容的表访问方法;该方法必须是 TABLE 类型的访问方法。更多信息请参见 Chapter 62。如果未指定此选项,将为新表选择默认的表访问方法。更多信息请参见 default_table_access_method。

创建分区时,表访问方法是其分区表的访问方法(如果已设置)。

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

此子句为表或索引指定可选的存储参数;更多信息请参见下文的 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。对于分区表,由于表本身不需要存储,当没有显式指定其他表空间时,所指定的表空间将覆盖 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 的更多信息,请参见 Section 66.2)。如果设置了表参数值而等效的 toast. 参数未设置,则 TOAST 表将使用表的参数值。不支持为分区表指定这些参数,但可以为各个叶子分区指定它们。

fillfactor (integer) #

表的 fillfactor 是一个介于 10 到 100 之间的百分比。默认值是 100(完全填满)。当指定较小的 fillfactor 时,INSERT 操作只会将表页面填充到指定的百分比;每一页上的剩余空间会保留给该页上行的更新。这使得 UPDATE 有机会将行的更新副本放在与原始行相同的页面上,这比放在不同的页面上更高效,并且使堆内元组更新更有可能发生。对于条目从不更新的表,完全填满是最佳选择,但对于更新频繁的表,较小的 fillfactor 更为合适。不能为 TOAST 表设置此参数。

toast_tuple_target (integer) #

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

parallel_workers (integer) #

此参数设置应用于协助对该表进行并行扫描的工作进程数量。如果未设置,系统将根据关系大小确定一个值。规划器或使用并行扫描的实用工具语句实际选择的工作进程数量可能会更少,例如由于 max_worker_processes 的设置。

autovacuum_enabled, toast.autovacuum_enabled (boolean) #

为特定的表启用或禁用自动清理守护进程。如果为真,自动清理守护进程将对该表执行自动 VACUUM 和/或 ANALYZE 操作,遵循 Section 24.1.6 中所讨论的规则。如果为假,该表将不会被自动清理,但防止事务 ID 回卷的情况除外。有关回卷预防的更多信息,请参见 Section 24.1.5。请注意,如果 autovacuum 参数为假,自动清理守护进程将完全不会运行(防止事务 ID 回卷的情况除外);设置单个表的存储参数不能覆盖这一点。因此,将此存储参数显式设置为 true 通常没有什么意义,只有设置为 false 才有意义。

vacuum_index_cleanup, toast.vacuum_index_cleanup (enum) #

在对该表运行 VACUUM 时强制执行或禁用索引清理。默认值为 AUTO。设为 OFF 时禁用索引清理,设为 ON 时启用索引清理,设为 AUTO 时则会在每次运行 VACUUM 时动态做出决定。这种动态行为使 VACUUM 可以避免为了清除极少量死元组而毫无必要地扫描索引。强制禁用所有索引清理可以显著加快 VACUUM 的速度,但如果表的修改很频繁,也可能导致索引严重膨胀。如果指定了 INDEX_CLEANUP 参数(VACUUM 命令的参数),它将覆盖此选项的值。

vacuum_truncate, toast.vacuum_truncate (boolean) #

vacuum_truncate 参数的每表取值。如果指定了 TRUNCATE 参数(VACUUM 命令的参数),它将覆盖此选项的值。

autovacuum_vacuum_threshold, toast.autovacuum_vacuum_threshold (integer) #

autovacuum_vacuum_threshold 参数的每表取值。

autovacuum_vacuum_max_threshold, toast.autovacuum_vacuum_max_threshold (integer) #

autovacuum_vacuum_max_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 (floating point) #

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_min_age 参数中大于系统级 autovacuum_freeze_max_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_min_age 参数中大于系统级 autovacuum_multixact_freeze_max_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 参数的每表取值。

vacuum_max_eager_freeze_failure_rate, toast.vacuum_max_eager_freeze_failure_rate (floating point) #

vacuum_max_eager_freeze_failure_rate 参数的每表取值。

user_catalog_table (boolean) #

将该表声明为用于逻辑复制的附加目录表。详见 Section 47.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
);

定义两个 NOT NULL 列约束,作用在表 distributors 上,其中一个被显式命名:

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 &&)
);

创建表 cinemas,位于表空间 diskvol1 中:

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;

兼容性

CREATE TABLE 命令符合 SQL 标准,但存在下面列出的例外。

临时表

虽然 CREATE TEMPORARY TABLE 的语法与 SQL 标准类似,但效果并不相同。在标准中,临时表只定义一次,并且自动存在于每一个需要它的会话中(初始内容为空)。而 PostgreSQL 则要求每个会话为要使用的每一个临时表各自发出自己的 CREATE TEMPORARY TABLE 命令。这允许不同的会话将同一个临时表名用于不同的目的,而标准的方法则强制给定临时表名的所有实例都具有相同的表结构。

标准中关于临时表行为的定义被广泛忽视。在这一点上,PostgreSQL 的行为与其他几种 SQL 数据库类似。

SQL 标准还区分全局临时表和本地临时表,本地临时表在每个会话中的每个 SQL 模块都有一组单独的内容,尽管其定义仍然跨会话共享。由于 PostgreSQL 不支持 SQL 模块,这种区分在 PostgreSQL 中没有意义。

为了兼容性起见,PostgreSQL 会接受在临时表声明中使用 GLOBAL 和 LOCAL 关键字,但它们目前没有任何效果。不建议使用这些关键字,因为 PostgreSQL 的未来版本可能会采用更符合标准的含义解释。

临时表的 ON COMMIT 子句也与 SQL 标准类似,但存在一些差异。如果省略了 ON COMMIT 子句,SQL 规定默认行为是 ON COMMIT DELETE ROWS。然而,PostgreSQL 中的默认行为是 ON COMMIT PRESERVE ROWS。ON COMMIT DROP 选项在 SQL 中不存在。

非延迟唯一性约束

当 UNIQUE 或 PRIMARY KEY 约束不可延迟时,PostgreSQL 会在每次插入或修改行时立即检查唯一性。SQL 标准规定唯一性应当只在语句结束时强制实施;当单个命令更新多个键值时,这会产生区别。为了获得符合标准的行为,请将约束声明为 DEFERRABLE 但不进行延迟(即 INITIALLY IMMEDIATE)。请注意,这可能会比立即唯一性检查慢得多。

列检查约束

SQL 标准规定 CHECK 列约束只能引用它所应用的列;只有 CHECK 表约束才能引用多列。PostgreSQL 不强制执行这一限制;它对列检查约束和表检查约束一视同仁。

EXCLUDE 约束

EXCLUDE 约束类型是 PostgreSQL 的扩展。

外键约束

在外键操作 SET DEFAULT 和 SET NULL 中指定列列表的能力是 PostgreSQL 的扩展。

外键约束可以引用唯一索引的列而不是主键约束或唯一约束的列,这是 PostgreSQL 的扩展。

NULL “约束”

NULL “约束”(实际上并不是约束)是 PostgreSQL 对 SQL 标准的一个扩展,它的加入是为了与其他一些数据库系统兼容(以及与 NOT NULL 约束保持对称)。由于它是任何列的默认行为,它的存在纯属多余。

约束命名

SQL 标准规定表约束和域约束的名称在包含该表或域的模式中必须唯一。PostgreSQL 更为宽松:它只要求约束名称在附加到特定表或域的约束中唯一。但是,对于基于索引的约束(UNIQUE、PRIMARY KEY 和 EXCLUDE 约束),这种额外的自由并不存在,因为相关联的索引与约束同名,而索引名称在同一模式中的所有关系中必须唯一。

继承

通过 INHERITS 子句实现的多重继承是 PostgreSQL 的语言扩展。SQL:1999 及后续标准使用不同的语法和不同的语义定义了单一继承。PostgreSQL 尚不支持 SQL:1999 风格的继承。

零列的表

PostgreSQL 允许创建没有任何列的表(例如,CREATE TABLE foo();)。这是对 SQL 标准的一个扩展,标准不允许零列的表。零列的表本身并没有太大的用处,但如果不允许它们,就会给 ALTER TABLE DROP COLUMN 带来奇怪的特殊情况,因此忽略规范中的这一限制似乎更为干净。

多个标识列

PostgreSQL 允许一个表拥有多个标识列。标准规定一个表最多只能有一个标识列。放宽这一限制主要是为了在进行模式更改或迁移时提供更大的灵活性。请注意,INSERT 命令只支持一个适用于整个语句的覆盖子句,因此对具有不同行为的多个标识列的支持并不完善。

生成列

选项 STORED 和 VIRTUAL 不是标准的,但也被其他 SQL 实现所使用。SQL 标准没有规定生成列的存储方式。

LIKE 子句

虽然 SQL 标准中存在 LIKE 子句,但 PostgreSQL 为它接受的许多选项并不在标准中,而标准的某些选项也未在 PostgreSQL 中实现。

WITH 子句

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

表空间

PostgreSQL 的表空间概念不是标准的一部分。因此,TABLESPACE 和 USING 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