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_queryWITH 子句允许您指定一个或多个可以在 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
当更新被 BEFORE UPDATE 触发器抑制时,count 是更新的行数,包括值未更改的匹配行。请注意,该数字可能小于与 condition 匹配的行数。如果 count 为 0,则查询未更新任何行(这不被视为错误)。
如果 UPDATE 命令包含 RETURNING 子句,则结果将类似于 SELECT 语句的结果,其中包含 RETURNING 列表中定义的列和值,这些列和值是通过命令更新的行计算得出的。
当存在 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');
更新 accounts 表中的联系人姓名,使其与当前分配的销售人员相匹配
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 条目没有匹配项,则第一个查询会将相应的 name 字段设置为 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以防止多个命令更新同一行。但是,然后需要一个没有 SKIP LOCKED 或 LIMIT 的最终 UPDATE,以确保不会遗漏任何匹配的行。
此命令符合SQL标准,但 FROM 和 RETURNING 子句是 PostgreSQL 扩展,就像 UPDATE 可以使用 WITH 一样。
一些其他数据库系统提供了一个 FROM 选项,其中目标表应该在 FROM 中再次列出。这不是 PostgreSQL 解释 FROM 的方式。在移植使用此扩展的应用程序时请小心。
根据标准,目标列名带括号的子列表的源值可以是产生正确列数的任何行值表达式。PostgreSQL 只允许源值为行构造函数或子 SELECT。在行构造函数的情况下,可以将单个列的更新值指定为 DEFAULT,但在子 SELECT 中则不能指定。
如果您在文档中看到任何不正确、与您使用特定功能的经验不符或需要进一步澄清的内容,请使用此表单报告文档问题。