#UPDATE

# 通用描述

UPDATE用于更新数据库的表或视图的基表的数据。

对LSC表更新数据时,约束如下:

  • 不能对LSC表执行跨分区更新。
  • 不能对AC执行UPDATE操作。
  • 更新LSC表冷数据的数据,需要开启ROW MOVEMENT。

基于视图对其基表更新数据时,约束如下:

  • 不适用于分布式部署。
  • 目标视图需满足如下条件:
    • 视图的所有基表均为HEAP表,且视图不包含分组、聚合、去重、ROWNUM或CONNECT BY操作。
    • 视图中来自同一个基表的数据ROWID唯一。
    • 多基表视图中,要求某个基表存在列与其他所有基表的主键约束或唯一约束列都具备等值连接条件,才能基于视图UPDATE该表数据。
  • UPDATE的列必须对应基表的列(不能是其他表达式类型)。

默认情况下,在UPDATE的事务(Transaction)被提交(Commit)前,其他会话无法查询到被更新的数据,可以按需开启自动提交(SET AUTOCOMMIT ON)使其他会话也能及时查询到新数据。

对于被子表定义了外键约束的父表,如果要被更新的列字段为该外键项且其数据值已在子表中存在,则无法更新该父表中的此项数据。

# 语句定义

update::=

syntax
UPDATE hint dml_table_expression_clause t_alias update_set_clause WHERE condition

table_reference::=

syntax
schema . table_name dblink partition_extension_clause view_name

partition_extension_clause::=

syntax
PARTITION ( partition ) FOR ( partition_key_value , ) SUBPARTITION ( subpartition ) FOR ( subpartition_key_value , )

update_set_clause::=

syntax
SET column = expr DEFAULT ( subquery ) ( column , ) = ( expr DEFAULT ( subquery ) , ) ,

# hint

该语句用于提出给定的方案到优化器(Optimizer ),使其按照此方案生成语句的执行计划。查看hint说明

# table_reference

该语句用于指定要更新数据的对象,可以为表名称(包括本地数据库的表或远端表)、表分区名称或视图名称,可对其指定一个别名。

对于分区表,如未显式指定分区对象,由系统根据分区项字段的值判断要更新的表分区。在显式指定且表未被定义为ENABLE ROW MOVEMENT时:

  • 当分区表类型为RANGE时,如更新该表的分区项字段,请注意不要超出其所在分区的界值,否则会更新失败并提示错误。
  • 当分区表类型为LIST时,如更新该表的分区项字段,请注意数据值在其所在分区的列表项中,否则会更新失败并提示错误。

对于分布式部署中的分布表,不允许修改其分区键字段的值。

示例1(单机/共享集群部署)

SELECT year,month,branch,product,quantity,amount,salsperson FROM sales_info_range PARTITION (p_sales_info_range_1);
YEAR  MONTH BRANCH PRODUCT                QUANTITY                AMOUNT SALSPERSON  
----- ----- ------ --------- --------------------- --------------------- -------------
2001  01    0201   11001                        30                   500 0201010011 
2000  12    0102   11001                        20                   300       

-- 要更新数据的此行记录位于sales_info_range 表的p_sales_info_range_1分区,其界值为'2011',对year字段的超出界值更新将会失败
UPDATE sales_info_range PARTITION (p_sales_info_range_1) SET year='2023' WHERE year='2001';
YAS-02209 ROW MOVEMENT is not enabled

-- 未指定分区时,按分区项判断更新值不在当前分区列表中,更新数据失败
UPDATE sales_info_list SET year='2021' WHERE year='2018';
YAS-02209 ROW MOVEMENT is not enabled
  
-- 指定分区时,按分区项判断其原值和更新值均在指定分区,更新数据成功
UPDATE sales_info_list PARTITION (p_sales_info_list_1) SET year='2019' WHERE year='2018';
SELECT year,month,branch,product,quantity,amount,salsperson FROM sales_info_list PARTITION (p_sales_info_list_1);
YEAR  MONTH BRANCH PRODUCT                QUANTITY                AMOUNT SALSPERSON  
----- ----- ------ --------- --------------------- --------------------- -------------
2019  10    0101   11001                        20                   300

示例2(分布式部署)

--sales_info_range为一张范围分区表,该表以branch字段作为分区键,对分布表的分区键执行update将失败
UPDATE sales_info_range SET branch='0101' WHERE branch='0201';
YAS-04510 cannot update partitioning column for sharded table

# partition_extension_clause

INSERT语句中partition_extension_clause的描述一致。

# update_set_clause

该语句用于指定要更新数据的列字段,并对其赋值。

对于UDT列字段,通过对象初始化方法赋值,详见用户自定义类型中描述。

YashanDB支持通过两种方式更新多个列字段:

方式一:UPDATE table_name SET column = value, column = value;

方式二:UPDATE table_name SET (column,...,column) = (value,...value);

YashanDB支持按如下语句对列字段赋值:

  • expr表达式
  • 子查询
  • DEFAULT

当上述语句的结果与列字段定义的数据类型不一致时,系统会先进行数据类型转换,转换失败则返回错误。

使用方式二更新多个列字段有如下约束限制:

  • 括号内指定的列字段需位于同一张表,否则返回错误。
  • 除对所有指定列字段均赋值为DEFAULT情况外,其他情况下值的数量需与列字段数量相同。
  • value中不允许同时出现子查询和表达式。

示例

--在area表中插入数据
INSERT INTO area VALUES ('09','Other','Shanghai1');
  
--更新多个列字段(方式一)
UPDATE area SET area_name=23*67,DHQ='Shanghai1' WHERE area_no='09';
  
--result 
SELECT area_no,area_name,DHQ FROM area WHERE area_no='09';
AREA_NO AREA_NAME      DHQ        
------- -------------- ------------
09      1541           Shanghai1

--更新多个列字段(方式二)
UPDATE area SET (area_name,DHQ) = ('华西','Shanxi') WHERE area_no='09';

其中,当使用子查询对列字段赋值时,更新的列字段须与子查询返回的列项必须按顺序一一对应,且子查询的返回结果不能为多条。如子查询无返回结果,将以NULL值返回,此时如对应的列存在非空约束,则更新数据失败。

示例

--将上述示例插入记录的DHQ更新为'Shanghai2'
UPDATE area SET DHQ='Shanghai2' WHERE area_no='09';
  
--在area表中未检索到DHQ='Shanghai1'的记录,以NULL值对DHQ字段进行更新触发非空约束错误
UPDATE area SET DHQ = (SELECT a.DHQ FROM area a WHERE a.DHQ='Shanghai1') WHERE area_no='09';
YAS-04006 cannot insert NULL value to column DHQ
  
--子查询返回多行记录,更新提示错误
UPDATE area SET DHQ = (SELECT a.DHQ FROM area a WHERE a.DHQ LIKE 'Shanghai%') WHERE area_no='09';
[1:24]YAS-04402 query expression return multiple rows

当使用DEFAULT对列字段赋值时,如对应的列上已定义了DEFAULT值,则更新的数据为该DEFAULT值,否则为NULL,基于这个规则,如对应的列存在非空约束,则更新数据失败。

示例

--area表上的DHQ字段已定义了DEFAULT值'ShenZhen',则按此值更新数据成功
UPDATE area SET DHQ=DEFAULT WHERE area_no='09';
  
--branches表上的BRANCH_NAME字段非空且无DEFAULT值,则按NULL值更新数据失败
UPDATE branches SET branch_name=DEFAULT WHERE branch_no='0201';
YAS-04006 cannot insert NULL value to column BRANCH_NAME

# where condition

该语句用于指定condition,按此条件过滤出的记录行被执行更新操作。可省略,则表示更新表的所有行。