當您需要對Transactional表或Transaction Table2.0表執行insert
、update
、delete
操作時,可以通過merge into
功能將這些操作合并為一條SQL語句,根據與源表關聯的結果,對目標Transactional表執行插入、更新或刪除操作,只需要進行一次全表掃描操作,以提高執行效率。
前提條件
執行merge into
操作前需要具備目標Transactional表的讀取表資料許可權(Select)及更新表資料許可權(Update)。授權操作請參見MaxCompute許可權。
功能介紹
MaxCompute支援了delete
、update
功能,但當您需要使用多個insert
、update
、delete
對目標表進行大量操作時,需要編寫多條SQL語句,然後進行多次全表掃描才能完成操作。MaxCompute提供的merge into
功能,只需要進行一次全表掃描操作,就可以完成全部操作,執行效率要高於insert
+update
+delete
。
merge into
操作具備原子性,作業中的insert
、update
、delete
操作都執行成功時,作業才算執行成功;任一內部邏輯處理失敗,則整體作業執行失敗。
同時,merge into
可以為您避免分別執行insert
、update
、delete
操作時,可能導致部分操作執行成功,部分操作執行失敗,其中成功部分無法回退的問題。
使用限制
不允許在同一條merge into
語句中對相同的行執行多次insert
或update
操作。
命令格式
merge into <target_table> as <alias_name_t> using <source expression|table_name> as <alias_name_s>
--從on開始對源表和目標表的資料進行關聯判斷。
on <boolean expression1>
--when matched…then指定on的結果為True的行為。多個when matched…then之間的資料無交集。
when matched [and <boolean expression2>] then update set <set_clause_list>
when matched [and <boolean expression3>] then delete
--when not matched…then指定on的結果為False的行為。
when not matched [and <boolean expression4>] then insert values <value_list>
target_table:必填。目標表名稱,必須是實際存在的表。
alias_name_t:必填。目標表的別名。
source expression|table_name:必填。關聯的源表名稱、視圖或子查詢。
alias_name_s:必填。關聯的源表、視圖或子查詢的別名。
boolean expression1:必填。BOOLEAN類型判斷條件,判斷結果必須為True或False。
boolean expression2、boolean expression3、boolean expression4:可選。
update
、delete
、insert
操作相應的BOOLEAN類型判斷條件。需要注意的是:當出現三個WHEN子句時,
update
、delete
、insert
都只能出現一次。如果
update
和delete
同時出現,出現在前的操作必須包括[and <boolean expression>]
。when not matched
只能出現在最後一個WHEN子句中,並且只支援insert
操作。
set_clause_list:當出現
update
操作時必填。待更新資料資訊。更多update
資訊,請參見更新資料(UPDATE)。value_list:當出現
insert
操作時必填。待插入資料資訊。更多values
資訊,請參見VALUES。
使用樣本
樣本1:建立目標表acid_address_book_base1及源表tmp_table1,並插入資料。執行
merge into
操作,對符合on
條件的資料用源表的資料對目標表進行更新操作,對不符合on
條件並且源表中滿足event_type為I的資料插入目標表。命令樣本如下:--建立目標表acid_address_book_base1。 create table if not exists acid_address_book_base1 (id bigint,first_name string,last_name string,phone string) partitioned by(year string, month string, day string, hour string) tblproperties ("transactional"="true"); --建立源表tmp_table1。 create table if not exists tmp_table1 (id bigint, first_name string, last_name string, phone string, _event_type_ string); --向目標表acid_address_book_base1插入測試資料。 insert overwrite table acid_address_book_base1 partition(year='2020', month='08', day='20', hour='16') values (4, 'nihaho', 'li', '222'), (5, 'tahao', 'ha', '333'), (7, 'djh', 'hahh', '555'); --查詢目標表的資料確認插入測試資料的操作結果。 set odps.sql.allow.fullscan=true; select * from acid_address_book_base1; +------------+------------+------------+------------+------------+------------+------------+------------+ | id | first_name | last_name | phone | year | month | day | hour | +------------+------------+------------+------------+------------+------------+------------+------------+ | 4 | nihaho | li | 222 | 2020 | 08 | 20 | 16 | | 5 | tahao | ha | 333 | 2020 | 08 | 20 | 16 | | 7 | djh | hahh | 555 | 2020 | 08 | 20 | 16 | +------------+------------+------------+------------+------------+------------+------------+------------+ --向源表tmp_table1插入測試資料。 insert overwrite table tmp_table1 values (1, 'hh', 'liu', '999', 'I'), (2, 'cc', 'zhang', '888', 'I'), (3, 'cy', 'zhang', '666', 'I'),(4, 'hh', 'liu', '999', 'U'), (5, 'cc', 'zhang', '888', 'U'),(6, 'cy', 'zhang', '666', 'U'); --查詢源表的資料確認插入測試資料的操作結果。 select * from tmp_table1; +------------+------------+------------+------------+--------------+ | id | first_name | last_name | phone | _event_type_ | +------------+------------+------------+------------+--------------+ | 1 | hh | liu | 999 | I | | 2 | cc | zhang | 888 | I | | 3 | cy | zhang | 666 | I | | 4 | hh | liu | 999 | U | | 5 | cc | zhang | 888 | U | | 6 | cy | zhang | 666 | U | +------------+------------+------------+------------+--------------+ --執行merge into操作。 merge into acid_address_book_base1 as t using tmp_table1 as s on s.id = t.id and t.year='2020' and t.month='08' and t.day='20' and t.hour='16' when matched then update set t.first_name = s.first_name, t.last_name = s.last_name, t.phone = s.phone when not matched and (s._event_type_='I') then insert values(s.id, s.first_name, s.last_name,s.phone,'2020','08','20','16'); --查詢目標表的資料確認merge into操作結果。 select * from acid_address_book_base1; +------------+------------+------------+------------+------------+------------+------------+------------+ | id | first_name | last_name | phone | year | month | day | hour | +------------+------------+------------+------------+------------+------------+------------+------------+ | 4 | hh | liu | 999 | 2020 | 08 | 20 | 16 | | 5 | cc | zhang | 888 | 2020 | 08 | 20 | 16 | | 7 | djh | hahh | 555 | 2020 | 08 | 20 | 16 | | 1 | hh | liu | 999 | 2020 | 08 | 20 | 16 | | 2 | cc | zhang | 888 | 2020 | 08 | 20 | 16 | | 3 | cy | zhang | 666 | 2020 | 08 | 20 | 16 | +------------+------------+------------+------------+------------+------------+------------+------------+
樣本2:建立目標表merge_acid_dp及源表merge_acid_source,並插入資料。以不指定分區方式執行
merge into
命令,進行更新或者插入資料,對目標表的所有分區生效。--建立目標表merge_acid_dp。 create table if not exists merge_acid_dp(c1 bigint not null, c2 bigint not null) partitioned by (dd string, hh string) tblproperties ("transactional" = "true"); --建立源表merge_acid_source。 create table if not exists merge_acid_source(c1 bigint not null, c2 bigint not null, c3 string, c4 string) lifecycle 30; --向目標表merge_acid_dp插入測試資料。 insert overwrite table merge_acid_dp partition (dd='01', hh='01') values (1, 1), (2, 2); insert overwrite table merge_acid_dp partition (dd='02', hh='02') values (4, 1), (3, 2); --查詢目標表的資料確認插入測試資料的操作結果。 set odps.sql.allow.fullscan=true; select * from merge_acid_dp; +------------+------------+----+----+ | c1 | c2 | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 2 | 2 | 01 | 01 | | 4 | 1 | 02 | 02 | | 3 | 2 | 02 | 02 | +------------+------------+----+----+ --向源表merge_acid_source插入測試資料。 insert overwrite table merge_acid_source values(8, 2, '03', '03'), (5, 5, '05', '05'), (6, 6, '02', '02'); --查詢源表的資料確認插入測試資料的操作結果。 select * from merge_acid_source; +------------+------------+----+----+ | c1 | c2 | c3 | c4 | +------------+------------+----+----+ | 8 | 2 | 03 | 03 | | 5 | 5 | 05 | 05 | | 6 | 6 | 02 | 02 | +------------+------------+----+----+ --執行merge into操作。 merge into merge_acid_dp tar using merge_acid_source src on tar.c2 = src.c2 when matched then update set tar.c1 = src.c1 when not matched then insert values(src.c1, src.c2, src.c3, src.c4); --查詢目標表的資料確認merge into操作結果。 select * from merge_acid_dp; +------------+------------+----+----+ | c1 | c2 | dd | hh | +------------+------------+----+----+ | 6 | 6 | 02 | 02 | | 5 | 5 | 05 | 05 | | 8 | 2 | 02 | 02 | | 8 | 2 | 01 | 01 | | 1 | 1 | 01 | 01 | | 4 | 1 | 02 | 02 | +------------+------------+----+----+
樣本3:建立目標表merge_acid_sp及源表merge_acid_source,並插入資料。以指定分區方式執行
merge into
命令,進行更新或者插入資料,對目標表的指定分區生效。--建立目標表merge_acid_sp。 create table if not exists merge_acid_sp(c1 bigint not null, c2 bigint not null) partitioned by (dd string, hh string) tblproperties ("transactional" = "true"); --建立源表merge_acid_source。 create table if not exists merge_acid_source(c1 bigint not null, c2 bigint not null, c3 string, c4 string) lifecycle 30; --向目標表merge_acid_sp插入測試資料。 insert overwrite table merge_acid_sp partition (dd='01', hh='01') values (1, 1), (2, 2); insert overwrite table merge_acid_sp partition (dd='02', hh='02') values (4, 1), (3, 2); --查詢目標表的資料確認插入測試資料的操作結果。 set odps.sql.allow.fullscan=true; select * from merge_acid_sp; +------------+------------+----+----+ | c1 | c2 | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 2 | 2 | 01 | 01 | | 4 | 1 | 02 | 02 | | 3 | 2 | 02 | 02 | +------------+------------+----+----+ --向源表merge_acid_source插入測試資料。 insert overwrite table merge_acid_source values(8, 2, '03', '03'), (5, 5, '05', '05'), (6, 6, '02', '02'); --查詢源表的資料確認插入測試資料的操作結果。 select * from merge_acid_source; +------------+------------+----+----+ | c1 | c2 | c3 | c4 | +------------+------------+----+----+ | 8 | 2 | 03 | 03 | | 5 | 5 | 05 | 05 | | 6 | 6 | 02 | 02 | +------------+------------+----+----+ --執行merge into操作,同時在on條件中指定只對目標表的dd = '01' and hh = '01'分區執行更新或者插入操作。 merge into merge_acid_sp tar using merge_acid_source src on tar.c2 = src.c2 and tar.dd = '01' and tar.hh = '01' when matched then update set tar.c1 = src.c1 when not matched then insert values(src.c1, src.c2, src.c3, src.c4); --查詢目標表的資料確認merge into操作結果。 select * from merge_acid_sp; +------------+------------+----+----+ | c1 | c2 | dd | hh | +------------+------------+----+----+ | 5 | 5 | 05 | 05 | | 6 | 6 | 02 | 02 | | 8 | 2 | 01 | 01 | | 1 | 1 | 01 | 01 | | 4 | 1 | 02 | 02 | | 3 | 2 | 02 | 02 | +------------+------------+----+----+
樣本4:建立Transaction Table2.0類型目標表mf_tt6及源表mf_delta,並插入資料。以指定分區方式執行
merge into
命令,進行更新、插入或刪除資料,對目標表的指定分區生效。--建立Transaction Table2.0類型目標表mf_tt6。 create table if not exists mf_tt6 (pk bigint not null primary key, val bigint not null) partitioned by (dd string, hh string) tblproperties ("transactional"="true"); --向目標表mf_tt6插入測試資料。 insert overwrite table mf_tt6 partition (dd='01', hh='02') values (1, 1), (2, 2), (3, 3); insert overwrite table mf_tt6 partition (dd='01', hh='01') values (1, 10), (2, 20), (3, 30); --開啟全表掃描,僅此Session有效。執行select語句查看錶mf_tt6中的資料。 set odps.sql.allow.fullscan=true; select * from mf_tt6; +------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 10 | 01 | 01 | | 3 | 30 | 01 | 01 | | 2 | 20 | 01 | 01 | | 1 | 1 | 01 | 02 | | 3 | 3 | 01 | 02 | | 2 | 2 | 01 | 02 | +------------+------------+----+----+ --建立源表mf_delta,並插入測試資料。 create table if not exists mf_delta as select pk, val from values (1, 10), (2, 20), (6, 60) t (pk, val); --查詢源表的資料,確認插入測試資料的操作結果。 select * from mf_delta; +------+------+ | pk | val | +------+------+ | 1 | 10 | | 2 | 20 | | 6 | 60 | +------+------+ --執行merge into操作,同時在on條件中指定只對目標表mf_tt6的dd = '01' and hh = '02'分區執行更新、插入或刪除操作。 merge into mf_tt6 using mf_delta on mf_tt6.pk = mf_delta.pk and mf_tt6.dd='01' and mf_tt6.hh='02' when matched and (mf_tt6.pk > 1) then update set mf_tt6.val = mf_delta.val when matched then delete when not matched then insert values (mf_delta.pk, mf_delta.val, '01', '02'); --查詢目標表的資料確認merge into操作結果。 set odps.sql.allow.fullscan=true; select * from mf_tt6; +------------+------------+----+----+ | pk | val | dd | hh | +------------+------------+----+----+ | 1 | 10 | 01 | 01 | | 3 | 30 | 01 | 01 | | 2 | 20 | 01 | 01 | | 3 | 3 | 01 | 02 | | 6 | 60 | 01 | 02 | | 2 | 20 | 01 | 02 | +------------+------------+----+----+