UPDATE — 更新表的行
[ WITH [ RECURSIVE ]with_query
[, ...] ] UPDATE [ ONLY ]table_name
[ * ] [ [ AS ]alias
] SET {column_name
= {expression
| DEFAULT } | (column_name
[, ...] ) = [ ROW ] ( {expression
| DEFAULT } [, ...] ) | (column_name
[, ...] ) = (sub-SELECT
) } [, ...] [ FROMfrom_item
[, ...] ] [ WHEREcondition
| WHERE CURRENT OFcursor_name
] [ RETURNING { * |output_expression
[ [ AS ]output_name
] } [, ...] ]
UPDATE
更改满足条件的所有行中指定列的值。只有需要修改的列需要在 SET
子句中提及;未明确修改的列保留其先前值。
有两种方法可以使用数据库中其他表包含的信息来修改表:使用子选择或在 FROM
子句中指定其他表。哪种技术更合适取决于具体情况。
可选的 RETURNING
子句导致 UPDATE
计算并返回基于每个实际更新行的值。可以使用表列和/或 FROM
中提到的其他表的列的任何表达式进行计算。使用表的列的新(更新后)值。 RETURNING
列表的语法与 SELECT
的输出列表的语法相同。
您必须对表具有 UPDATE
权限,或者至少对列出要更新的列具有 UPDATE
权限。您还必须对在 expressions
或 condition
中读取其值的任何列具有 SELECT
权限。
with_query
WITH
子句允许您指定一个或多个子查询,这些子查询可以在 UPDATE
查询中按名称引用。有关详细信息,请参见 第 7.8 节 和 SELECT。
table_name
要更新的表的名称(可选地进行模式限定)。如果在表名前指定了 ONLY
,则仅在指定的表中更新匹配的行。如果未指定 ONLY
,则还会更新从指定表继承的任何表中的匹配行。可选地,可以在表名后指定 *
以明确指示包含后代表。
alias
目标表的替代名称。提供别名时,它会完全隐藏表的实际名称。例如,给定 UPDATE foo AS f
,UPDATE
语句的其余部分必须将此表称为 f
而不是 foo
。
column_name
由 table_name
命名的表中的一列的名称。如果需要,列名可以使用子字段名称或数组下标进行限定。不要在目标列的规范中包含表的名称 - 例如,UPDATE table_name SET table_name.col = 1
无效。
expression
要分配给列的表达式。该表达式可以使用此表中以及其他列的旧值。
DEFAULT
将列设置为其默认值(如果未为其分配特定的默认表达式,则为 NULL)。标识列将设置为关联序列生成的新值。对于生成的列,允许指定此项,但这仅仅指定了根据其生成表达式计算列的正常行为。
sub-SELECT
一个 SELECT
子查询,它产生的输出列与它前面的括号内的列列表一样多。子查询在执行时必须产生不超过一行。如果它产生一行,则其列值将分配给目标列;如果它不产生任何行,则将 NULL 值分配给目标列。子查询可以引用正在更新的表的当前行的旧值。
from_item
一个表表达式,允许来自其他表的列出现在 WHERE
条件和更新表达式中。这使用与 FROM
的 SELECT
语句相同的语法;例如,可以为表名称指定一个别名。除非您打算进行自连接(在这种情况下,它必须在 from_item
中使用别名出现),否则不要将目标表重复为 from_item
。
condition
返回类型为 boolean
的值的表达式。只有此表达式返回 true
的行才会被更新。
cursor_name
在 WHERE CURRENT OF
条件中使用的游标的名称。要更新的行是最近从该游标中提取的行。该游标必须是对 UPDATE
的目标表的非分组查询。请注意,WHERE CURRENT OF
不能与布尔条件一起指定。有关使用 WHERE CURRENT OF
的游标的更多信息,请参见 DECLARE。
output_expression
在更新每一行后由 UPDATE
命令计算并返回的表达式。该表达式可以使用由 table_name
或 FROM
中列出的表命名的表的任何列名。编写 *
以返回所有列。
output_name
要用于返回列的名称。
成功完成时,UPDATE
命令将返回以下形式的命令标签:
UPDATE count
count
是更新的行数,包括值未更改的匹配行。请注意,当更新被 BEFORE UPDATE
触发器抑制时,该数字可能小于匹配 condition
的行数。如果 count
为 0,则查询未更新任何行(这不被认为是错误)。
如果 UPDATE
命令包含 RETURNING
子句,则结果将类似于包含在 RETURNING
列表中定义的列和值的 SELECT
语句,这些列和值是在命令更新的行上计算的。
当存在 FROM
子句时,实际上发生的事情是目标表与 from_item
列表中提到的表连接,并且联接的每个输出行都表示目标表的更新操作。使用 FROM
时,应确保联接最多为每个要修改的行生成一个输出行。换句话说,目标行不应该与其他表中的多个行连接。如果它确实如此,则仅使用联接行之一来更新目标行,但使用哪一个行是无法预测的。
由于这种不确定性,仅在子选择中引用其他表更安全,尽管通常比使用联接更难阅读且速度更慢。
对于分区表,更新行可能会导致它不再满足包含分区的分区约束。在这种情况下,如果分区树中存在其他一些分区,并且此行满足其分区约束,则该行将移动到该分区。如果没有这样的分区,则会发生错误。在幕后,行移动实际上是 DELETE
和 INSERT
操作。
可能存在对正在移动的行进行并发 UPDATE
或 DELETE
会导致序列化失败错误的情况。假设会话 1 正在对分区键执行 UPDATE
,而与此同时,此行可见的并发会话 2 对此行执行 UPDATE
或 DELETE
操作。在这种情况下,会话 2 的 UPDATE
或 DELETE
将检测到行移动并引发序列化失败错误(始终返回 SQLSTATE 代码“40001”)。如果发生这种情况,应用程序可能希望重试事务。在表未分区或没有行移动的常见情况下,会话 2 将识别新更新的行并在该新行版本上执行 UPDATE
/DELETE
。
请注意,虽然可以将行从本地分区移动到外部表分区(前提是外部数据包装器支持元组路由),但不能将它们从外部表分区移动到另一个分区。
如果发现外键直接引用源分区的祖先,而该祖先与 UPDATE
查询中提到的祖先不同,则尝试将行从一个分区移动到另一个分区将失败。
将表 films
的列 kind
中的单词 Drama
更改为 Dramatic
UPDATE films SET kind = 'Dramatic' WHERE kind = 'Drama';
调整表 weather
中一行中的温度条目并将降水量重置为其默认值
UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT WHERE city = 'San Francisco' AND date = '2003-07-03';
执行相同的操作并返回更新的条目
UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT WHERE city = 'San Francisco' AND date = '2003-07-03' RETURNING temp_lo, temp_hi, prcp;
使用替代的列列表语法执行相同的更新
UPDATE weather SET (temp_lo, temp_hi, prcp) = (temp_lo+1, temp_lo+15, DEFAULT) WHERE city = 'San Francisco' AND date = '2003-07-03';
使用 FROM
子句语法,递增管理 Acme Corporation 账户的销售人员的销售计数。
UPDATE employees SET sales_count = sales_count + 1 FROM accounts WHERE accounts.name = 'Acme Corporation' AND employees.id = accounts.sales_person;
执行相同的操作,在 WHERE
子句中使用子查询。
UPDATE employees SET sales_count = sales_count + 1 WHERE id = (SELECT sales_person FROM accounts WHERE name = 'Acme Corporation');
更新账户表中的联系人姓名,使其与当前分配的销售人员匹配。
UPDATE accounts SET (contact_first_name, contact_last_name) = (SELECT first_name, last_name FROM employees WHERE employees.id = accounts.sales_person);
可以使用连接实现类似的结果。
UPDATE accounts SET contact_first_name = first_name, contact_last_name = last_name FROM employees WHERE employees.id = accounts.sales_person;
但是,如果 employees
.id
不是唯一键,则第二个查询可能会产生意外的结果,而第一个查询如果有多个 id
匹配则保证会引发错误。此外,如果某个 accounts
.sales_person
条目没有匹配项,则第一个查询会将相应的名称字段设置为 NULL,而第二个查询则根本不会更新该行。
更新汇总表中的统计信息,使其与当前数据匹配。
UPDATE summary s SET (sum_x, sum_y, avg_x, avg_y) = (SELECT sum(x), sum(y), avg(x), avg(y) FROM data d WHERE d.group_id = s.group_id);
尝试插入新的库存项目以及库存数量。如果该项目已存在,则更新现有项目的库存数量。为了在不使整个事务失败的情况下做到这一点,请使用保存点。
BEGIN; -- other operations SAVEPOINT sp1; INSERT INTO wines VALUES('Chateau Lafite 2003', '24'); -- Assume the above fails because of a unique key violation, -- so now we issue these commands: ROLLBACK TO sp1; UPDATE wines SET stock = stock + 24 WHERE winename = 'Chateau Lafite 2003'; -- continue with other operations, and eventually COMMIT;
更改光标 c_films
当前所在行的表 films
的 kind
列。
UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_films;
影响许多行的更新可能会对系统性能产生负面影响,例如表膨胀、复制延迟增加和锁争用增加。在这种情况下,可以考虑分批执行操作,可能在批次之间对表执行 VACUUM
操作。虽然 UPDATE
没有 LIMIT
子句,但可以通过使用 公共表表达式 和自连接获得类似的效果。使用标准的 PostgreSQL 表访问方法,对系统列 ctid 进行自连接非常高效。
WITH exceeded_max_retries AS ( SELECT w.ctid FROM work_item AS w WHERE w.status = 'active' AND w.num_retries > 10 ORDER BY w.retry_timestamp FOR UPDATE LIMIT 5000 ) UPDATE work_item SET status = 'failed' FROM exceeded_max_retries AS emr WHERE work_item.ctid = emr.ctid;
需要重复执行此命令,直到没有剩余行需要更新。使用 ORDER BY
子句允许命令优先更新哪些行;如果其他更新操作使用相同的排序,它还可以防止死锁。如果锁争用是一个问题,那么可以将 SKIP LOCKED
添加到CTE以防止多个命令更新同一行。但是,然后需要一个最终的 UPDATE
,不带 SKIP LOCKED
或 LIMIT
,以确保没有忽略任何匹配的行。
此命令符合SQL标准,除了 FROM
和 RETURNING
子句是 PostgreSQL 扩展之外,与 UPDATE
一起使用 WITH
的能力也是如此。
一些其他数据库系统提供了一个 FROM
选项,其中目标表应该在 FROM
中再次列出。这不是 PostgreSQL 解释 FROM
的方式。在移植使用此扩展的应用程序时要小心。
根据标准,目标列名称的带括号的子列表的源值可以是任何产生正确列数的行值表达式。PostgreSQL 仅允许源值是 行构造器 或子 SELECT
。在行构造器情况下,可以将单个列的更新值指定为 DEFAULT
,但在子 SELECT
中则不行。
如果您在文档中发现任何不正确的内容、与您对特定功能的体验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。