UPDATE

UPDATE操作用于将Transactional表或Delta Table表中行对应的单列或多列数据更新为新值。

前提条件

执行deleteupdate操作前需要具备目标Transactional表的读取表数据权限(Select)及更新表数据权限(Update)。授权操作请参见MaxCompute权限

使用限制

  • DELETEUPDATE功能及对应Transactional表、Delta Table表的使用限制如下:

    说明

    关于Transaction表和Delta Table表详细信息,详情请参见Transaction TableDelta Table表参数

    • Delta TableUPDATE语法不支持修改PK列。

注意事项

通过DELETEUPDATE操作删除或更新表或分区内的数据时,注意事项如下:

  • 如果需要对表中较少数据进行删除或更新操作,且操作和后续读数据的频率也不频繁,建议使用DELETEUPDATE操作,并且在多次执行删除或更新操作之后,请合并表的Base文件和Delta文件,降低表的实际存储。更多信息,请参见合并Transactional表文件

  • 如果删除或更新行数较多(超过5%)并且操作不频繁,但后续对该表的读操作比较频繁,建议使用INSERT OVERWRITEINSERT INTO操作。更多信息,请参见插入或覆写数据(INSERT INTO | INSERT OVERWRITE)

    例如,某业务场景为每次删除或更新10%的数据,一天更新10次。建议根据实际情况评估DELETEUPDATE操作产生的费用及后续对读性能的消耗是否小于每次使用INSERT OVERWRITEINSERT INTO操作产生的费用及后续对读性能的消耗,比较两种方式在具体场景中的效率,选择更优方案。

  • 删除数据会生成Delta文件,所以删除数据不一定能降低存储,如果您希望通过DELETE操作删除数据来降低存储,请合并表的Base文件和Delta文件,降低表的实际存储。更多信息,请参见合并Transactional表文件

  • MaxCompute会按照批处理方式执行DELETEUPDATE作业,每一条语句都会使用资源并产生费用,建议您使用批量方式删除或更新数据。例如您通过Python脚本生成并提交了大量行级别更新作业,且每条语句只操作一行或者少量行数据,则每条语句都会产生与SQL扫描输入数据量对应的费用,并使用相应的计算资源,多条语句累加时将明显增加费用成本,降低系统效率。命令示例如下。

    • 推荐方案:

      UPDATE table1 SET col1= (SELECT value1 FROM table2 WHERE table1.id = table2.id AND table1.region = table2.region);
    • 不推荐方案:

      UPDATE table1 SET col1=1 WHERE id='2021063001' AND region='beijing';                 
      UPDATE table1 SET col1=2 WHERE id='2021063002' AND region='beijing';

命令格式

--方式1
UPDATE <table_name> [[AS] alias] SET <col1_name> = <value1> [, <col2_name> = <value2> ...] [WHERE <where_condition>];

--方式2
UPDATE <table_name> [[AS] alias] SET (<col1_name> [, <col2_name> ...]) = (<value1> [, <value2> ...]) [WHERE <where_condition>];

--方式3
UPDATE <table_name> [[AS] alias]
    SET <col1_name> = <value1> [, <col2_name> = <value2>, ...]
    [FROM <additional_tables>]
    [WHERE <where_condition>];

参数说明

  • table_name:必填。待执行UPDATE操作的Transactional表或Delta Table表名称。

  • alias:可选。表别名。

  • col1_namecol2_name:必填。至少更新一个。待修改行对应的列名称。

  • value1value2:必填。至少更新一个列值。修改后的新值。

  • where_condition:可选。WHERE子句,用于筛选满足条件的数据。更多WHERE子句信息,请参见SELECT语法。如果不带WHERE子句,会更新表中的所有数据。

  • additional_tables:可选。FROM子句。

    UPDATE支持FROM子句,使用FROM子句时,UPDATE的使用会更加方便,不使用FROM子句与使用FROM子句的对比示例如下。

    场景

    示例代码

    不使用FROM子句

    UPDATE target SET v = 
      (SELECT MIN(v) FROM src GROUP BY k WHERE target.k = src.key)
      WHERE target.k IN (SELECT k FROM src);

    使用FROM子句

    UPDATE target SET v = b.v
      FROM (SELECT k, MIN(v) AS v FROM src GROUP BY k) b
      WHERE target.k = b.k;

    从上述示例代码可见:

    • 当用源表的多行数据更新目标表的一行数据的时,由于不知道用哪条源表的数据去更新,所以遇到这种情况需要用户写聚合操作来保证数据源的unique性,可以看出不使用FROM子句时代码不够简洁,使用FROM子句的写法比较简洁易懂。

    • 关联更新的时候,如果只更新交集数据,不使用FROM子句时需要写额外的where条件,相对于FROM语法而言也不太简洁。

使用示例

  • 示例1:创建非分区表acid_update,并导入数据,执行UPDATE操作更新满足指定条件的行对应的列数据。命令示例如下:

    --创建Transactionalacid_update。  
    CREATE TABLE IF  NOT EXISTS acid_update(id BIGINT) tblproperties ("transactional"="true");
    
    --插入数据。
    INSERT OVERWRITE TABLE acid_update VALUES(1),(2),(3),(2);
    
    --查看插入结果。
    SELECT * FROM acid_update; 
    
    --返回结果
    +------------+
    | id         |
    +------------+
    | 1          |
    | 2          |
    | 3          |
    | 2          |
    +------------+
    
    --将所有id2的行,id值更新为4。
    UPDATE acid_update SET id = 4 WHERE id = 2; 
    
    --查看更新结果,2被更新为4。
    SELECT * FROM acid_update; 
    
    --返回结果
    +------------+
    | id         |
    +------------+
    | 1          |
    | 3          |
    | 4          |
    | 4          |
    +------------+
  • 示例2:创建分区表acid_update,并导入数据,执行UPDATE操作更新满足指定条件的行对应的列数据。命令示例如下:

    --创建Transactionalacid_update_pt。 
    CREATE TABLE IF  NOT EXISTS acid_update_pt(id BIGINT) PARTITIONED BY(ds STRING) tblproperties ("transactional"="true");
    
    --添加分区。
    ALTER TABLE acid_update_pt ADD IF  NOT EXISTS PARTITION (ds= '2019');
    
    --插入数据。
    INSERT OVERWRITE TABLE acid_update_pt PARTITION (ds='2019') VALUES(1),(2),(3);
    
    --查看插入结果
    SELECT * FROM acid_update_pt WHERE ds = '2019'; 
    
    --返回结果
    +------------+------------+
    | id         | ds         |
    +------------+------------+
    | 1          | 2019       |
    | 2          | 2019       |
    | 3          | 2019       |
    +------------+------------+
    
    --更新指定行的一列数据,将分区为2019的所有id=2的行,id值更新为4。
    UPDATE acid_update_pt SET id = 4 WHERE ds = '2019' AND id = 2; 
    
    --查看更新结果,2被更新为4。
    SELECT * FROM acid_update_pt WHERE ds = '2019';
    
    --返回结果
    +------------+------------+
    | id         | ds         |
    +------------+------------+
    | 4          | 2019       |
    | 1          | 2019       |
    | 3          | 2019       |
    +------------+------------+
  • 示例3:创建目标表acid_update_t和关联表acid_update_s,实现同时更新多列值。命令示例如下:

    --创建待更新目标Transactionalacid_update_t和关联表acid_update_s。
    CREATE TABLE IF  NOT EXISTS acid_update_t(id INT,value1 INT,value2 INT) tblproperties ("transactional"="true");
    CREATE TABLE IF  NOT EXISTS acid_update_s(id INT,value1 INT,value2 INT); 
    
    --插入数据。
    INSERT OVERWRITE TABLE acid_update_t VALUES(2,20,21),(3,30,31),(4,40,41);
    INSERT OVERWRITE TABLE acid_update_s VALUES(1,100,101),(2,200,201),(3,300,301);
    
    --方式一:用常量更新。
    UPDATE acid_update_t SET (value1, value2) = (60,61);
    --查询方式一目标表结果数据。
    SELECT * FROM acid_update_t;
    
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 2          | 60         | 61         |
    | 3          | 60         | 61         |
    | 4          | 60         | 61         |
    +------------+------------+------------+
    
    --方式二:关联更新,规则为acid_update_t表左关联acid_update_s表。
    UPDATE acid_update_t SET (value1, value2) = (SELECT value1, value2 FROM acid_update_s WHERE acid_update_t.id = acid_update_s.id);
    --查询方式二目标表结果数据。
    SELECT * FROM acid_update_t;
    
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 2          | 200        | 201        |
    | 3          | 300        | 301        |
    | 4          | NULL       | NULL       |
    +------------+------------+------------+
    
    --方式三(基于“方式二”的结果进行更新):关联更新,规则为增加过滤条件,只更新交集。
    UPDATE acid_update_t SET (value1, value2) = (SELECT value1, value2 FROM acid_update_s WHERE acid_update_t.id = acid_update_s.id) WHERE acid_update_t.id IN (SELECT id FROM acid_update_s);
    --查询方式三目标表结果数据。
    SELECT * FROM acid_update_t;
    
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 2          | 200        | 201        |
    | 3          | 300        | 301        |
    | 4          | NULL       | NULL       |
    +------------+------------+------------+
    
    --方式四(基于“方式三”的结果进行更新):用汇总结果关联更新。
    UPDATE acid_update_t SET (id, value1, value2) = (SELECT id, MAX(value1),MAX(value2) FROM acid_update_s WHERE acid_update_t.id = acid_update_s.id GROUP BY acid_update_s.id) WHERE acid_update_t.id IN (SELECT id FROM acid_update_s);
    --查询方式四目标表结果数据。
    SELECT * FROM acid_update_t;
    
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 2          | 200        | 201        |
    | 3          | 300        | 301        |
    | 4          | NULL       | NULL       |
    +------------+------------+------------+
  • 示例4:涉及两个表的简单关联查询,示例命令如下:

    --创建更新目标表acid_update_t和关联表acid_update_s 
    CREATE TABLE IF  NOT EXISTS acid_update_t(id BIGINT,value1 BIGINT,value2 BIGINT) tblproperties ("transactional"="true");
    CREATE TABLE IF  NOT EXISTS acid_update_s(id BIGINT,value1 BIGINT,value2 BIGINT);
    
    --插入数据
    INSERT OVERWRITE TABLE acid_update_t VALUES(2,20,21),(3,30,31),(4,40,41);
    INSERT OVERWRITE TABLE acid_update_s VALUES(1,100,101),(2,200,201),(3,300,301);
    
    --查询acid_update_t表数据
    SELECT * FROM acid_update_t;
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 2          | 20         | 21         |
    | 3          | 30         | 31         |
    | 4          | 40         | 41         |
    +------------+------------+------------+
    
    --查询acid_update_s表数据
    SELECT * FROM acid_update_s;
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 1          | 100        | 101        |
    | 2          | 200        | 201        |
    | 3          | 300        | 301        |
    +------------+------------+------------+
    
    --关联更新,目标表增加过滤条件,只取交集
    UPDATE acid_update_t SET value1 = b.value1, value2 = b.value2
    FROM acid_update_s b WHERE acid_update_t.id = b.id;
    -- 等价于上面写法
    UPDATE acid_update_t a SET a.value1 = b.value1, a.value2 = b.value2 
    FROM acid_update_s b WHERE a.id = b.id;
    
    --查看更新结果,20被更新为200,21被更新为201,30被更新为300,31被更新为301
    SELECT * FROM acid_update_t;
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 4          | 40         | 41         |
    | 2          | 200        | 201        |
    | 3          | 300        | 301        |
    +------------+------------+------------+                          
  • 示例5:涉及多个表的复杂关联查询,示例命令如下:

    --创建更新目标表acid_update_t和关联表acid_update_s 
    CREATE TABLE IF  NOT EXISTS acid_update_t(id BIGINT,value1 BIGINT,value2 BIGINT) tblproperties ("transactional"="true");
    CREATE TABLE IF  NOT EXISTS acid_update_s(id BIGINT,value1 BIGINT,value2 BIGINT);
    CREATE TABLE IF  NOT EXISTS acid_update_m(id BIGINT,value1 BIGINT,value2 BIGINT);
    
    --插入数据
    INSERT OVERWRITE TABLE acid_update_t VALUES(2,20,21),(3,30,31),(4,40,41),(5,50,51);
    INSERT OVERWRITE TABLE acid_update_s VALUES (1,100,101),(2,200,201),(3,300,301),(4,400,401),(5,500,501);
    INSERT OVERWRITE TABLE acid_update_m VALUES(3,30,101),(4,400,201),(5,300,301);
    
    --查询acid_update_t表数据
    SELECT * FROM acid_update_t;
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 2          | 20         | 21         |
    | 3          | 30         | 31         |
    | 4          | 40         | 41         |
    | 5          | 50         | 51         |
    +------------+------------+------------+
    
    --查询acid_update_s表数据
    SELECT * FROM acid_update_s;
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 1          | 100        | 101        |
    | 2          | 200        | 201        |
    | 3          | 300        | 301        |
    | 4          | 400        | 401        |
    | 5          | 500        | 501        |
    +------------+------------+------------+
    
    --查询acid_update_m表数据
    SELECT * FROM acid_update_m;
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 3          | 30         | 101        |
    | 4          | 400        | 201        |
    | 5          | 300        | 301        |
    +------------+------------+------------+
    
    --关联更新,并且在where中同时对原表和目标表进行过滤
    UPDATE acid_update_t 
    SET value1 = acid_update_s.value1, value2 = acid_update_s.value2 
    FROM acid_update_s 
    WHERE acid_update_t.id = acid_update_s.id 
    AND acid_update_s.id > 2 
    AND acid_update_t.value1 NOT IN 
    (SELECT value1 FROM acid_update_m WHERE id = acid_update_t.id) 
    AND acid_update_s.value1 NOT IN 
    (SELECT value1 FROM acid_update_m WHERE id = acid_update_s.id);
    
    --查看更新结果,acid_update_t表只有id5的数据符合条件,对应value1被更新为500,valu2被更新为501
    SELECT * FROM acid_update_t;
    --返回结果
    +------------+------------+------------+
    | id         | value1     | value2     |
    +------------+------------+------------+
    | 5          | 500        | 501        |
    | 2          | 20         | 21         |
    | 3          | 30         | 31         |
    | 4          | 40         | 41         |
    +------------+------------+------------+
  • 示例6:创建Delta Tablemf_dt,并导入数据,执行UPDATE操作删除满足指定条件的行。命令示例如下:

    --创建目标Delta Tablemf_dt。
    CREATE TABLE IF  NOT EXISTS mf_dt (pk BIGINT  NOT NULL PRIMARY KEY, 
                      val  BIGINT NOT NULL) 
                      PARTITIONED BY(dd STRING, hh STRING) 
                      tblproperties ("transactional"="true");
    
    --插入数据
    INSERT OVERWRITE TABLE mf_dt PARTITION (dd='01', hh='02') 
                     VALUES (1, 1), (2, 2), (3, 3);
    
    --查看插入结果                 
    SELECT * FROM mf_dt WHERE dd='01' AND hh='02';
    --返回结果
    +------------+------------+----+----+
    | pk         | val        | dd | hh |
    +------------+------------+----+----+
    | 1          | 1          | 01 | 02 |
    | 3          | 3          | 01 | 02 |
    | 2          | 2          | 01 | 02 |
    +------------+------------+----+----+
    
    --更新指定行的一列数据,将分区为0102的所有pk=3的行,val值更新为30。
    --方法一
    UPDATE mf_dt SET val = 30 WHERE pk = 3 AND dd='01' AND hh='02';
    
    --方法二
    UPDATE mf_dt SET val = delta.val 
                  FROM (SELECT pk, val FROM VALUES (3, 30) t (pk, val)) delta 
                  WHERE delta.pk = mf_dt.pk AND mf_dt.dd='01' AND mf_dt.hh='02';
    
    --查看更新结果。
    SELECT * FROM mf_dt WHERE dd='01' AND hh='02';
    --返回结果,pk=3的行val值被更新为30。
    +------------+------------+----+----+
    | pk         | val        | dd | hh |
    +------------+------------+----+----+
    | 1          | 1          | 01 | 02 |
    | 3          | 30         | 01 | 02 |
    | 2          | 2          | 01 | 02 |
    +------------+------------+----+----+

相关命令

  • DELETE:用于删除Transactional分区表或非分区表中满足指定条件的单行或多行数据。

  • ALTER TABLE:合并Transactional表文件。