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 [, ... ] ) ] [ 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 } [, ... ] ) ] [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | 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 | 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 ] 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 action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] like_option 是: { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | INDEXES | STORAGE | COMMENTS | ALL } UNIQUE、PRIMARY KEY以及EXCLUDE约束中的index_parameters是: [ WITH ( storage_parameter [= value] [, ... ] ) ] [ USING INDEX TABLESPACE tablespace_name ] 一个EXCLUDE约束中的exclude_element是: { column_name | ( expression ) } [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]
描述
CREATE TABLE将在当前数据库中创建一个新的、初始为空的表。该表将由发出该命令的用户所拥有。
如果给定了一个模式名(例如CREATE TABLE myschema.mytable ...),那么该表被创建在指定的模式中。否则它被创建在当前模式中。临时表存在于一个特殊的模式中,因此在创建一个临时表时不能给定一个模式名。该表的名称必须与同一个模式中的任何其他表、序列、索引、视图或外部表的名称区分开。
CREATE TABLE也会自动地创建一个数据类型来表示对应于该表一行的组合类型。因此,表不能用同一个模式中任何已有数据类型的名称。
可选的约束子句指定一个插入或更新操作要成功,新的或更新过的行必须满足的约束(测试)。一个约束是一个 SQL 对象,它帮助以多种方式定义表中的合法值集合。
有两种方式来定义约束:表约束和列约束。一个列约束会作为列定义的一部分定义。一个表约束定义不与一个特定列绑定,并且它可以包含多于一个列。每一个列约束也可以被写作一个表约束,列约束只是一种当约束只影响一列时方便书写的记号习惯。
要能创建一个表,你必须分别具有所有列类型或OF子句中类型的USAGE特权。
参数
- TEMPORARY or TEMP
-
如果指定,该表被创建为一个临时表。临时表会被在会话结束时自动被删除,或者也可以选择在当前事务结束时删除(见下文的ON COMMIT)。当临时表存在时,已有的同名持久表将对于当前会话不可见,不过可以使用模式限定的名称进行引用。在一个临时表上创建的任何索引也自动地变为临时的。
自动清理守护进程不能访问并且因此也不能清理或分析临时表。由于这个原因,应该通过会话的 SQL 命令执行合适的清理和分析操作。例如,如果一个临时表将要被用于复杂的查询,最好在把它填充完毕后在其上运行ANALYZE。
可以选择将GLOBAL或LOCAL写在TEMPORARY或TEMP的前面。这当前在PostgreSQL中没有区别并且已被废弃,见兼容性。
- UNLOGGED
-
如果指定,该表被创建为一个不受日志记录的表。被写入到不做日志的表中的数据不会被写到预写式日志中(见第 30 章),这让它们比普通表快非常多。不过,它们在崩溃时是不安全的:一个不做日志的表在一次崩溃或非干净关闭之后会被自动地截断。一个不做日志的表中的内容也不会被复制到后备服务器中。在一个不做日志的表上创建的任何索引也会自动地不被日志记录。
- 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设置也会从父表复制过来。
- LIKE source_table [ like_option ... ]
-
LIKE指定新表将从哪一个表自动地复制所有的列名、数据类型以及它们的非空约束。
和INHERITS不同,新表和原始表在创建完成之后是完全分离的。对原始表的更改将不会被应用到新表,并且不可能在原始表的扫描中包括新表的数据。
只有INCLUDING DEFAULTS被指定时,被拷贝的列定义的默认表达式才会被拷贝。默认的行为是排除默认表达式,导致新表中被拷贝过来的列的默认值为空值。注意,如果拷贝的默认值调用了数据库修改函数(如
nextval
),则可能在原始表和新表之间创建功能联系。非空约束总是会被复制到新表。CHECK约束只有在INCLUDING CONSTRAINTS被指定时才会被复制。列约束和表约束之间没有区别对待。
只有INCLUDING INDEXES被指定时,原始表上的索引、PRIMARY KEY、UNIQUE以及EXCLUDE约束将被创建在新表上。新索引和约束的名称将根据默认规则选定,而不管原始的名称如何(这种行为可以避免新索引重名导致的失败)。
只有INCLUDING STORAGE被指定时,复制而来的列定义的STORAGE设置才会被复制。默认行为会排除STORAGE设置,导致新表中复制而来的列具有与类型相关的默认设置。更多关于STORAGE设置的信息,请见第 65.2 节。
只有INCLUDING COMMENTS被指定时,复制而来的列、约束和索引的注释才会被拷贝。默认行为是排除注释,这导致新表中复制而来的列和约束没有注释。
INCLUDING ALL是 INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE INCLUDING COMMENTS的简写形式。
注意和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子句为出现在其定义中的列赋予一个默认数据。该值是可以使用变量的表达式(不允许用子查询和对其他列的交叉引用)。默认值表达式的数据类型必须匹配列的数据类型。
默认值表达式将被用在任何没有为该列指定值的插入操作中。如果一列没有默认值,那么默认值为空值。
- UNIQUE (列约束)
UNIQUE ( column_name [, ... ] ) (表约束) -
UNIQUE约束指定一个表中的一列或多列组成的组包含唯一的值。唯一表约束的行为与列约束的行为相同,只是表约束能够跨越多列。
对于一个唯一约束的目的来说,空值不被认为是相等的。
每一个唯一表约束必须命名一个列的集合,并且它与该表上任何其他唯一或主键约束所命名的列集合都不相同(否则它将是一个被列举了两次的约束)。
- PRIMARY KEY (列约束)
PRIMARY KEY ( column_name [, ... ] ) (表约束) -
PRIMARY KEY约束指定表的一个或者多个列只能包含唯一(不重复)、非空的值。一个表上只能指定一个主键,可以作为列约束或表约束。
主键约束所涉及的列集合应该不同于同一个表上定义的任何唯一约束的列集合(否则,该唯一约束是多余的并且会被丢弃)。
PRIMARY KEY强制的数据约束可以看成是UNIQUE和NOT NULL的组合,不过把一组列标识为主键也为模式设计提供了元数据,因为主键标识其他表可以依赖这一个列集合作为行的唯一标识符。
- EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ]
-
EXCLUDE子句定一个排除约束,它保证如果任意两行在指定列或表达式上使用指定操作符进行比较,不是所有的比较都将会返回TRUE。如果所有指定的操作符都测试相等,这就等价于一个UNIQUE约束,尽管一个普通的唯一约束将更快。不过,排除约束能够指定比简单相等更通用的约束。例如,你可以使用&&操作符指定一个约束,要求表中没有两行包含相互覆盖的圆(见 第 8.8 节)。
排除约束使用一个索引实现,这样每一个指定的操作符必须与用于索引访问方法index_method的一个适当的操作符类(见第 11.9 节)相关联。操作符被要求是交换的。每一个exclude_element可以选择性地指定一个操作符类或者顺序选项,这些在CREATE INDEX中有完整描述。
访问方法必须支持amgettuple(见第 59 章),目前这意味着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的主键。被引用列必须是被引用表中一个非可延迟唯一约束或主键约束的列。注意外键约束不能在临时表和永久表之间定义。
被插入到引用列的一个值会使用给定的匹配类型与被引用表的值进行匹配。有三种匹配类型: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 详见第 65.2 节)。如果一个表的参数值被设置但是相应的toast.参数没有被设置,那么 TOAST 表将使用该表的参数值。
- fillfactor (integer)
-
一个表的填充因子是一个 10 到 100 之间的百分数。100(完全填满)是默认值。当一个较小的填充因子被指定时,INSERT操作会把表页面只填满到指定的百分比,每个页面上剩余的空间被保留给该页上行的更新。这就让UPDATE有机会把一行的已更新版本放在与其原始版本相同的页面上,这比把它放在一个不同的页面上效率更高。对于一个项从来不会被更新的表来说,完全填满是最好的选择,但是在更新繁重的表上则较小的填充因子更合适。这个参数不能对 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才更有用。
- 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)
-
声明该表是一个用于逻辑复制目的的额外的目录表。详见第 47.6.2 节。不能对 TOAST 表设置这个参数。
注解
我们不推荐在新应用中使用 OID:在可能要用到的地方,使用一个SERIAL或者其他序列生成器作为表的主键会更好。不过,如果你的应用确实需要用到 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 DEFAULT nextval('serial'), 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命令遵从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)。注意这可能要显著地慢于立即唯一性检查。
NULL "约束"
NULL "约束"(实际上是一个非约束)是一个PostgreSQL对 SQL 标准的扩展,它也被包括(以及对称的NOT NULL约束)在一些其他的数据库系统中以实现兼容性。因为它是任意列的默认值,它的存在就像噪声一样。
继承
通过INHERITS子句的多继承是一种PostgreSQL的语言扩展。SQL:1999 以及之后的标准使用一种不同的语法和不同的语义定义了单继承。SQL:1999-风格的继承还没有被PostgreSQL。