SQL COMMAND · 查询与数据操作
INSERT
在表中插入新行
INSERT查询与数据操作引入 10(基线)现存至 20 devel3 次语法变更
- 动词
INSERT- 对象
—- 分组
- 查询与数据操作
- 引入版本
- 10(基线)
- 状态
- 现存
- 语法变更次数
- 3
- 手册小节数
- 6
版本轨迹
相对 PostgreSQL 17:语法概要新增 1 行,移除 0 行。
语法铁道图 PostgreSQL 18
沿轨道从左向右阅读,分岔表示选择,绕行表示可选,回环表示重复。方框为参数,点击带下划线的参数可展开子规则。
conflict_target
conflict_action
锁模式 PostgreSQL 18
具体锁模式取决于操作变体、目标对象和执行阶段;同一命令可同时取得表锁与行锁。查看完整冲突矩阵
ROW SHARE· 表级锁INSERT(外键检查):外键检查的内部 SELECT … FOR KEY SHARE 在被引用表上取得 ROW SHARE;写入目标表上的模式仍是 ROW EXCLUSIVE。ROW EXCLUSIVE· 表级锁INSERT:在写入的目标表上加锁;新插入行不能简单等同于对已有行取得 FOR UPDATE。INSERT … ON CONFLICT DO UPDATE(非键):这个写入变体在目标表上取得 ROW EXCLUSIVE;对已有行的锁另按实际动作取得。INSERT … ON CONFLICT DO UPDATE(键):这个写入变体在目标表上取得 ROW EXCLUSIVE;对已有行的锁另按实际动作取得。INSERT(外键检查):原始写入命令在写入目标表上取得 ROW EXCLUSIVE;外键检查的 ROW SHARE 与 FOR KEY SHARE 则作用于被引用的表和行,不能混为同一对象。FOR KEY SHARE· 行级锁INSERT(外键检查):实际检查非空外键引用时,在被引用表的匹配行上取得 FOR KEY SHARE;可能在语句内或延迟约束检查时执行。级联动作还会取得相应 UPDATE / DELETE 的锁。FOR NO KEY UPDATE· 行级锁INSERT … ON CONFLICT DO UPDATE(非键):冲突路径锁住要更新的已有行;锁强度按 UPDATE 的键列规则确定,即使 DO UPDATE WHERE 排除更新也会锁行。FOR UPDATE· 行级锁INSERT … ON CONFLICT DO UPDATE(键):冲突路径修改键列时,锁住冲突的已有行;不是普通 INSERT 的固定行锁。
语法概要
相对 PostgreSQL 17 新增 1 行,移除 0 行;新增行以绿色标记。
[ WITH [ RECURSIVE ]with_query[, ...] ] INSERT INTOtable_name[ ASalias] [ (column_name[, ...] ) ] [ OVERRIDING { SYSTEM | USER } VALUE ] { DEFAULT VALUES | VALUES ( {expression| DEFAULT } [, ...] ) [, ...] |query} [ ON CONFLICT [conflict_target]conflict_action] [ RETURNING [ WITH ( { OLD | NEW } ASoutput_alias[, ...] ) ] { * |output_expression[ [ AS ]output_name] } [, ...] ] 其中conflict_target可以是以下之一: ( {index_column_name| (index_expression) } [ COLLATEcollation] [opclass] [, ...] ) [ WHEREindex_predicate] ON CONSTRAINTconstraint_name其中conflict_action是以下之一: DO NOTHING DO UPDATE SET {column_name= {expression| DEFAULT } | (column_name[, ...] ) = [ ROW ] ( {expression| DEFAULT } [, ...] ) | (column_name[, ...] ) = (sub-SELECT) } [, ...] [ WHEREcondition]
描述
INSERT将新行插入表中。可以插入由值表达式指定的一行或多行,也可以插入由查询产生的零行或多行。
目标列名可以按任意顺序列出。如果根本未给出列名列表,则默认使用按声明顺序排列的全部列;或者如果VALUES子句或 query只提供了N列,则默认使用按声明顺序排列的前N个列名。VALUES子句或query 提供的值,会按从左到右的顺序与显式或隐式列列表对应起来。
任何未出现在显式或隐式列列表中的列都会填入默认值;如果没有声明默认值,则填入空值。
如果任何列的表达式数据类型不正确,将尝试自动进行类型转换。
对没有唯一索引的表执行INSERT不会被并发活动阻塞。若并发会话执行的操作会锁定或修改与待插入唯一索引值匹配的行,则带有唯一索引的表可能发生阻塞;详见第 63.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还要求对任何值会被读取的列具有SELECT权限。这包括 conflict_target中提到的任何列(包括仲裁约束引用的列),以及ON CONFLICT DO UPDATE的 expression或WHERE子句 condition中提到的任何列。
使用RETURNING子句要求对 RETURNING中提到的所有列具有 SELECT权限。如果使用query子句将查询结果中的行插入表中,那么当然还需要对查询中用到的任何表或列具有SELECT 权限。
参数
插入
本节介绍仅在插入新行时可用的参数。专门用于 ON CONFLICT子句的参数将单独说明。
with_queryWITH子句允许指定一个或多个子查询,这些子查询可以在INSERT查询中按名称引用。详见第 7.8 节和SELECT。query(SELECT语句)本身也可以包含WITH子句。在这种情况下,query中可以引用两组with_query,但由于第二组嵌套得更近,它具有更高的优先级。table_name一个现有表的名称(可以是模式限定的)。
aliastable_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_nameOLD.*返回目标表旧值,通过NEW.或column_nameNEW.*返回新值。提供别名后,这些名称会被隐藏,必须使用别名来引用旧行或新行。例如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 UPDATE子句的INSERT,旧值可能为非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 组成。所有在不考虑顺序的情况下恰好包含 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_actionconflict_action指定一个替代的ON CONFLICT动作。它可以是DO NOTHING,也可以是DO UPDATE子句,用以精确指定发生冲突时要执行的UPDATE动作细节。在ON CONFLICT DO UPDATE中,SET和WHERE子句既可以通过表名(或别名)访问现有行,也可以通过特殊表excluded访问拟插入的行。对于任何被读取的excluded列,必须对目标表中的对应列具有SELECT权限。注意,所有行级
BEFORE INSERT触发器的效果都会反映在excluded值中,因为这些效果可能促成该行被排除在插入之外。index_column_nametable_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命令会返回如下形式的命令标签:
INSERToidcount
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;
如果可能就插入新的分销商;否则执行 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;
兼容性
语法演化
相邻大版本之间的差异,新的在前。版本号链接到对应快照。
PostgreSQL 19← 18语法变化
+ DO SELECT [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } ] [ WHERE condition ]+ DO UPDATE SET { column_name = { expression | DEFAULT } |正文更新PostgreSQL 18← 17语法变化
+ [ RETURNING [ WITH ( { OLD | NEW } AS output_alias [, ...] ) ]正文更新PostgreSQL 17← 16正文更新
正文更新PostgreSQL 15← 14正文更新
正文更新PostgreSQL 14← 13正文更新
正文更新PostgreSQL 13← 12正文更新
正文更新PostgreSQL 12← 11语法变化
+ [ RETURNING { * | output_expression [ [ AS ] output_name ] } [, ...] ]正文更新PostgreSQL 11← 10正文更新
正文更新
同组命令
| 命令 | 动词 | 对象 | 版本变动 | 最近变更 |
|---|---|---|---|---|
COPY | COPY | — | 196 次 | |
| 在文件和表之间复制数据 | 现存 | |||
DELETE | DELETE | — | 182 次 | |
| 删除表中的行 | 现存 | |||
EXPLAIN | EXPLAIN | — | 195 次 | |
| 显示一个语句的执行计划 | 现存 | |||
INSERT | INSERT | — | 193 次 | |
| 在表中插入新行 | 现存 | |||
LOCK | LOCK | — | — | |
| 锁定表 | 现存 | |||
MERGE | MERGE | — | 182 次 | |
| 有条件地插入、更新或删除表中的行 | 现存 | |||
SELECT | SELECT | — | 176 次 | |
| 从表或视图中检索行 | 现存 | |||
UPDATE | UPDATE | — | 182 次 | |
| 更新表中的行 | 现存 | |||
VALUES | VALUES | — | — | |
| 计算一组行 | 现存 | |||
SELECT INTO | SELECT | INTO | 192 次 | |
| 根据查询结果定义一个新表 | 现存 | |||