Saat Anda perlu melakukan operasi INSERT, UPDATE, dan DELETE pada tabel transaksional atau tabel Delta, Anda dapat menggunakan fitur MERGE INTO untuk menggabungkan operasi tersebut dalam satu Pernyataan SQL. Pernyataan ini melakukan penyisipan, pembaruan, atau penghapusan pada tabel transaksional target berdasarkan hasil join dengan tabel sumber, hanya dengan satu kali pemindaian tabel penuh sehingga meningkatkan efisiensi eksekusi.
Pengenalan
MaxCompute mendukung operasi DELETE dan UPDATE. Namun, untuk menjalankan operasi batch INSERT, UPDATE, dan DELETE pada tabel target, Anda harus menulis Pernyataan SQL terpisah, yang memerlukan beberapa kali pemindaian tabel penuh. Fitur MERGE INTO MaxCompute menjalankan semua operasi tersebut hanya dalam satu kali pemindaian tabel penuh, sehingga lebih efisien dibandingkan menjalankan pernyataan INSERT, UPDATE, dan DELETE secara terpisah.
Operasi MERGE INTO bersifat atomik. Sebuah Pekerjaan hanya berhasil jika seluruh operasi INSERT, UPDATE, dan DELETE berhasil. Jika ada operasi internal yang gagal, seluruh Pekerjaan akan gagal.
Pernyataan MERGE INTO juga mencegah masalah yang dapat terjadi saat Anda menjalankan operasi INSERT, UPDATE, dan DELETE secara terpisah. Misalnya, jika sebagian operasi berhasil sementara yang lain gagal, perubahan yang berhasil tidak dapat di-rollback. Pernyataan MERGE INTO menghindari masalah ini.
Penerapan
Operasi
MERGE INTOmemerlukan izin Select (baca) dan Update pada tabel transaksional target. Untuk informasi selengkapnya, lihat izin MaxCompute.Jangan lakukan beberapa operasi
INSERTatau UPDATE pada baris yang sama dalam satu pernyataanMERGE INTO.Tabel target dari pernyataan
MERGE INTOharus berupa tabel transaksional.Pernyataan
MERGE INTOharus mencakup setidaknya satumerge_action.Jika Anda menggunakan beberapa klausa
not_matched_by_target_clause, paling banyak satu klausa yang boleh menghilangkansearch_condition.Jika Anda menggunakan beberapa klausa
not_matched_by_source_clause, paling banyak satu klausa yang boleh menghilangkansearch_condition.Jika Anda menggunakan beberapa klausa
matched_clause, paling banyak satu klausa yang boleh menghilangkansearch_condition.Subkueri tidak didukung dalam
merge_conditiondansearch_condition.
Format perintah
MERGE INTO <target_table> AS <alias_name_t>
USING <source expression | table_name> AS <alias_name_s>
-- Klausa ON menentukan kondisi join untuk tabel sumber dan target.
ON merge_condition
{ merge_action } +
merge_action ::= matched_clause | not_matched_by_target_clause | not_matched_by_source_clause
-- Klausa WHEN MATCHED...THEN menentukan aksi untuk hasil true dari klausa ON. Data yang diproses oleh beberapa klausa WHEN MATCHED...THEN tidak boleh tumpang tindih.
matched_clause ::= WHEN MATCHED [ AND <search_condition> ] THEN { merge_update_clause | merge_delete_clause }
-- Klausa WHEN NOT MATCHED...THEN menentukan aksi untuk hasil false dari klausa ON.
not_matched_by_target_clause ::= WHEN NOT MATCHED [BY TARGET] [ AND <search_condition> ] THEN merge_insert_clause
not_matched_by_source_clause ::= WHEN NOT MATCHED BY SOURCE [ AND <search_condition> ] THEN { merge_update_clause | merge_delete_clause }
merge_condition ::= ekspresi BOOLEAN
search_condition ::= ekspresi BOOLEAN
merge_update_clause ::= UPDATE SET <set_clause_list>
merge_delete_clause ::= DELETE
merge_insert_clause ::= INSERT <value_list> | ROW | *Parameter
Parameter | Wajib | Deskripsi |
target_table | Ya | Nama tabel target. Tabel tersebut harus sudah ada. |
alias_name_t | Tidak | Alias untuk tabel target. |
source expression|table_name | Ya | Nama tabel sumber, Tampilan, atau subkueri yang akan di-join. |
alias_name_s | Tidak | Alias untuk tabel sumber, Tampilan, atau subkueri. |
merge_condition | Ya | Ekspresi kondisional yang mengembalikan nilai BOOLEAN. Hasilnya harus True atau False. |
search_condition | Tidak | Ekspresi kondisional BOOLEAN yang sesuai untuk operasi
|
set_clause_list | Tidak | Data yang akan diperbarui. Parameter ini wajib untuk operasi Untuk informasi selengkapnya tentang |
value_list | Tidak | Data yang akan disisipkan. Ini wajib untuk operasi Untuk informasi selengkapnya tentang |
merge_action | Ya | merge_action memiliki tiga opsi: MATCHED, NOT MATCHED BY TARGET, dan NOT MATCHED BY SOURCE. Setiap merge_action dapat menyertakan kondisi pencarian opsional (search_condition). merge_action hanya dieksekusi pada suatu baris jika kedua kondisi—merge_condition dan search_condition—terpenuhi. Jika beberapa klausa cocok, hanya merge_action pertama yang cocok yang dieksekusi untuk baris tersebut. |
matched_clause | Tidak | matched_clause memiliki dua opsi, UPDATE dan DELETE, untuk menentukan cara memperbarui atau menghapus baris di tabel target saat baris tersebut cocok dengan baris dari tabel sumber. |
not_matched_by_target_clause | Tidak | Menentukan cara menyisipkan baris dari tabel sumber ke tabel target jika tidak ada baris yang cocok. |
not_matched_by_source_clause | Tidak | Menentukan cara memperbarui atau menghapus baris di tabel target saat baris tersebut tidak memiliki baris yang cocok di tabel sumber. |
merge_insert_clause | Tidak | merge_insert_clause memiliki tiga opsi: value_list, ROW, dan *. Opsi value_list menggunakan ekspresi values untuk menentukan data yang akan disisipkan. Opsi ROW dan * langsung menyisipkan data yang cocok dari tabel sumber ke tabel target. Untuk opsi-opsi ini, jumlah kolom pada tabel target dan sumber harus sama, serta tipe data yang sesuai harus kompatibel. |
Contoh
Contoh 1: Buat tabel target `acid_address_book_base1` dan tabel sumber `tmp_table1`, lalu sisipkan data. Jalankan operasi
MERGE INTO. Jika data memenuhi kondisiON, perbarui tabel target dengan data dari tabel sumber. Jika data tidak memenuhi kondisiONdan _event_type_ di tabel sumber adalah I, sisipkan data tersebut ke tabel target. Perintah contoh berikut digunakan:--Buat tabel target 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"); --Buat tabel sumber tmp_table1. CREATE TABLE IF NOT EXISTS tmp_table1 (id BIGINT, first_name STRING, last_name STRING, phone STRING, _event_type_ STRING); --Sisipkan data uji ke tabel target 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'); --Kueri tabel target untuk mengonfirmasi hasil penyisipan data. SET odps.sql.allow.fullscan=true; SELECT * FROM acid_address_book_base1; --Hasil berikut dikembalikan: +------------+------------+------------+------------+------------+------------+------------+------------+ | 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 | +------------+------------+------------+------------+------------+------------+------------+------------+ --Sisipkan data uji ke tabel sumber 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'); --Kueri tabel sumber untuk mengonfirmasi hasil penyisipan data. SET odps.sql.allow.fullscan=true; SELECT * FROM tmp_table1; --Hasil berikut dikembalikan: +------------+------------+------------+------------+--------------+ | 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 | +------------+------------+------------+------------+--------------+ --Jalankan operasi 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'); --Kueri tabel target untuk mengonfirmasi hasil operasi merge into. SET odps.sql.allow.fullscan=true; SELECT * FROM acid_address_book_base1; --Hasil berikut dikembalikan: +------------+------------+------------+------------+------------+------------+------------+------------+ | 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 | +------------+------------+------------+------------+------------+------------+------------+------------+Contoh 2: Buat tabel target `acid_target1` dan tabel sumber `tmp_table2`, lalu sisipkan data. Jalankan operasi
MERGE INTOuntuk melakukan tindakan berikut: sisipkan baris dari tabel sumber ke tabel target jika baris tersebut tidak cocok dengan baris apa pun di tabel target dan kolom `name`-nya adalah 'Nika'; hapus baris dari tabel target jika baris tersebut tidak cocok dengan baris apa pun di tabel sumber dan kolom `name`-nya adalah 'Tommy'; serta perbarui baris di tabel target jika baris tersebut cocok dengan baris di tabel sumber dan kolom `name`-nya adalah 'Gene'.--Buat tabel target acid_target1. CREATE TABLE IF NOT EXISTS acid_target1 (id BIGINT, name STRING, phone STRING) tblproperties ("transactional"="true"); --Buat tabel sumber tmp_table2. CREATE TABLE IF NOT EXISTS tmp_table2 (id BIGINT, name STRING, phone STRING); --Sisipkan data uji ke tabel target acid_target1. INSERT OVERWRITE TABLE acid_target1 VALUES (1, 'Tommy', '111'), (2, 'Gene', '222'), (3, 'Abram', '333'); --Kueri tabel target untuk mengonfirmasi hasil penyisipan data. SELECT * FROM acid_target1; --Hasil berikut dikembalikan: +------------+------+-------+ | id | name | phone | +------------+------+-------+ | 1 | Tommy | 111 | | 2 | Gene | 222 | | 3 | Abram | 333 | +------------+------+-------+ --Sisipkan data uji ke tabel sumber tmp_table2. INSERT OVERWRITE TABLE tmp_table2 VALUES (6, 'Queen', '666'), (7, 'Nika', '777'); --Kueri tabel sumber untuk mengonfirmasi hasil penyisipan data. SELECT * FROM tmp_table2; --Hasil berikut dikembalikan: +------------+------+-------+ | id | name | phone | +------------+------+-------+ | 6 | Queen | 666 | | 7 | Nika | 777 | +------------+------+-------+ --Jalankan operasi merge into. --Sisipkan baris dengan name 'Nika' dari tabel sumber ke tabel target. --Hapus baris dengan name 'Tommy' dari tabel target. --Perbarui baris dengan name 'Gene' di tabel target. Ubah nilai phone dari '222' menjadi '999'. MERGE INTO acid_target1 t USING tmp_table2 s ON t.id = s.id WHEN NOT MATCHED BY TARGET AND s.name = 'Nika' THEN INSERT (id, name, phone) VALUES(s.id, s.name, s.phone) WHEN NOT MATCHED BY SOURCE AND t.name = 'Tommy' THEN DELETE WHEN NOT MATCHED BY SOURCE AND t.name = 'Gene' THEN UPDATE SET t.phone = '999'; --Kueri tabel target untuk mengonfirmasi hasil operasi merge into. SELECT * FROM acid_target1; --Hasil berikut dikembalikan: +------------+------+-------+ | id | name | phone | +------------+------+-------+ | 2 | Gene | 999 | | 7 | Nika | 777 | | 3 | Abram | 333 | +------------+------+-------+Contoh 3: Buat tabel target `merge_acid_dp` dan tabel sumber `merge_acid_source`, lalu sisipkan data. Jalankan perintah
MERGE INTOuntuk memperbarui atau menyisipkan data tanpa menentukan partisi tertentu. Operasi ini diterapkan ke semua partisi tabel target.--Buat tabel target 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"); --Buat tabel sumber 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; --Sisipkan data uji ke tabel target 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); --Kueri tabel target untuk mengonfirmasi hasil penyisipan data. SET odps.sql.allow.fullscan=true; SELECT * FROM merge_acid_dp; --Hasil berikut dikembalikan: +------------+------------+----+----+ | c1 | c2 | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 2 | 2 | 01 | 01 | | 4 | 1 | 02 | 02 | | 3 | 2 | 02 | 02 | +------------+------------+----+----+ --Sisipkan data uji ke tabel sumber merge_acid_source. INSERT OVERWRITE TABLE merge_acid_source VALUES(8, 2, '03', '03'), (5, 5, '05', '05'), (6, 6, '02', '02'); --Kueri tabel sumber untuk mengonfirmasi hasil penyisipan data. SET odps.sql.allow.fullscan=true; SELECT * FROM merge_acid_source; --Hasil berikut dikembalikan: +------------+------------+----+----+ | c1 | c2 | c3 | c4 | +------------+------------+----+----+ | 8 | 2 | 03 | 03 | | 5 | 5 | 05 | 05 | | 6 | 6 | 02 | 02 | +------------+------------+----+----+ --Jalankan operasi merge into. SET odps.sql.allow.fullscan=true; 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); --Kueri tabel target untuk mengonfirmasi hasil operasi merge into. SET odps.sql.allow.fullscan=true; SELECT * FROM merge_acid_dp; --Hasil berikut dikembalikan: +------------+------------+----+----+ | 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 | +------------+------------+----+----+Contoh 4: Buat tabel target `merge_acid_sp` dan tabel sumber `merge_acid_source`, lalu sisipkan data. Jalankan perintah
MERGE INTOuntuk memperbarui atau menyisipkan data ke partisi tertentu dari tabel target.--Buat tabel target 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"); --Buat tabel sumber 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; --Sisipkan data uji ke tabel target 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); --Kueri tabel target untuk mengonfirmasi hasil penyisipan data. SET odps.sql.allow.fullscan=true; SELECT * FROM merge_acid_sp; --Hasil berikut dikembalikan: +------------+------------+----+----+ | c1 | c2 | dd | hh | +------------+------------+----+----+ | 1 | 1 | 01 | 01 | | 2 | 2 | 01 | 01 | | 4 | 1 | 02 | 02 | | 3 | 2 | 02 | 02 | +------------+------------+----+----+ --Sisipkan data uji ke tabel sumber merge_acid_source. INSERT OVERWRITE TABLE merge_acid_source VALUES(8, 2, '03', '03'), (5, 5, '05', '05'), (6, 6, '02', '02'); --Kueri tabel sumber untuk mengonfirmasi hasil penyisipan data. SET odps.sql.allow.fullscan=true; SELECT * FROM merge_acid_source; --Hasil berikut dikembalikan: +------------+------------+----+----+ | c1 | c2 | c3 | c4 | +------------+------------+----+----+ | 8 | 2 | 03 | 03 | | 5 | 5 | 05 | 05 | | 6 | 6 | 02 | 02 | +------------+------------+----+----+ --Jalankan operasi merge into. Dalam kondisi ON, tentukan bahwa operasi pembaruan atau penyisipan hanya berlaku untuk partisi dd = '01' dan hh = '01' dari tabel target. SET odps.sql.allow.fullscan=true; 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); --Kueri tabel target untuk mengonfirmasi hasil operasi merge into. SET odps.sql.allow.fullscan=true; 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 | +------------+------------+----+----+Contoh 5: Buat tabel Delta `mf_tt6` sebagai tabel target dan tabel sumber `mf_delta`, lalu sisipkan data. Jalankan perintah
MERGE INTOdengan partisi tertentu untuk memperbarui, menyisipkan, atau menghapus data di partisi-partisi tersebut.--Buat tabel Transaksional 2.0 mf_tt6 sebagai tabel target. 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"); --Sisipkan data uji ke tabel target 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); --Aktifkan pemindaian tabel penuh hanya untuk Sesi saat ini. Jalankan pernyataan select untuk melihat data di tabel mf_tt6. SET odps.sql.allow.fullscan=true; SELECT * FROM mf_tt6; --Hasil berikut dikembalikan: +------------+------------+----+----+ | 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 | +------------+------------+----+----+ --Buat tabel sumber mf_delta dan sisipkan data uji. CREATE TABLE IF NOT EXISTS mf_delta AS SELECT pk, val FROM VALUES (1, 10), (2, 20), (6, 60) t (pk, val); --Kueri tabel sumber untuk mengonfirmasi hasil penyisipan data. SELECT * FROM mf_delta; --Hasil berikut dikembalikan: +------+------+ | pk | val | +------+------+ | 1 | 10 | | 2 | 20 | | 6 | 60 | +------+------+ --Jalankan operasi merge into. Dalam kondisi ON, tentukan bahwa operasi pembaruan, penyisipan, atau penghapusan hanya berlaku untuk partisi dd = '01' dan hh = '02' dari tabel target mf_tt6. 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'); --Kueri tabel target untuk mengonfirmasi hasil operasi merge into. SET odps.sql.allow.fullscan=true; SELECT * FROM mf_tt6; --Hasil berikut dikembalikan: +------------+------------+----+----+ | 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 | +------------+------------+----+----+