Operator set adalah operator SQL yang menangani penggabungan, dengan cara yang berbeda, set hasil yang berbeda. Katakanlah Anda memiliki dua SELECT
. yang berbeda s yang ingin Anda gabungkan menjadi satu set hasil, operator set ikut bermain. MariaDB telah mendukung UNION
dan UNION ALL
set operator untuk waktu yang lama, dan ini adalah operator set SQL yang paling umum.
Tapi kita lebih dulu di sini, izinkan saya menjelaskan operator set SQL yang kita miliki dan cara kerjanya. Jika Anda ingin mencobanya, Anda dapat menggunakan penerapan Server MariaDB yang ada, atau mencobanya di database awan MariaDB SkySQL.
UNION dan UNION SEMUA
UNION
dan UNION ALL
set operator menambahkan hasil dari dua atau lebih set hasil. Mari kita mulai dengan UNION ALL
dan UNION
kemudian akan menjadi variasi dari UNION ALL
.
Mari kita lihat seperti apa di SQL. Mari kita asumsikan kita menjalankan toko web dan untuk produk yang kita jual, kita memiliki inventaris. Sekarang kita ingin melihat semua produk yang sedang dipesan atau ada dalam inventaris, kueri untuk ini akan terlihat seperti ini:
PILIH oi.prod_id, p.prod_name FROM order_items oi GABUNG produk p ON oi.prod_id =p.id UNION SEMUA PILIH i.prod_id, p.prod_name FROM inventory i JOIN products p ON i.prod_id =p.id;
Ini, dalam teori himpunan, adalah UNION
dari set produk yang telah dipesan dan set produk yang ada di persediaan. Yang secara teori baik-baik saja, tetapi ada masalah dengan hasil kueri ini. Masalahnya adalah bahwa produk yang muncul di pesanan dan inventaris, atau di beberapa tempat di inventaris, akan muncul lebih dari satu kali di output. Masalah ini adalah mengapa UNION ALL
tidak banyak digunakan dan sebagai gantinya UNION DISTINCT
(DISTINCT
adalah default dan dapat diabaikan) digunakan. Misalnya:
PILIH oi.prod_id, p.prod_name FROM order_items oi GABUNG produk p ON oi.prod_id =p.id UNION PILIH i.prod_id, p.prod_name FROM inventory i JOIN products p ON i.prod_id =p.id;Dengan kueri ini, produk yang sedang dipesan atau ada di inventaris hanya dicantumkan satu kali. Perhatikan bahwa ketika kami menghapus duplikat di sini, ini adalah nilai yang dibandingkan, sehingga dua baris dengan nilai yang sama di kolom yang sama dianggap sama, meskipun nilainya berasal dari tabel atau kolom yang berbeda.
Sejujurnya, tidak ada kueri di atas yang tidak dapat dilakukan dengan
SELECT
biasa dari produk tabel dan beberapa bergabung. Dalam beberapa halUNION
mungkin lebih mudah dibaca. Di sisi lain, jika kita ingin memiliki daftar produk yang dipesan atau di inventaris, dan juga ingin tahu yang mana, maka kuerinya akan seperti ini:SELECT 'On order', oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id UNION SELECT 'Inventory', i.prod_id, p.prod_name FROM inventory i JOIN products p ON i.prod_id =p.id;Berikut adalah kueri yang tidak mudah dilakukan dengan
SELECT
sederhana dari produk tabel karena kita melihat baris yang sama dari tabel produk dua kali (sekali untuk order_items dan sekali untuk inventaris ).Lebih banyak operator kumpulan SQL
Dengan MariaDB Server 10.3 datang dua operator set SQL baru, sebagian besar diperkenalkan untuk meningkatkan kompatibilitas Oracle, tetapi operator ini berguna dalam hak mereka sendiri. MariaDB Server 10.4 kemudian menambahkan kemampuan untuk mengontrol prioritas operator yang ditetapkan. Kami akan melihat itu juga. Tanpa kemampuan untuk mengontrol prioritas operator, operator yang ditetapkan tidak selalu berfungsi seperti yang Anda inginkan atau harapkan.
Operator set SQL yang baru adalah
INTERSECT
danEXCEPT
dan mereka berguna, terutama saat menggunakan analitik. Juga, meskipunJOIN
s dan konstruksi lainnya sering dapat digunakan sebagai gantinya, operator set SQL memungkinkan sintaks SQL yang dapat lebih mudah dibaca dan dipahami. Dan, jika Anda memiliki aplikasi Oracle yang Anda migrasikan ke MariaDB, kegunaan operator ini jelas.
Operator set INTERSECT
INTERSECT
operator akan mengembalikan semua item yang ada di dua atau lebih set, atau dalam istilah SQL, semua baris yang ada di dua set hasil. Dalam hal ini, penampang dari dua set item dibuat. Dalam istilah SQL itu berarti bahwa hanya baris yang ada di kedua set yang dikembalikan, jadi jika saya ingin memeriksa produk mana yang saya pesan dan yang juga ada dalam inventaris, kueri mungkin terlihat seperti ini:PILIH oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id INTERSECT SELECT i.prod_id, p.prod_name FROM inventory i JOIN products p ON i.prod_id =p.id;Sekali lagi, kueri ini dapat dibuat menggunakan
JOIN
pada produk tabel, tetapi kueri di atas sedikit lebih jelas tentang apa yang ingin kami capai.Operator set KECUALI
Dalam kasus
EXCEPT
operator, kami menginginkan item yang ada di salah satu set, tetapi tidak di yang lain. Jadi, sekali lagi menggunakan contoh di atas, jika kita ingin melihat produk yang kita pesan tetapi tidak memiliki persediaan, kita bisa menulis query seperti ini:PILIH oi.prod_id, p.prod_name FROM order_items oi GABUNG produk p ON oi.prod_id =p.id KECUALI PILIH i.prod_id, p.prod_name FROM inventory i JOIN products p ON i.prod_id =p.id;Sekali lagi, ada cara lain untuk menulis kueri khusus ini, tetapi untuk kueri lain yang lebih canggih saat kita menggabungkan data dari dua tabel yang berbeda, hal ini tidak terjadi.
Menggabungkan beberapa set operator
Anda dapat menggabungkan lebih dari 2 set operator jika ini berguna. Misalnya, mari kita lihat apakah kita dapat menemukan produk yang sedang dipesan dan telah dikirim atau ada dalam persediaan. SQL untuk ini akan terlihat seperti ini:
PILIH oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id INTERSECT SELECT d.prod_id, p.prod_name FROM delivery d JOIN products p ON d.prod_id =p.id UNION SELECT i.prod_id, p.prod_name FROM inventory i JOIN products p ON i.prod_id =p.id;Untuk mengungkapkan hal ini dalam bahasa sederhana, apa yang terjadi adalah pertama-tama saya memeriksa produk mana yang dipesan dan telah dikirim, lalu saya menggabungkan rangkaian produk ini dengan semua produk dalam inventaris. Produk apa pun yang tidak ada dalam kumpulan hasil tidak ada dalam inventaris tetapi mungkin sedang dipesan atau mungkin telah dikirimkan, tetapi tidak keduanya.
Tapi sekarang, mari kita ungkapkan ini secara berbeda, dan lihat apa yang terjadi. Saya ingin daftar semua produk yang tersedia atau telah dikirim dan sedang dipesan. SQL kemudian akan menjadi seperti ini, mirip dengan SQL di atas tetapi sedikit berbeda:
PILIH i.prod_id, p.prod_name FROM inventory i JOIN products p ON i.prod_id =p.id UNION SELECT oi.prod_id, p.prod_name FROM order_items oi JOIN products p ON oi.prod_id =p.id INTERSECT SELECT d.prod_id, p.prod_name DARI pengiriman d GABUNG produk p ON d.prod_id =p.id;Bagaimana Anda menafsirkan ini kemudian? Apakah Anda mencantumkan produk yang tersedia dan yang sedang dipesan dan produk yang sedang dikirim? Ini adalah apa yang terlihat seperti ini, kan? Hanya saja
INTERSECT
(danEXCEPT
dalam hal ini) memiliki diutamakan melaluiUNION
. Kedua pernyataan SQL menghasilkan kumpulan hasil yang sama, setidaknya di MariaDB dan beginilah cara Standar SQL mengatakan segala sesuatunya harus bekerja. Tapi ada pengecualian, Oracle.Cara kerjanya di Oracle
Oracle telah memiliki keempat operator set SQL (
UNION
,UNION ALL
,INTERSECT
danEXCEPT
) untuk waktu yang lama, jauh sebelum mereka distandarisasi, jadi implementasinya sedikit berbeda. Mari kita coba dengan tabel di atas dan masukkan beberapa data di dalamnya. Datanya sangat sederhana dan mencerminkan perusahaan yang tidak begitu sukses, tetapi ini berfungsi sebagai contoh, dan kami hanya menampilkan kolom yang relevan di sini.
Tabel | produk | order_items | persediaan | pengiriman | ||
Kolom | prod_id | nama_prod | id_pesanan | prod_id | prod_id | prod_id |
Data | 1 | Vas Biru | 1 | 1 | 1 | 2 |
2 | Vas Merah | 2 | 1 | 2 | 3 | |
3 | Karpet Merah | 2 | 3 |
Dengan data yang ada, mari kita lihat lagi pernyataan SQL terakhir di atas. Ada fitur yang memungkinkan Anda untuk mengontrol prioritas, dan itu adalah menggunakan tanda kurung, atau tanda kurung (Diperkenalkan di MariaDB 10.4, lihat https://jira.mariadb.org/browse/MDEV-11953), dan gunakan ini untuk mengilustrasikan apa yang terjadi, pernyataannya akan terlihat seperti ini:
MariaDB> PILIH i.prod_id, p.prod_name -> FROM inventory i JOIN products p ON i.prod_id =p.id -> UNION -> (SELECT oi.prod_id, p.prod_name -> FROM order_items oi JOIN products p ON oi.prod_id =p.id -> INTERSECT -> SELECT d.prod_id, p.prod_name -> FROM pengiriman d GABUNG produk p PADA d.prod_id =p.id); +---------+------------+ | prod_id | nama_prod | +---------+------------+ | 1 | Vas Biru | | 2 | Vas Merah | | 3 | Karpet Merah | +---------+------------+ 3 baris dalam set (0,001 detik)
Sekarang, mari gunakan teknik yang sama untuk menerapkan tiga komponen kueri agar beroperasi dalam urutan yang ketat:
MariaDB> (PILIH i.prod_id, p.prod_name -> FROM inventory i JOIN products p ON i.prod_id =p.id -> UNION -> SELECT oi.prod_id, p.prod_name -> FROM order_items oi JOIN products p ON oi.prod_id =p.id) -> INTERSECT -> SELECT d.prod_id, p.prod_name -> FROM pengiriman d GABUNG produk p ON d.prod_id =p.id; +---------+------------+ | prod_id | nama_prod | +---------+------------+ | 2 | Vas Merah | | 3 | Karpet Merah | +---------+------------+ 2 baris dalam set (0,001 detik)
Dan terakhir tanpa tanda kurung:
MariaDB [test]> PILIH i.prod_id, p.prod_name -> FROM inventory i JOIN products p ON i.prod_id =p.id -> UNION -> SELECT oi.prod_id, p.prod_name -> FROM order_items oi GABUNG produk p ON oi.prod_id =p.id -> INTERSECT -> PILIH d.prod_id, p.prod_name -> FROM pengiriman d GABUNG produk p ON d.prod_id =p.id; +---------+------------+ | prod_id | nama_prod | +---------+------------+ | 1 | Vas Biru | | 2 | Vas Merah | | 3 | Karpet Merah | +---------+------------+ 3 baris dalam set (0,001 detik)
Kami melihat bahwa MariaDB, mengikuti standar, mengasumsikan bahwa INTERSECT
didahulukan daripada UNION
. Yang membawa kita ke Oracle. Mari kita coba SQL di atas di Oracle menggunakan sqlplus:
SQL> PILIH i.prod_id, p.prod_name 2 FROM inventory i JOIN products p ON i.prod_id =p.id 3 UNION 4 SELECT oi.prod_id, p.prod_name 5 FROM order_items oi JOIN products p ON oi.prod_id =p.id 6 INTERSECT 7 PILIH d.prod_id, p.prod_name 8 DARI pengiriman d GABUNG produk p ON d.prod_id =p.id; PROD_ID PROD_NAME ---------- ------------------------------ 2 Vas Merah 3 Karpet MerahApa yang terjadi di sini, Anda bertanya? Nah, Oracle tidak mengikuti standar. Operator himpunan yang berbeda diperlakukan sama dan tidak ada yang didahulukan dari yang lain. Ini adalah masalah ketika Anda memigrasikan aplikasi dari Oracle ke MariaDB, dan yang lebih buruk, perbedaan ini agak sulit ditemukan. Tidak ada kesalahan yang dihasilkan dan data dikembalikan dan, dalam banyak kasus, data yang benar dikembalikan. Namun, dalam beberapa kasus, di mana data seperti pada contoh kami di atas, data yang salah dikembalikan, yang merupakan masalah.
Pengaruh pada Migrasi Data
Jadi bagaimana kita menghadapi ini jika kita memigrasikan aplikasi dari Oracle ke MariaDB? Ada beberapa opsi:
- Tulis ulang aplikasi sehingga mengasumsikan bahwa data yang dikembalikan dari kueri seperti ini sejalan dengan Standar SQL dan MariaDB.
- Tulis ulang pernyataan SQL, menggunakan tanda kurung, sehingga MariaDB mengembalikan data yang sama dengan Oracle
- Atau, dan ini adalah cara paling cerdas, gunakan
SQL_MODE=Oracle
MariaDB pengaturan.
Untuk cara terakhir, dan paling cerdas, agar berfungsi, kita perlu menjalankan dengan MariaDB 10.3.7 atau lebih tinggi (ini disarankan oleh Anda benar-benar di https://jira.mariadb.org/browse/MDEV-13695). Mari kita periksa cara kerjanya. Bandingkan hasil SELECT
. ini dengan Oracle yang di atas (yang menghasilkan hasil yang sama) dan yang dari MariaDB di atasnya (yang tidak):
MariaDB> atur SQL_MODE=Oracle; Kueri OK, 0 baris terpengaruh (0,001 detik) MariaDB> SELECT i.prod_id, p.prod_name -> FROM inventory i JOIN products p ON i.prod_id =p.id -> UNION -> SELECT oi.prod_id, p.prod_name -> FROM order_items oi JOIN products p ON oi.prod_id =p.id -> INTERSECT -> SELECT d.prod_id, p.prod_name -> FROM delivery d JOIN products p ON d.prod_id =p.id; +---------+------------+ | prod_id | nama_prod | +---------+------------+ | 2 | Vas Merah | | 3 | Karpet Merah | +---------+------------+ 2 baris dalam set (0,002 detik)
Seperti yang Anda lihat, ketika SQL_MODE
diatur ke Oracle
, MariaDB benar-benar berperilaku seperti Oracle. Ini bukan satu-satunya hal yang SQL_MODE=Oracle
tentu saja, tetapi ini adalah salah satu area yang kurang dikenal.
Kesimpulan
Operator yang ditetapkan INTERSECT
dan EXCEPT
tidak banyak digunakan, meskipun mereka muncul di sana-sini, dan ada beberapa kegunaan untuk mereka. Contoh di blog ini lebih untuk menggambarkan cara kerja operator ini daripada menunjukkan kegunaan yang sangat baik untuk mereka. Mungkin ada contoh yang lebih baik. Ketika Anda bermigrasi dari Oracle ke MariaDB, operator set SQL sangat berguna karena banyak aplikasi Oracle menggunakannya, dan seperti yang dapat dilihat, MariaDB dapat ditipu untuk bekerja seperti Oracle, yang non-Standar tetapi tetap memiliki tujuan. Namun, secara default, tentu saja MariaDB berfungsi sebagaimana mestinya dan mengikuti Standar SQL.
Selamat SQL'ing
/Karlsson