UPDATE

UPDATE —更新表的行

Synopsis

[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ]
    SET { column_name = { expression | DEFAULT } |
          ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
          ( column_name [, ...] ) = ( sub-SELECT )
        } [, ...]
    [ FROM from_item [, ...] ]
    [ WHERE condition | WHERE CURRENT OF cursor_name ]
    [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

Description

UPDATE更改所有满足条件的行中指定列的值。 SET子句中仅需提及要修改的列;未显式修改的列将保留其先前的值。

有两种方法可以使用数据库中其他表中包含的信息来修改表:使用子选择,或在FROM子句中指定其他表。哪种技术更合适取决于具体情况。

可选的RETURNING子句使UPDATE根据实际更新的每一行计算并返回值。可以计算使用表的列和/或FROM中提到的其他表的列的任何表达式。使用表列的新(更新后)值。 RETURNING列表的语法与SELECT的输出列表的语法相同。

您必须在表上或至少在要更新的列上具有UPDATE特权。您还必须对在* expressions condition *中读取其值的任何列具有SELECT特权。

Parameters

  • with_query

    • WITH子句允许您指定一个或多个子查询,这些子查询可以在UPDATE查询中按名称引用。有关详情,请参见Section 7.8SELECT
  • 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条件中并更新表达式。它使用与SELECT语句的FROM Clause相同的语法;例如,可以指定表名的别名。除非打算使用自联接,否则不要将目标表重复为* 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

    • 用于返回的列的名称。

Outputs

成功完成后,UPDATE命令将返回以下形式的命令标签:

UPDATE count
  • count 是已更新的行数,包括其值未更改的匹配行。请注意,当通过BEFORE UPDATE触发器抑制更新时,该数目可能小于与 condition 匹配的行数。如果 count *为 0,则查询没有更新任何行(这不视为错误)。

如果UPDATE命令包含RETURNING子句,则结果将类似于SELECT语句的结果,该语句包含在RETURNING列表中定义的列和值,并通过该命令更新的行进行计算。

Notes

当存在FROM子句时,本质上是将目标表连接到* from_item *列表中提到的表,并且连接的每个输出行都代表目标表的更新操作。使用FROM时,应确保该联接为要修改的每一行最多产生一个输出行。换句话说,目标行不应与其他表中的行合并。如果是这样,那么将仅使用联接行之一来更新目标行,但是将很难预测将使用哪一行。

由于存在这种不确定性,因此仅在子选择内引用其他表更为安全,尽管与使用联接相比,通常更难阅读且速度较慢。

对于分区表,更新行可能导致其不再满足所在分区的分区约束。在这种情况下,如果分区树中存在该行满足其分区约束的其他分区,则该行将移至该分区。如果没有这样的分区,将发生错误。在幕后,行移动实际上是DELETEINSERT操作。

被移动的行上并发的UPDATEDELETE可能会出现序列化失败错误。假设会话 1 在分区键上执行UPDATE,同时可见该行的并发会话 2 在该行上执行UPDATEDELETE操作。在这种情况下,会话 2 的UPDATEDELETE将检测到行移动并引发序列化失败错误(该错误始终返回 SQLSTATE 代码'40001')。如果发生这种情况,应用程序可能希望重试该事务。在表未分区或没有行移动的通常情况下,会话 2 将识别出新近更新的行并对该新行版本执行UPDATE/DELETE

请注意,虽然可以将行从本地分区移动到外部表分区(前提是外部数据包装程序支持 Tuples 路由),但是不能将行从外部表分区移动到另一个分区。

Examples

在表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子句语法,增加 ManagementAcme 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');

更新 Client 表中的联系人姓名以匹配当前分配的销售员:

UPDATE accounts SET (contact_first_name, contact_last_name) =
    (SELECT first_name, last_name FROM salesmen
     WHERE salesmen.id = accounts.sales_id);

通过联接可以实现类似的结果:

UPDATE accounts SET contact_first_name = first_name,
                    contact_last_name = last_name
  FROM salesmen WHERE salesmen.id = accounts.sales_id;

但是,如果salesmen,则第二个查询可能会给出意外结果。 id不是唯一键,但是如果有多个id匹配项,则保证第一个查询会引发错误。另外,如果没有匹配特定的accountssales_id条目,第一个查询会将相应的名称字段设置为 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当前所在的行中更改表filmskind列:

UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_films;

Compatibility

该命令符合 SQL 标准,除了FROMRETURNING子句是 PostgreSQL 扩展,以及将WITHUPDATE结合使用的能力。

其他一些数据库系统提供了FROM选项,其中应该在FROM内再次列出目标表。 PostgreSQL 不会这样解释FROM。移植使用此 extensions 的应用程序时请小心。

根据标准,目标列名称的带括号的子列表的源值可以是产生正确列数的任何行值表达式。 PostgreSQL 仅允许源值是row constructor或子SELECT。在行构造器的情况下,可以将单个列的更新值指定为DEFAULT,但不能在子SELECT内指定。