CREATE TABLE — 定义一个新表
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ]table_name
( [ {column_name
data_type
[ COLLATEcollation
] [column_constraint
[ ... ] ] |table_constraint
| LIKEsource_table
[like_option
... ] } [, ... ] ] ) [ INHERITS (parent_table
[, ... ] ) ] [ PARTITION BY { RANGE | LIST | HASH } ( {column_name
| (expression
) } [ COLLATEcollation
] [opclass
] [, ... ] ) ] [ WITH (storage_parameter
[=value
] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACEtablespace_name
] CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ]table_name
OFtype_name
[ ( {column_name
[ WITH OPTIONS ] [column_constraint
[ ... ] ] |table_constraint
} [, ... ] ) ] [ PARTITION BY { RANGE | LIST | HASH } ( {column_name
| (expression
) } [ COLLATEcollation
] [opclass
] [, ... ] ) ] [ WITH (storage_parameter
[=value
] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACEtablespace_name
] CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ]table_name
PARTITION OFparent_table
[ ( {column_name
[ WITH OPTIONS ] [column_constraint
[ ... ] ] |table_constraint
} [, ... ] ) ] { FOR VALUESpartition_bound_spec
| DEFAULT } [ PARTITION BY { RANGE | LIST | HASH } ( {column_name
| (expression
) } [ COLLATEcollation
] [opclass
] [, ... ] ) ] [ WITH (storage_parameter
[=value
] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACEtablespace_name
] 其中column_constraint
是: [ CONSTRAINTconstraint_name
] { NOT NULL | NULL | CHECK (expression
) [ NO INHERIT ] | DEFAULTdefault_expr
| GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ (sequence_options
) ] | UNIQUEindex_parameters
| PRIMARY KEYindex_parameters
| REFERENCESreftable
[ (refcolumn
) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETEaction
] [ ON UPDATEaction
] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]table_constraint
是: [ CONSTRAINTconstraint_name
] { CHECK (expression
) [ NO INHERIT ] | UNIQUE (column_name
[, ... ] )index_parameters
| PRIMARY KEY (column_name
[, ... ] )index_parameters
| EXCLUDE [ USINGindex_method
] (exclude_element
WITHoperator
[, ... ] )index_parameters
[ WHERE (predicate
) ] | FOREIGN KEY (column_name
[, ... ] ) REFERENCESreftable
[ (refcolumn
[, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETEaction
] [ ON UPDATEaction
] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]like_option
是: { INCLUDING | EXCLUDING } { COMMENTS | CONSTRAINTS | DEFAULTS | IDENTITY | INDEXES | STATISTICS | STORAGE | ALL }partition_bound_spec
是: 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 ( MODULUSnumeric_literal
, REMAINDERnumeric_literal
)UNIQUE
、PRIMARY KEY
以及EXCLUDE
约束中的index_parameters
是: [ INCLUDE (column_name
[, ... ] ) ] [ WITH (storage_parameter
[=value
] [, ... ] ) ] [ USING INDEX TABLESPACEtablespace_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
或TEMP
如果指定,该表被创建为一个临时表。临时表会被在会话结束时自动被删除,或者也可以选择在当前事务结束时删除(见下文的ON COMMIT
)。当临时表存在时,已有的同名持久表将对于当前会话不可见,不过可以使用模式限定的名称进行引用。在一个临时表上创建的任何索引也自动地变为临时的。
自动清理守护进程不能访问并且因此也不能清理或分析临时表。由于这个原因,应该通过会话的 SQL 命令执行合适的清理和分析操作。例如,如果一个临时表将要被用于复杂的查询,最好在把它填充完毕后在其上运行ANALYZE
。
可以选择将GLOBAL
或LOCAL
写在TEMPORARY
或TEMP
的前面。这当前在PostgreSQL中没有区别并且已被废弃,见兼容性。
UNLOGGED
如果指定,该表被创建为一个不受日志记录的表。被写入到不做日志的表中的数据不会被写到预写式日志中(见Chapter 30),这让它们比普通表快非常多。不过,它们在崩溃时是不安全的:一个不做日志的表在一次崩溃或非干净关闭之后会被自动地截断。一个不做日志的表中的内容也不会被复制到后备服务器中。在一个不做日志的表上创建的任何索引也会自动地不被日志记录。
IF NOT EXISTS
如果一个同名关系已经存在,不要抛出一个错误。在这种情况下会发出一个提示。注意这不保证现有的关系是和将要被创建的表相似的东西。
table_name
要被创建的表名(可以选择用模式限定)。
OF type_name
创建一个类型化的表,它的结构取自于指定的组合类型(名字可以选择用模式限定)。一个类型化的表和它的类型绑定在一起,例如如果类型被删除,该表也将被删除(用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
子句指定对该表进行分区的策略。这样创建的表被称为一个分区表。放在圆括号内的列或表达式的列表构成了该表的分区键。在使用范围或哈希分区时,分区键可以包括多列或者值(最多是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
的形式被用于列表分区,使用FROM
和TO
的形式被用于范围分区,而使用WITH
的形式被用于哈希分区。
partition_bound_spec
中指定的每一个值是一个文本、NULL
、MINVALUE
或MAXVALUE
。每个文本值必须是一个可以被强制为对应分区键列数据类型的数字常量或者是该类型有效输入的字符串。
在创建一个列表分区时,可以指定NULL
表示该分区允许分区键列为空值。不过,对于一个给定的父表,不能有多于一个这样的列表分区。对于范围分区不能指定NULL
。
在创建一个范围分区时,用FROM
指定的下界是一个包含下界,而用TO
指定的上界是一个不包含上界。也就是说,FROM
列表中指定的值是这个分区的相应分区键列的有效值,而TO
列表中的值不是。注意,这种语句必须根据逐行比较(见Section 9.23.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的分区重复这种做法,直到没有模数为8的分区剩下。虽然这样做仍然会在每一步涉及到大量的数据移动,但是仍然比创建一个全新的表并且一次移动所有的数据更好。
分区必须和它所属的分区表具有相同的列名和类型。如果父表指定了WITH OIDS
,则所有的分区都必须有OID,父表的OID列将和其他任何列一样被所有的分区所继承。对分区表的列名或类型的修改、OID列的增加或者删除都将会自动传播到所有的分区。CHECK
约束将被每一个分区自动地继承,但是个别分区也可以指定额外的CHECK
约束,与父表中约束具有相同名称和条件的额外约束将被合并到父表约束中。可以为每个分区单独指定默认值。
被插入到分区表的行将被自动路由到正确的分区。如果不存在合适的分区,则会发生错误。
通常会影响一个表及其继承子表的操作(例如TRUNCATE)将级联到所有的分区上,但也可以在个别分区上执行。注意用DROP TABLE
删除一个分区要求在其父表上拿到一个ACCESS EXCLUSIVE
锁。
LIKE source_table
[ like_option
... ]
LIKE
指定新表将从哪一个表自动地复制所有的列名、数据类型以及它们的非空约束。
和INHERITS
不同,新表和原始表在创建完成之后是完全分离的。对原始表的更改将不会被应用到新表,并且不可能在原始表的扫描中包括新表的数据。
只有INCLUDING DEFAULTS
被指定时,被拷贝的列定义的默认表达式才会被拷贝。默认的行为是排除默认表达式,导致新表中被拷贝过来的列的默认值为空值。注意,如果拷贝的默认值调用了数据库修改函数(如nextval
),则可能在原始表和新表之间创建功能联系。
只有指定了INCLUDING IDENTITY
,被拷贝的列定义上的标识说明才会被拷贝。为新表的每一个标识列都会创建一个新的序列,它们与旧表上相关联的序列之间是独立的。
非空约束总是会被复制到新表。CHECK
约束只有在INCLUDING CONSTRAINTS
被指定时才会被复制。列约束和表约束之间没有区别对待。
只有INCLUDING INDEXES
被指定时,原始表上的索引、PRIMARY KEY
、UNIQUE
以及EXCLUDE
约束将被创建在新表上。新索引和约束的名称将根据默认规则选定,而不管原始的名称如何(这种行为可以避免新索引重名导致的失败)。
只有INCLUDING STORAGE
被指定时,复制而来的列定义的STORAGE
设置才会被复制。默认行为会排除STORAGE
设置,导致新表中复制而来的列具有与类型相关的默认设置。更多关于STORAGE
设置的信息,请见Section 68.2。
只有INCLUDING COMMENTS
被指定时,复制而来的列、约束和索引的注释才会被拷贝。默认行为是排除注释,这导致新表中复制而来的列和约束没有注释。
INCLUDING ALL
是
INCLUDING COMMENTS INCLUDING CONSTRAINTS INCLUDING DEFAULTS INCLUDING IDENTITY INCLUDING INDEXES INCLUDING STATISTICS INCLUDING STORAGE
的简写形式。
注意和INHERITS
不同,用LIKE
拷贝的列和约束不会和相似的命名列及约束融合。如果显式指定了相同的名称或者在另一个LIKE
子句中指定了相同的名称,将会发出一个错误。
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
约束后,对于每一行会以它们名称的字母表顺序来进行检查(版本 9.5 之前的PostgreSQL对于CHECK
约束不遵从任何特定的引发顺序)。
DEFAULT
default_expr
DEFAULT
子句为出现在其定义中的列赋予一个默认数据。该值是可以使用变量的表达式(不允许用子查询和对其他列的交叉引用)。默认值表达式的数据类型必须匹配列的数据类型。
默认值表达式将被用在任何没有为该列指定值的插入操作中。如果一列没有默认值,那么默认值为空值。
GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options
) ]
这个子句把该列创建为一个标识列。将会有一个隐式序列依附于它,并且新行中的这个列将自动从属于它的序列中得到值。
子句ALWAYS
和BY DEFAULT
决定序列值和INSERT
语句中用户指定的值之间的优先顺序。如果指定了ALWAYS
,则只有在INSERT
语句指定了OVERRIDING SYSTEM VALUE
的情况下才会接受用户指定的值。如果指定的是BY DEFAULT
,则用户指定的值优先。详情请见INSERT(在COPY
命令中,不管这个设置如何,将总是使用用户指定的值)。
可选的sequence_options
子句可以被用来覆盖该序列的选项。详情请见CREATE SEQUENCE。
UNIQUE
(列约束)UNIQUE ( column_name
[, ... ] )
(表约束)
[ INCLUDE ( column_name
[, ...]) ] (table constraint)
UNIQUE
约束指定一个表中的一列或多列组成的组包含唯一的值。唯一表约束的行为与列约束的行为相同,只是表约束能够跨越多列。
对于一个唯一约束的目的来说,空值不被认为是相等的。
每一个唯一表约束必须命名一个列的集合,并且它与该表上任何其他唯一或主键约束所命名的列集合都不相同(否则它将是一个被列举了两次的约束)。
在为一个多层分区层次建立一个唯一约束时,目标分区表的分区键中的所有列以及那些在其所有后代分区表中的列,都必须被包括在该约束定义中。
增加一个唯一约束将自动在约束中用到的列或者列组上创建一个唯一btree索引。可选的子句INCLUDE
会在该索引中增加一个或多个列,唯一性不会在这些列上实施。注意尽管不会在被包括的列上强制该约束,但该约束仍然依赖于它们。因此,这些列上的一些操作(例如DROP COLUMN
)可能导致级联的约束删除以及索引删除。
PRIMARY KEY
(列约束)PRIMARY KEY ( column_name
[, ... ] )
(表约束)
[ INCLUDE ( column_name
[, ...]) ] (table constraint)
PRIMARY KEY
约束指定表的一个或者多个列只能包含唯一(不重复)、非空的值。一个表上只能指定一个主键,可以作为列约束或表约束。
主键约束所涉及的列集合应该不同于同一个表上定义的任何唯一约束的列集合(否则,该唯一约束是多余的并且会被丢弃)。
PRIMARY KEY
强制的数据约束可以看成是UNIQUE
和NOT NULL
的组合,不过把一组列标识为主键也为模式设计提供了元数据,因为主键标识其他表可以依赖这一个列集合作为行的唯一标识符。
当在分区表上建立PRIMARY KEY
约束时,将会共享UNIQUE
约束所拥有的限制。
增加一个PRIMARY KEY
约束将自动在约束中用到的列或者列组上创建一个唯一btree索引。可选的子句INCLUDE
允许指定一个列的列表,它们将被包括在该索引的非键部分。
EXCLUDE [ USING index_method
] ( exclude_element
WITH operator
[, ... ] ) index_parameters
[ WHERE ( predicate
) ]
EXCLUDE
子句定一个排除约束,它保证如果任意两行在指定列或表达式上使用指定操作符进行比较,不是所有的比较都将会返回TRUE
。如果所有指定的操作符都测试相等,这就等价于一个UNIQUE
约束,尽管一个普通的唯一约束将更快。不过,排除约束能够指定比简单相等更通用的约束。例如,你可以使用&&
操作符指定一个约束,要求表中没有两行包含相互覆盖的圆(见 Section 8.8)。
排除约束使用一个索引实现,这样每一个指定的操作符必须与用于索引访问方法index_method
的一个适当的操作符类(见Section 11.9)相关联。操作符被要求是交换的。每一个exclude_element
可以选择性地指定一个操作符类或者顺序选项,这些在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 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命令修改。
WITH ( storage_parameter
[= value
] [, ... ] )
这个子句为一个表或索引指定可选的存储参数,详见存储参数。一个表的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 可以减少存储该表所需的磁盘空间,减少的量是每行减少 4 字节(在大部分机器上),这也略微提高了性能。
要在表被创建后从中移除 OID,使用ALTER TABLE.
WITH OIDS
WITHOUT OIDS
这些语法已被荒废,它们分别等效于WITH (OIDS)
和WITH (OIDS=FALSE)
。如果你希望同时给出一个OIDS
设置和存储参数,你必须使用WITH ( ... )
语法,见上文。
ON COMMIT
临时表在一个事务块结束时的行为由ON COMMIT
控制。三种选项是:
PRESERVE ROWS
在事务结束时不采取特殊的动作。这是默认行为。
DELETE ROWS
在每一个事务块结束时将删除临时表中的所有行。实质上,在每一次提交时会完成一次自动的TRUNCATE。
DROP
在当前事务块结束时将删除临时表。
TABLESPACE tablespace_name
tablespace_name
是新表要创建于其中的表空间名称。如果没有指定,将参考default_tablespace,或者如果表是临时的则参考temp_tablespaces。
USING INDEX TABLESPACE tablespace_name
这个子句允许选择与一个UNIQUE
、PRIMARY KEY
或者EXCLUDE
约束相关的索引将被创建在哪个表空间中。如果没有指定,将参考default_tablespace,或者如果表是临时的则参考temp_tablespaces。
WITH
子句能够为表或与一个UNIQUE
、PRIMARY KEY
或者EXCLUDE
约束相关的索引指定存储参数。用于索引的存储参数已经在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表中之前所要求的最小元组长度,它也是我们在TOAST操作开始后要把长度减少到的目标。这个参数仅影响被标记为External或Extended的列,并且只影响新元组 - 它对已有行无影响。默认情况下这个参数被设置为允许每个块装至少4个元组,在默认的blocksize下这个值将是2040字节。有效值在128字节和(blocksize - header)之间,默认是8160字节。对于非常短或非常长的行更改这个值可能没什么用处。注意默认设置通常是接近于最优的,在一些情况下设置这个参数可能会产生反效果。不能为TOAST表设置这个参数。
parallel_workers
(integer
)这个参数设置应该被用来辅助对这个表并行扫描的工作者数量。如果没有设置这个参数,系统将基于关系的尺寸来决定一个值。规划器或者使用并行扫描的utility语句实际选择的工作者数量可能会少于这个参数,例如max_worker_processes的设置较小就是一种可能的原因。
autovacuum_enabled
, toast.autovacuum_enabled
(boolean
)
为一个特定的表启用或者禁用自动清理守护进程。如果为真,自动清理守护进程将遵照Section 24.1.6中讨论的规则在这个表上执行自动的VACUUM
或者ANALYZE
操作。如果为假,这个表不会被自动清理,不过为了阻止事务 ID 回卷时还是会对它进行自动的清理。有关回卷阻止请见Section 24.1.5。如果autovacuum参数为假,自动清理守护进程根本就不会运行(除非为了阻止事务 ID 回卷),设置独立的表存储参数也不会覆盖这个设置。因此显式地将这个存储参数设置为true
很少有大的意义,只有设置为false
才更有用。
autovacuum_vacuum_threshold
, toast.autovacuum_vacuum_threshold
(integer
)autovacuum_vacuum_threshold参数对于每个表的值。
autovacuum_vacuum_scale_factor
, toast.autovacuum_vacuum_scale_factor
(float4
)autovacuum_vacuum_scale_factor参数对于每个表的值。
autovacuum_analyze_threshold
(integer
)autovacuum_analyze_threshold参数对于每个表的值。
autovacuum_analyze_scale_factor
(float4
)autovacuum_analyze_scale_factor参数对于每个表的值。
autovacuum_vacuum_cost_delay
, toast.autovacuum_vacuum_cost_delay
(integer
)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
)声明该表是一个用于逻辑复制目的的额外的目录表。详见Section 49.6.2。不能对 TOAST 表设置这个参数。
我们不推荐在新应用中使用 OID:在可能要用到的地方,使用一个标识列或者其他序列生成器作为表的主键会更好。不过,如果你的应用确实需要用到 OID 来标识一个表的特定行,我们推荐在表的oid
列上创建一个唯一约束,来确保表中的 OID 在计数器回卷后能唯一标识行。如果你需要一个数据库范围的唯一标识符,要避免假定 OID 在表之间也是唯一的,应该用tableoid
和行 OID 的组合来实现该目的。
我们不推荐对没有主键的表使用OIDS=FALSE
,因为没有 OID 或 唯一数据键,就很难标识特定的行。
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;
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
。SQL 中不存在ON COMMIT DROP
选项。
但一个UNIQUE
或PRIMARY KEY
约束是非可延迟的,只要一个行被插入或修改,PostgreSQL就会立即检查唯一性。SQL 标准指出只有在语句结束时才应该强制唯一性。当一个单一命令更新多个键值时,这两者是不同的。要得到兼容标准的行为,将该约束声明为DEFERRABLE
但是不延迟(即INITIALLY IMMEDIATE
)。注意这可能要显著地慢于立即唯一性检查。
SQL 标准指出CHECK
列约束只能引用它们应用到的列,只有CHECK
表约束能够引用多列。PostgreSQL并没有强制这个限制,它同样处理列检查约束和表检查约束。
EXCLUDE
约束
EXCLUDE
约束类型是一种PostgreSQL扩展。
NULL
“约束”
NULL
“约束”(实际上是一个非约束)是一个PostgreSQL对 SQL 标准的扩展,它也被包括(以及对称的NOT NULL
约束)在一些其他的数据库系统中以实现兼容性。因为它是任意列的默认值,它的存在就像噪声一样。
SQL标准要求表和域的约束必须在包含该表或域的方案中具有唯一的名称。PostgreSQL则要更宽松:它只要求约束名在其所附属的表或域上唯一。不过,对于基于索引的约束(UNIQUE
、PRIMARY KEY
以及EXCLUDE
约束)则不存在这种额外的自由,因为相关的索引会被命名成约束的名称并且索引名必须在同一个方案的所有关系之间唯一。
当前,PostgreSQL根本不为NOT NULL
约束记录名称,因此它们不服从唯一性限制。在未来的版本中可能会改变这一点。
通过INHERITS
子句的多继承是一种PostgreSQL的语言扩展。SQL:1999 以及之后的标准使用一种不同的语法和不同的语义定义了单继承。SQL:1999-风格的继承还没有被PostgreSQL。
PostgreSQL允许创建一个没有列的表(例如CREATE TABLE foo();
)。这是一个对于 SQL 标准的扩展,它不允许零列表。零列表本身并不是很有用,但是不允许它们会为ALTER TABLE DROP COLUMN
带来奇怪的特殊情况,因此忽略这种规则限制看起来更加整洁。
PostgreSQL允许一个表有多个标识列。标准指定一个表最多只能有一个标识列。为了让模式更改或者迁移更加灵活,所以才对这种要求进行了放松。注意INSERT
命令只支持一个应用于整个语句的重载子句,因此不能很好地支持多个标识列有不同行为的情况。
LIKE
子句
虽然 SQL 标准中有一个LIKE
子句,但是PostgreSQL接受的很多LIKE
子句选项却不在标准中,并且有些标准中的选项也没有被PostgreSQL实现。
WITH
子句
WITH
子句是一个PostgreSQL扩展,存储参数和 OID 都不在标准中。
PostgreSQL的表空间概念不是标准的一部分。因此,子句TABLESPACE
和USING INDEX TABLESPACE
是扩展。
类型化的表实现了 SQL 标准的一个子集。根据标准,一个类型化的表具有与底层组合类型相对应的列,以及其他的“自引用列”。PostgreSQL 不显式支持这些自引用列,但是可以使用 OID 特性获得相同的效果。
PARTITION BY
子句
PARTITION BY
子句是一种PostgreSQL扩展。
PARTITION OF
子句
PARTITION OF
子句是一种PostgreSQL扩展。