↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

文档 → PostgreSQL devel 2026-09-28 13:10:20
受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 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 20 开发快照尚未正式发布,内容与行为随时可能变化;构建于 2026-09-28。正式内容请看当前版本。

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 [ WITH ( { OLD | NEW } AS output_alias [, ...] ) ]
                { * | 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 SELECT [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } ] [ WHERE condition ]
    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不会被并发活动阻塞。若并发会话执行的操作会锁定或修改与待插入唯一索引值匹配的行,则带有唯一索引的表可能发生阻塞;详见第 63.5 节。ON CONFLICT可用于指定一种替代动作,而不是报出违反唯一约束或排他约束的错误。(见下文ON CONFLICT Clause。)

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

要向表中插入行,必须具有该表上的INSERT权限。如果存在ON CONFLICT DO UPDATE子句,还要求具有该表上的UPDATE权限。如果存在ON CONFLICT DO SELECT,则还要求具有该表上的SELECT权限。如果使用 ON CONFLICT DO SELECT FOR UPDATE/SHARE,则除了SELECT权限外,还要求至少对一列具有 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查询中按名称引用。详见第 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_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进行限定,也可以用 OLD或NEW对应的 output_alias进行限定,以返回旧值或新值。未限定的列名或*,以及使用目标表名或别名限定的列名或*,都会返回新值。

对于普通INSERT,所有旧值都为 NULL。但对于带 ON CONFLICT DO SELECT/UPDATE子句的 INSERT,旧值可能为非NULL(当拟插入的行与现有行冲突时)。如果走的是SELECT路径,则新值与旧值相同,因为并不会发生修改。

output_name #

用于返回列的名称。

ON CONFLICT 子句

可选的ON CONFLICT子句指定一种替代动作,用来替代抛出唯一约束或排他约束违背错误。对于每一条拟插入的行,要么插入继续进行;要么如果违反了由conflict_target 指定的某个仲裁约束或索引,就执行替代的 conflict_action。ON CONFLICT DO NOTHING的替代动作只是跳过该行的插入。ON CONFLICT DO UPDATE的替代动作则是更新与拟插入行冲突的现有行。ON CONFLICT DO SELECT返回与拟插入行冲突的现有行,并可选择加行级锁。

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”。

ON CONFLICT DO SELECT同样保证得到原子的 INSERT或SELECT结果。这也称为幂等插入或获取或创建(get or create)。对于ON CONFLICT DO SELECT,必须提供RETURNING子句。

conflict_target #

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

conflict_action #

conflict_action指定一个替代的 ON CONFLICT动作。它可以是 DO NOTHING、允许返回冲突行的 DO SELECT子句,或者在发生冲突时精确指定 UPDATE动作细节的DO UPDATE 子句。

在DO UPDATE中的SET子句,以及DO SELECT和DO UPDATE 中的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 #

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

FOR UPDATE
FOR NO KEY UPDATE
FOR SHARE
FOR KEY SHARE #

如果在ON CONFLICT DO SELECT子句中指定这些形式,则冲突的表行会被锁定,以防并发更新。详见The Locking Clause和SELECT文档。

condition #

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

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

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

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

提示

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

输出

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

INSERT oid count

count是插入、更新或选中返回的行数。oid始终为 0(过去,如果 count恰好为 1 且目标表声明为 WITH OIDS,则它是分配给插入行的 OID,否则为 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';

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

-- 为井字棋创建一个空的 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;

按照上例插入或更新新的分销商,并返回任何被更新的既有值以及插入的新数据。请注意,对于没有冲突的行,返回的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子句来限制实际会被更新的行(不过,任何未更新的现有行仍会被锁定):

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

如果可能就插入新的分销商;否则返回现有的分销商行。示例假设已经定义了一个唯一索引,用于约束出现在did列中的值。这对获取或创建模式很有用:

INSERT INTO distributors (did, dname) VALUES (11, 'Global Electronics')
    ON CONFLICT (did) DO SELECT
    RETURNING *;

如果新分销商的 ID 不匹配,则插入它;否则,如果其名称不匹配,则返回现有行:

INSERT INTO distributors AS d (did, dname) VALUES (12, 'Micro Devices Inc')
    ON CONFLICT (did) DO SELECT WHERE d.dname != EXCLUDED.dname
    RETURNING *;

插入一个新分销商,或返回并锁定现有行以便更新。当你需要确保对该行的独占访问时,这很有用:

INSERT INTO distributors (did, dname) VALUES (13, 'Advanced Systems')
    ON CONFLICT (did) DO SELECT FOR UPDATE
    RETURNING *;

如果可能就插入新的分销商;否则执行 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填充的情况。如果你希望使用比ON CONFLICT更符合 SQL 标准的语句,请参见MERGE。

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

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

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游会在正式发布前持续修订。