
# UPDATE
#### 功能描述
更新表中的数据，UPDATE修改满足条件的所有行中指定的字段值，WHERE子句声明条件，SET子句指定的字段会被修改，没有出现的字段则保持它们的原值。
#### 注意事项
- 表的所有者、拥有表UPDATE权限的用户或拥有UPDATE ANY TABLE权限的用户，有权更新表中的数据，系统管理员默认拥有此权限。
- 对expression或condition条件里涉及到的任何表要有SELECT权限。
- 生成列不能被直接写入。在UPDATE命令中不能为生成列指定值，但是可以指定关键字DEFAULT。
- 对于多表更新语法，暂时不支持对视图和含有RULE的表进行多表更新。
- 对于子查询是stream计划的UPDATE语句，不支持并发更新同一行。
- 不支持用户通过update系统表的方式将数据库编码更改为GB18030_2022字符集或将GB18030_2022字符集数据库更改为其他字符编码，进行更改数据库字符编码的操作会导致存量数据和部分操作异常。若需更改数据库的字符集编码，应当遵循切库流程，进行相关的数据迁移操作。
 
#### 语法格式
```
单表更新：
[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [/*+ plan_hint */] [ ONLY ] table_name [ partition_clause ] [ * ] [ [ AS ] alias ]
SET {column_name = { expression | DEFAULT } 
    |( column_name [, ...] ) = {( { expression | DEFAULT } [, ...] ) |sub_query }}[, ...]
    [ FROM from_list] [ WHERE condition | WHERE CURRENT OF cursor_name ]
    [ ORDER BY {expression [ [ ASC | DESC | USING operator ]
    [ LIMIT { count } ]
    [ RETURNING {* 
                | {output_expression [ [ AS ] output_name ]} [, ...] }];
多表更新：
[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [/*+ plan_hint */] table_list
SET {column_name = { expression | DEFAULT } 
    |( column_name [, ...] ) = {( { expression | DEFAULT } [, ...] ) |sub_query }}[, ...]
    [ FROM from_list] [ WHERE condition ];
where sub_query can be:
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
{ * | {expression [ [ AS ] output_name ]} [, ...] }
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
[ HAVING condition [, ...] ]
[ ORDER BY {expression [ [ ASC | DESC | USING operator ] | nlssort_expression_clause ] [ NULLS { FIRST | LAST } ]} [, ...] ]
[ LIMIT { [offset,] count | ALL } ]
```
- 其中子查询with_query为：
  ```
  with_query_name [ ( column_name [, ...] ) ]
      AS [ [ NOT ] MATERIALIZED ] ( {select | values | insert | update | delete} )
  ```
  
#### 参数说明
- **WITH \[ RECURSIVE \] with_query \[, ...\]**
  用于声明一个或多个可以在主查询中通过名称引用的子查询，相当于临时表。这种子查询语句结构称为CTE（Common Table Expression）结构，应用这种结构时，执行计划中将存在CTE SCAN的内容。
  如果声明了RECURSIVE，那么允许SELECT子查询通过名称引用它自己。
  其中with_query的详细格式为：
  ```
  with_query_name [ ( column_name [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( {select | values | insert | update | delete} )
  ```
  - with_query_name指定子查询生成的结果集名称，在查询中可使用该名称访问子查询的结果集。
  
  - column_name指定子查询结果集中显示的列名。
  
  - 每个子查询可以是SELECT、VALUES、INSERT、UPDATE或DELETE语句。
  
  - 用户可以使用MATERIALIZED / NOT MATERIALIZED对CTE进行修饰。
    - 如果声明为MATERIALIZED，WITH查询将被物化，生成一个子查询结果集的拷贝，在引用处直接查询该拷贝，因此WITH子查询无法和主干SELECT语句进行联合优化（如谓词下推、等价类传递等），对于此类场景可以使用NOT MATERIALIZED进行修饰，如果WITH查询语义上可以作为子查询内联执行，则可以进行上述优化。
    
    - 如果用户没有显示声明物化属性则遵守以下规则：如果CTE只在所属SELECT主干中被引用一次，且语义上支持内联执行，则会被改写为子查询内联执行，否则以CTE Scan的方式物化执行。
     
   

- **plan_hint子句**
  以/\*+ \*/的形式在UPDATE关键字后，用于对UPDATE对应的语句块生成的计划进行hint调优，详细用法请参见章节[使用Plan Hint进行调优](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/gaussdb-42-0292.html#ZH-CN_TOPIC_0000002200578674)。每条语句中只有第一个/\*+ plan_hint \*/注释块会作为hint生效，里面可以写多条hint。
  
- **table_name**
  要更新的表名，可以使用模式修饰。
  取值范围：已存在的表名称。
  ![](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
  支持使用DATABASE LINK方式对远端表进行操作，使用方式详情请见[DATABASE LINK](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/gaussdb-42-0679.html#ZH-CN_TOPIC_0000002200579378)。
  
- **partition_clause**
  指定分区更新操作
  PARTITION { ( partition_name ) \| FOR ( partition_value \[, ...\] ) } \|
  SUBPARTITION { ( subpartition_name ) \| FOR ( subpartition_value \[, ...\] ) }
  关键字详见[SELECT](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/gaussdb-42-0649.html#ZH-CN_TOPIC_0000002200419502)一节介绍
  示例详见[CREATE TABLE SUBPARTITION](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/gaussdb-42-0561.html#ZH-CN_TOPIC_0000002200579098)
  
- **alias**
  目标表的别名。
  取值范围：字符串，符合[标识符命名规范](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/gaussdb-42-0327.html#ZH-CN_TOPIC_0000002235339153__zh-cn_topic_0000002235101877_section1257443811315)。
  
- **table_list**
  一个表的表达式列表，与from_list类似，但可以同时声明目标表和关联表，仅在多表更新语法中使用。
  
- **column_name**
  要修改的字段名。
  支持使用目标表的别名加字段名来引用这个字段。例如：
  UPDATE foo AS f SET f.col_name = 'namecol';
  取值范围：已存在的字段名。
  
- **expression**
  赋给字段的值或表达式。
  
- **DEFAULT**
  用对应字段的缺省值填充该字段。
  如果没有缺省值，则为NULL。
  
- **sub_query**
  子查询。
  使用同一数据库里其他表的信息来更新一个表可以使用子查询的方法。其中SELECT子句具体介绍请参考[SELECT](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/gaussdb-42-0649.html#ZH-CN_TOPIC_0000002200419502)。
  在UPDATE单列时，支持使用ORDER BY子句与LIMIT子句；而在UPDATE多列时，则不支持使用ORDER BY子句与LIMIT子句。
  ![](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
  对于UPDATE t1 SET (c1,c2) = (SELECT c1, c2 FROM t2 ...)形式的UPDATE语句，在执行计划中，对于每一个字段，会生成一个子计划。当更新字段数较多时，子计划数量较多，对性能影响较大。
  
- **from_list**
  一个表的表达式列表，允许在WHERE条件里使用其他表的字段。与在一个SELECT语句的FROM子句里声明表列表类似。
  ![](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/public_sys-resources/notice_3.0-zh-cn.png)
  目标表不能出现在from_list里，除非在使用一个自连接（此时它必须以from_list的别名出现）。
  
- **condition**
  一个返回Boolean类型结果的表达式。只有这个表达式返回true的行才会被更新。不建议使用int等数值类型作为condition，因为int等数值类型可以隐式转换为Boolean值（非0值隐式转换为true，0转换为false），可能导致非预期的结果。
  
- **WHERE CURRENT OF cursor_name**
  当cursor指向表的某一行时，可以使用此语法更新cursor当前指向的行。
  cursor_name：指定游标的名称。
  ![](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/public_sys-resources/notice_3.0-zh-cn.png)
  - B兼容模式的数据库不支持使用此语法。
  
  - 此语法仅支持普通表，不支持分区表。
  
  - 仅支持在存储过程中使用。
  
  - 不支持与其他WHERE条件组合使用。
  
  - 不支持多表更新。
  
  - 不支持与WITH、USING、ORDER BY、FROM组合使用。
  
  - CURSOR对应的SELECT语句必须声明为FOR UPDATE。
  
  - CURSOR对应的SELECT语句仅支持单表，不支持LIMIT/OFFSET，不支持带有子查询、子链接。
  
  - 存储过程中声明为FOR UPDATE的CURSOR，在COMMIT/ROLLBACK后，将无法再次使用。
  
  - 若CURSOR指向的行已经不存在，在A兼容性模式下将报错指定的行不存在（仅UPDATE时报错，DELETE不报错），其他兼容模式下不报错。
    
- ORDER BY子句 关键字详见[SELECT](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/gaussdb-42-0649.html#ZH-CN_TOPIC_0000002200419502)章节介绍。
  
- LIMIT子句 关键字详见[SELECT](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/gaussdb-42-0649.html#ZH-CN_TOPIC_0000002200419502)章节介绍。
  
- **output_expression**
  在所有需要更新的行都被更新之后，UPDATE命令用于计算返回值的表达式。
  取值范围：使用任何TABLE以及FROM中列出的表的字段。\*表示返回所有字段。
  
- **output_name**
  字段的返回名称。
  
 
#### 示例
```
--创建表student1。
gaussdb=# CREATE TABLE student1
gaussdb=#(
gaussdb=#   stuno     int,
gaussdb=#   classno   int 
gaussdb=#);
--插入数据。
gaussdb=# INSERT INTO student1 VALUES(1,1);
gaussdb=# INSERT INTO student1 VALUES(2,2);
gaussdb=# INSERT INTO student1 VALUES(3,3);
--查看数据。
gaussdb=# SELECT * FROM student1;
--直接更新所有记录的值。
gaussdb=# UPDATE student1 SET classno = classno*2;
--查看数据。
gaussdb=# SELECT * FROM student1;
--删除表。
gaussdb=# DROP TABLE student1;
--WHERE CURRENT OF cursor_name用例
gaussdb=# CREATE TABLE t1(c1 int, c2 varchar2) WITH (storage_type = 'ustore', fillfactor=100); -- 创建表
gaussdb=# INSERT INTO t1 VALUES(generate_series(1,1000),'abcd'); -- 插入数据
gaussdb=# DECLARE
gaussdb-# CURSOR cur1 IS SELECT * FROM t1 WHERE c1 = 1 FOR UPDATE;
gaussdb-# va t1%rowtype;
gaussdb-# BEGIN
gaussdb$# OPEN cur1;
gaussdb$# FETCH cur1 INTO va;
gaussdb$# UPDATE t1 SET c2 = c2 || c2  WHERE CURRENT OF cur1; -- 使用WHERE CURRENT OF cursor_name更新数据
gaussdb$# CLOSE cur1;
gaussdb$# COMMIT;
gaussdb$# END;
gaussdb$# /
gaussdb=# SELECT * FROM t1 WHERE c1 = 1; -- 查询数据
gaussdb=# DROP TABLE t1; --删除表
```
