↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1 / 7.0 / 6.5 / 6.4
历史版本。 PostgreSQL 13 已结束支持。 2025-11-13. 请参阅 当前版本手册.

INSERT

INSERT — 在表中插入新行

大纲

[ 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 { * | output_expression [ [ AS ] output_name ] } [, ...] ]

其中 conflict_target 可以是以下之一:

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

其中 conflict_action 是以下之一:

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

描述

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

目标列名可以按任意顺序列出。如果根本未给出列名列表,则默认使用按声明顺序排列的全部列;或者如果 VALUES 子句或 query 只提供了 N 列,则默认使用按声明顺序排列的前 N 个列名。VALUES 子句或 query 提供的值,会按从左到右的顺序与显式或隐式列列表对应起来。

任何未出现在显式或隐式列列表中的列都会填入默认值;如果没有声明默认值,则填入空值。

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

对没有唯一索引的表执行 INSERT 不会被并发活动阻塞。若并发会话执行的操作会锁定或修改与待插入唯一索引值匹配的行,则带有唯一索引的表可能发生阻塞;详见第 61.5 节。ON CONFLICT 可用于指定一种替代动作,而不是报出违反唯一约束或排他约束的错误。(见下文 ON CONFLICT Clause。)

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

要向表中插入行,必须具有该表上的 INSERT 权限。如果存在 ON CONFLICT DO UPDATE 子句,还要求具有该表上的 UPDATE 权限。

如果指定了列列表,你只需要对所列列具有 INSERT 权限。类似地,在指定 ON CONFLICT DO UPDATE 时,你只需要对列出要更新的列具有 UPDATE 权限。不过,ON CONFLICT DO UPDATE 还要求具有 SELECT 权限,涵盖 ON CONFLICT DO UPDATE 表达式或 condition 中读取其值的任何列。

使用 RETURNING 子句要求对 RETURNING 中提到的所有列具有 SELECT 权限。如果使用 query 子句将查询结果中的行插入表中,那么当然还需要对查询中用到的任何表或列具有 SELECT 权限。

参数

插入

本节介绍仅在插入新行时可用的参数。专门用于 ON CONFLICT 子句的参数将单独说明。

with_query

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

query(SELECT 语句)本身也可以包含 WITH 子句。在这种情况下,query 中可以引用两组 with_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 的标识列,如果插入显式值(DEFAULT 除外)而未指定 OVERRIDING SYSTEM VALUE 或 OVERRIDING USER VALUE,则会报错。(对于定义为 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_expression

在每一行插入或更新后由 INSERT 命令计算并返回的表达式。该表达式可以使用由 table_name 指定的表中的任何列。写成* 可返回插入或更新后行的全部列。

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 组成。所有在不考虑顺序的情况下恰好包含 conflict_target 指定列/表达式的 table_name 唯一索引,都会被推断(选中)为仲裁索引。如果指定了 index_predicate,则作为推断的进一步要求,候选仲裁索引还必须满足该谓词。注意,这意味着如果存在某个满足其他所有条件的非部分唯一索引(即没有谓词的唯一索引),那么该索引也会被推断出来(从而被 ON CONFLICT 使用)。如果推断尝试失败,则会报错。

ON CONFLICT DO UPDATE 保证得到原子的 INSERT 或 UPDATE 结果;只要没有其他独立错误,即使在高并发下,也能保证结果是这两者之一。这也称为 UPSERT — “UPDATE or INSERT”。

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 访问拟插入的行。对于任何被读取的 excluded 列,必须对目标表中的对应列具有 SELECT 权限。

注意,所有行级 BEFORE INSERT 触发器的效果都会反映在 excluded 值中,因为这些效果可能促成该行被排除在插入之外。

index_column_name

table_name 中某一列的名称。用于推断仲裁索引。遵循 CREATE INDEX 的格式。要求对 index_column_name 具有 SELECT 权限。

index_expression

与 index_column_name 类似,但用于推断出现在索引定义中的、基于 table_name 列的表达式(而非简单列)。遵循 CREATE INDEX 的格式。要求对出现在 index_expression 中的任何列具有 SELECT 权限。

collation

指定时,要求相应的 index_column_name 或 index_expression 必须使用特定的排序规则,才能在推断时匹配。通常会省略,因为排序规则通常不会影响是否发生约束违背。遵循 CREATE INDEX 格式。

opclass

指定时,要求相应的 index_column_name 或 index_expression 必须使用特定的操作符类,才能在推断时匹配。通常会省略,因为一种类型的各个操作符类在相等性语义上往往是等价的,或者只需相信已定义的唯一索引具有所需的相等性定义即可。遵循 CREATE INDEX 格式。

index_predicate

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

constraint_name

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

condition

返回 boolean 值的表达式。只有使该表达式返回 true 的行才会被更新,不过一旦采取 ON CONFLICT DO UPDATE 动作,所有行都会被锁定。请注意,只有在某个冲突已被识别为更新候选后,才会最后计算 condition。

请注意,排他约束不支持在 ON CONFLICT DO UPDATE 中充当仲裁对象。在所有情况下,只有 NOT DEFERRABLE 约束和唯一索引可作为仲裁对象。

带有 ON CONFLICT DO UPDATE 子句的 INSERT 是一种“确定性”语句。这意味着不允许该命令对任何单个现有行产生多于一次的影响;一旦出现这种情况,就会报出基数违背错误。拟插入的行在受仲裁索引或约束限制的属性上不应彼此重复。

请注意,目前尚不支持在针对分区表的 INSERT 的 ON CONFLICT DO UPDATE 子句中更新冲突行的分区键,从而需要将该行移动到一个新分区。

提示

通常更推荐使用唯一索引推断,而不是通过 ON CONFLICT ON CONSTRAINT constraint_name 直接命名约束。当底层索引以重叠方式被另一个大致等价的索引替换时,推断仍能继续正确工作,例如在删除待替换索引之前先使用 CREATE UNIQUE INDEX ... CONCURRENTLY。

警告

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

输出

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

INSERT oid count

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

如果 INSERT 命令包含 RETURNING 子句,则结果将类似于一个 SELECT 语句,其中包含 RETURNING 列表定义的列和值,它们是基于该命令插入或更新的行计算出来的。

注解

如果指定的表是分区表,则每一行都会被路由到适当的分区并插入其中。如果指定的表本身就是一个分区,则只要输入行中有任意一行违反该分区约束,就会报错。

示例

向表 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';

这个示例向数组列插入值:

-- 为井字棋创建一个空的 3x3 棋盘
INSERT INTO tictactoe (game, board[1:3][1:3])
    VALUES (1, '{{" "," "," "},{" "," "," "},{" "," "," "}}');
-- 上例中的下标实际上并非必需
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;

插入一个分销商;如果已存在一条会导致待插入行被排除的现有行(即在行级 BEFORE INSERT 触发器触发后,其受约束列与待插入行匹配的行),则对该待插入行不做任何操作。示例假设已经定义了一个唯一索引,用于约束出现在 did 列中的值:

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

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

-- 不更新位于某个邮政编码区域内的现有分销商
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';

-- 在语句中直接指定约束名称(使用关联的
-- 索引来仲裁是否采取 DO NOTHING 动作)
INSERT INTO distributors (did, dname) VALUES (9, 'Antwerp Design')
    ON CONFLICT ON CONSTRAINT distributors_pkey DO NOTHING;

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

-- 这条语句可以推断出 "did" 上以 "WHERE is_active"
-- 为谓词的部分唯一索引,但也可以直接使用
-- "did" 上的普通唯一约束
INSERT INTO distributors (did, dname) VALUES (10, 'Conrad International')
    ON CONFLICT (did) WHERE is_active DO NOTHING;

兼容性

INSERT 符合 SQL 标准,但 RETURNING 子句是 PostgreSQL 扩展,在 INSERT 中使用 WITH 的能力以及使用 ON CONFLICT 指定替代动作的能力也都是扩展。此外,标准不允许省略列名列表却又不是所有列都由 VALUES 子句或 query 填充的情况。

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

query 子句可能存在的限制见 SELECT。

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.