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

INSERT

INSERT — 在表中创建新行

Synopsis

[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
    [ OVERRIDING { SYSTEM | USER } VALUE ]
    { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
    [ ON CONFLICT [ conflict_target ] conflict_action ]
    [ RETURNING [ WITH ( { OLD | NEW } AS output_alias [, ...] ) ]
                { * | output_expression [ [ AS ] output_name ] } [, ...] ]

where conflict_target can be one of:

    ( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]
    ON CONSTRAINT constraint_name

and conflict_action is one of:

    DO NOTHING
    DO UPDATE SET { column_name = { expression | DEFAULT } |
                    ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
                    ( column_name [, ...] ) = ( sub-SELECT )
                  } [, ...]
              [ WHERE condition ]

描述

INSERT 向表中插入新行。可以插入由值表达式指定的一行或多行,也可以插入由查询得到的零行或多行。

目标列名可以按任意顺序列出。如果完全没有给出列名列表,则默认为表中按声明顺序排列的所有列;或者,在只给出了 N 列时,默认为前 N 个列名,这些列由 VALUES 子句或 query 提供。VALUES 子句或 query 提供的值会按从左到右的顺序与显式或隐式的列列表相关联。

显式或隐式列列表中没有出现的每一列都将被填充默认值,即它声明的默认值;如果没有默认值,则填充空值。

如果任何列的表达式不是正确的数据类型,将会尝试进行自动类型转换。

向缺少唯一索引的表执行 INSERT 不会被并发活动阻塞。具有唯一索引的表可能会发生阻塞,如果并发会话执行的操作锁定或修改了与正在插入的唯一索引值相匹配的行;详细信息见 Section 63.5。可以使用 ON CONFLICT 来指定一种替代动作,以代替引发唯一约束或排他约束冲突错误。(参见下文的 ON CONFLICT Clause。)

可选的 RETURNING 子句使得 INSERT 基于实际插入(或更新,如果使用了 ON CONFLICT DO UPDATE 子句)的每一行计算并返回值。这主要用于获取由默认值提供的值,例如序列号。不过,也允许使用该表的列的任何表达式。RETURNING 列表的语法与 SELECT 的输出列表完全相同。只有成功插入或更新的行才会被返回。例如,如果某行因为 ON CONFLICT DO UPDATE ... WHERE 子句的 condition 未得到满足而被锁定但没有被更新,则该行不会被返回。

必须对表拥有 INSERT 特权才能向其中插入。如果存在 ON CONFLICT DO UPDATE,还需要对该表拥有 UPDATE 特权。

如果指定了列列表,则只需要对所列出的列拥有 INSERT 特权。类似地,当指定了 ON CONFLICT DO UPDATE 时,只需要对被列出要更新的列拥有 UPDATE 特权。不过,ON CONFLICT 的所有形式还要求对任何被读取值的列拥有 SELECT 特权。这包括 conflict_target 中提到的任何列(包括仲裁者约束所引用的列),以及 ON CONFLICT DO UPDATE 的 expression 或 WHERE 子句的 condition 中提到的任何列。

使用 RETURNING 子句需要对 RETURNING 中提到的所有列拥有 SELECT 特权。如果使用 query 子句从查询中插入行,当然还需要对查询中使用的任何表或列拥有 SELECT 特权。

参数

插入

本节介绍仅插入新行时可以使用的参数。仅与 ON CONFLICT 子句一起使用的参数将单独描述。

with_query

WITH 子句允许你指定一个或多个子查询,这些子查询可以在 INSERT 查询中按名称引用。详见 Section 7.8 和 SELECT。

query(SELECT 语句)本身也可以包含 WITH 子句。在这种情况下,两组 with_query 都可以在 query 中被引用,但由于第二组嵌套得更深,它会优先。

table_name

一个现有表的名字(可以用模式限定)。

alias

table_name 的替代名称。提供别名后,它会完全隐藏表的实际名称。当 ON CONFLICT DO UPDATE 的目标是一个名为 excluded 的表时,这一点特别有用,否则该名称将被当作表示待插入行的特殊表的名字。

column_name

由 table_name 命名的表中某一列的名称。如有需要,列名可以用子字段名或数组下标限定。(只向组合列的部分字段插入会使其他字段为空值。)在使用 ON CONFLICT DO UPDATE 引用列时,不要在目标列的指定中包含表名。例如,INSERT INTO table_name ... ON CONFLICT DO UPDATE SET table_name.col = 1 是无效的(这遵循 UPDATE 的一般行为)。

OVERRIDING SYSTEM VALUE

如果指定了此子句,那么为标识列提供的任何值都将覆盖默认的序列生成值。

对于定义为 GENERATED ALWAYS 的标识列,如果没有指定 OVERRIDING SYSTEM VALUE 或 OVERRIDING USER VALUE,则插入显式值(DEFAULT 除外)是一个错误。(对于定义为 GENERATED BY DEFAULT 的标识列,OVERRIDING SYSTEM VALUE 是正常行为,指定它没有任何效果,但 PostgreSQL 作为扩展允许这样做。)

OVERRIDING USER VALUE

如果指定了此子句,那么为标识列提供的任何值都会被忽略,并应用默认的序列生成值。

例如,在表之间复制值时,此子句很有用。写入 INSERT INTO tbl2 OVERRIDING USER VALUE SELECT * FROM tbl1 将从 tbl1 复制所有在 tbl2 中不是标识列的列,而 tbl2 中标识列的值将由与 tbl2 关联的序列生成。

DEFAULT VALUES

所有列都将被填充其默认值,就像为每一列显式指定了 DEFAULT 一样。(这种形式不允许使用 OVERRIDING 子句。)

expression

要赋给对应列的表达式或值。

DEFAULT

对应的列将被填充其默认值。标识列将被填充由关联序列生成的新值。对于生成列,允许指定此项,但这只是指定了从生成表达式计算该列的正常行为。

query

一个提供待插入行的查询(SELECT 语句)。语法说明请参见 SELECT 语句。

output_alias

RETURNING 列表中 OLD 或 NEW 行的可选替代名称。

默认情况下,可以通过写 OLD.column_name 或 OLD.* 来返回目标表中的旧值,通过写 NEW.column_name 或 NEW.* 来返回新值。提供别名后,这些名称将被隐藏,必须使用该别名来引用旧行或新行。例如 RETURNING WITH (OLD AS o, NEW AS n) o.*, n.*。

output_expression

在每一行被插入或更新之后,由 INSERT 命令计算并返回的表达式。该表达式可以使用由 table_name 命名的表的任何列名。写入 * 可返回被插入或更新的行的所有列。

列名或 * 可以用 OLD 或 NEW 限定,或者用相应的 output_alias(对应 OLD 或 NEW)来限定,以返回旧值或新值。不带限定的列名或 *,或者用目标表名或别名限定的列名或 *,将返回新值。

对于简单的 INSERT,所有旧值都将为 NULL。但对于 INSERT 带有 ON CONFLICT DO UPDATE 子句的情形,旧值可能为非 NULL。

output_name

用于返回列的名称。

ON CONFLICT 子句

可选的 ON CONFLICT 子句指定一种替代动作,以代替引发唯一性冲突或排他约束冲突错误。对于每个待插入的行,要么继续插入,要么在仲裁者约束或索引(由 conflict_target 指定)被违反时,采取替代的 conflict_action。ON CONFLICT DO NOTHING 的替代动作只是避免插入该行。ON CONFLICT DO UPDATE 的替代动作则是更新与待插入行相冲突的现有行。

conflict_target 可以执行唯一索引推断。执行推断时,它由一个或多个 index_column_name 列和/或 index_expression 表达式,以及一个可选的 index_predicate 组成。table_name 的所有唯一索引中,只要不考虑顺序地恰好包含 conflict_target 指定的列/表达式,就会被推断(选定)为仲裁索引。如果指定了 index_predicate,作为推断的进一步要求,仲裁索引必须满足该谓词。注意,这意味着如果一个满足所有其他条件的非部分唯一索引(没有谓词的唯一索引)可用,它将被推断出来(从而被 ON CONFLICT 使用)。如果推断尝试不成功,则会引发错误。

ON CONFLICT DO UPDATE 保证原子性的 INSERT 或 UPDATE 结果;只要没有独立的错误发生,即使在高并发下也能保证出现这两种结果之一。这也被称为 UPSERT — “更新或插入”。

conflict_target

指定 ON CONFLICT 通过选择仲裁索引来对哪些冲突采取替代动作。既可以执行唯一索引推断,也可以显式命名一个约束。对于 ON CONFLICT DO NOTHING,指定 conflict_target 是可选的;省略时,将处理与所有可用约束(和唯一索引)的冲突。对于 ON CONFLICT DO UPDATE,提供 conflict_target 则是必须的。

conflict_action

conflict_action 指定一种替代的 ON CONFLICT 动作。它可以是 DO NOTHING,也可以是一个 DO UPDATE 子句,后者指定发生冲突时要执行的 UPDATE 动作的确切细节。ON CONFLICT DO UPDATE 中的 SET 和 WHERE 子句可以使用表名(或别名)访问现有行,并可以使用特殊的 excluded 表访问待插入的行。SELECT 特权对于目标表中被读取了对应 excluded 列值的任何列都是必需的。

注意,所有行级 BEFORE INSERT 触发器的效果都会反映在 excluded 值中,因为这些效果可能正是导致该行被排除而不被插入的原因。

index_column_name

table_name 的一个列名。用于推断仲裁索引。遵循 CREATE INDEX 格式。SELECT 特权对于 index_column_name 是必需的。

index_expression

与 index_column_name 类似,但用于推断索引定义中出现的基于 table_name 列的表达式(而非简单列)。遵循 CREATE INDEX 格式。SELECT 特权对于 index_expression 中出现的任何列都是必需的。

collation

指定后,将要求相应的 index_column_name 或 index_expression 在推断过程中使用特定的排序规则才能匹配。通常省略此项,因为排序规则通常不影响是否发生约束冲突。遵循 CREATE INDEX 格式。

opclass

指定后,将要求相应的 index_column_name 或 index_expression 在推断过程中使用特定的操作符类才能匹配。通常省略此项,因为一种类型的各操作符类之间的相等语义往往是等价的,或者因为可以相信已定义的唯一索引具有相关的相等定义。遵循 CREATE INDEX 格式。

index_predicate

用于允许推断部分唯一索引。任何满足该谓词的索引(不必实际上是部分索引)都可以被推断出来。遵循 CREATE INDEX 格式。SELECT 特权对于 index_predicate 中出现的任何列都是必需的。

constraint_name

通过名称显式指定一个仲裁者约束,而不是推断约束或索引。

condition

一个返回 boolean 类型值的表达式。只有该表达式返回 true 的行才会被更新,不过当采取 ON CONFLICT DO UPDATE 动作时,所有行都会被锁定。注意,condition 在最后求值,即在冲突已被确定为更新候选之后。

注意,ON CONFLICT DO UPDATE 不支持将排他约束用作仲裁者。在任何情况下,都只有 NOT DEFERRABLE 约束和唯一索引可以用作仲裁者。

INSERT 带有 ON CONFLICT DO UPDATE 子句时,它是一条“确定性”语句。这意味着不允许该命令对任何单个现有行产生一次以上的影响;当出现这种情况时,将引发基数冲突错误。待插入的行在受仲裁索引或仲裁者约束的属性方面不应相互重复。

注意,目前不支持这样的情形:ON CONFLICT DO UPDATE 子句(属于应用于分区表的 INSERT)更新了冲突行的分区键,以致需要把该行移动到新的分区。

Tip

与使用 ON CONFLICT ON CONSTRAINT constraint_name 直接命名约束相比,使用唯一索引推断通常更好。当底层索引以重叠方式被另一个大致等效的索引替换时(例如在删除被替换的索引之前使用 CREATE UNIQUE INDEX ... CONCURRENTLY),推断仍能继续正常工作。

Warning

当 CREATE INDEX CONCURRENTLY 或 REINDEX CONCURRENTLY 正在某个唯一索引上运行时,同一表上的 INSERT ... ON CONFLICT 语句可能会意外地因唯一性冲突而失败。

输出

成功完成时,INSERT 命令会返回如下形式的命令标签:

INSERT oid count

count 是被插入或更新的行数。oid 总是 0(过去,它是分配给被插入行的 OID,前提是 count 恰好为一且目标表被声明为 WITH OIDS,否则为 0,但现在已经不再支持创建 WITH OIDS 的表)。

如果 INSERT 命令包含 RETURNING 子句,其结果将类似于一条 SELECT 语句的结果,该语句包含在 RETURNING 列表中定义的列和值,并针对该命令插入或更新的行进行计算。

注记

如果指定的表是分区表,每一行都会被路由到相应的分区并插入其中。如果指定的表是一个分区,当输入行中有某一行违反该分区的分区约束时,将发生错误。

你也可以考虑使用 MERGE,因为它允许在单一语句中混合使用 INSERT、UPDATE 和 DELETE。参见 MERGE。

示例

向表 films 插入单行:

INSERT INTO films VALUES
    ('UA502', 'Bananas', 105, '1971-07-13', 'Comedy', '82 minutes');

在这个例子中,len 列被省略,因此它将具有默认值:

INSERT INTO films (code, title, did, date_prod, kind)
    VALUES ('T_601', 'Yojimbo', 106, '1961-06-16', 'Drama');

这个例子对日期列使用 DEFAULT 子句而不是指定一个值:

INSERT INTO films VALUES
    ('UA502', 'Bananas', 105, DEFAULT, 'Comedy', '82 minutes');
INSERT INTO films (code, title, did, date_prod, kind)
    VALUES ('T_601', 'Yojimbo', 106, DEFAULT, 'Drama');

插入一个完全由默认值组成的行:

INSERT INTO films DEFAULT VALUES;

使用多行 VALUES 语法插入多行:

INSERT INTO films (code, title, did, date_prod, kind) VALUES
    ('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
    ('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy');

这个例子从一个与 films 具有相同列布局的表 tmp_films 向表 films 插入一些行:

INSERT INTO films SELECT * FROM tmp_films WHERE date_prod < '2004-05-07';

这个例子向数组列插入数据:

-- Create an empty 3x3 gameboard for noughts-and-crosses
INSERT INTO tictactoe (game, board[1:3][1:3])
    VALUES (1, '{{" "," "," "},{" "," "," "},{" "," "," "}}');
-- The subscripts in the above example aren't really needed
INSERT INTO tictactoe (game, board)
    VALUES (2, '{{X," "," "},{" ",O," "},{" ",X," "}}');

向表 distributors 插入单行,并返回由 DEFAULT 子句生成的序列号:

INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets')
   RETURNING did;

增加为 Acme Corporation 管理账户的销售人员的销售计数,并将整个更新后的行连同当前时间记录到一个日志表中:

WITH upd AS (
  UPDATE employees SET sales_count = sales_count + 1 WHERE id =
    (SELECT sales_person FROM accounts WHERE name = 'Acme Corporation')
    RETURNING *
)
INSERT INTO employees_log SELECT *, current_timestamp FROM upd;

视情况插入或更新新的分销商。假设已经定义了一个唯一索引,用于约束 did 列中出现的值。注意,特殊的 excluded 表被用来引用最初提议插入的值:

INSERT INTO distributors (did, dname)
    VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc')
    ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname;

按上文的方式插入或更新新的分销商,返回有关被更新的任何现有值的信息以及插入的新数据。注意,对于未发生冲突的行,old_did 和 old_dname 的返回值将为 NULL:

INSERT INTO distributors (did, dname)
    VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc')
    ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname
    RETURNING old.did AS old_did, old.dname AS old_dname,
              new.did AS new_did, new.dname AS new_dname;

插入一个分销商;当已存在一个被排除的行(在行级 BEFORE INSERT 触发器触发之后,受约束的一个或多个列与之匹配的行)时,对提议插入的行什么也不做。例子假设已经定义了一个唯一索引,用于约束 did 列中出现的值:

INSERT INTO distributors (did, dname) VALUES (7, 'Redline GmbH')
    ON CONFLICT (did) DO NOTHING;

视情况插入或更新新的分销商。例子假设已经定义了一个唯一索引,用于约束 did 列中出现的值。WHERE 子句用于限制实际被更新的行(不过,任何未被更新的现有行仍会被锁定):

-- Don't update existing distributors based in a certain ZIP code
INSERT INTO distributors AS d (did, dname) VALUES (8, 'Anvil Distribution')
    ON CONFLICT (did) DO UPDATE
    SET dname = EXCLUDED.dname || ' (formerly ' || d.dname || ')'
    WHERE d.zipcode <> '21201';

-- Name a constraint directly in the statement (uses associated
-- index to arbitrate taking the DO NOTHING action)
INSERT INTO distributors (did, dname) VALUES (9, 'Antwerp Design')
    ON CONFLICT ON CONSTRAINT distributors_pkey DO NOTHING;

如果可能,插入新的分销商;否则执行 DO NOTHING。例子假设已经定义了一个唯一索引,用于在 is_active 布尔列取值为 true 的行子集上约束 did 列中出现的值:

-- This statement could infer a partial unique index on "did"
-- with a predicate of "WHERE is_active", but it could also
-- just use a regular unique constraint on "did"
INSERT INTO distributors (did, dname) VALUES (10, 'Conrad International')
    ON CONFLICT (did) WHERE is_active DO NOTHING;

兼容性

INSERT 符合 SQL 标准,但 RETURNING 子句是 PostgreSQL 的扩展,将 WITH 与 INSERT 一起使用的能力以及用 ON CONFLICT 指定替代动作的能力也是如此。此外,省略列名列表但并非所有列都由 VALUES 子句或 query 填充的情形是标准所不允许的。如果你想要比 ON CONFLICT 更符合 SQL 标准的语句,请参见 MERGE。

SQL 标准规定,只有当存在一个按 GENERATED ALWAYS 方式生成的标识列时,才能指定 OVERRIDING SYSTEM VALUE。PostgreSQL 在任何情况下都允许该子句,并在它不适用时忽略它。

query 子句可能的限制记录在 SELECT 中。