Bayangkan kamu punya dua laporan penjualan — satu dari toko fisik, satu dari toko online — dan bosmu minta satu laporan gabungan dalam satu tabel bersih. Kamu nggak mau repot copas manual, kan? Di MySQL, kebutuhan "gabungkan dua hasil query jadi satu" ini diselesaikan dengan sangat elegan oleh UNION MySQL. Cukup dua kata, dua query pun berpadu jadi satu.
Selamat datang di Artikel ke-24 dari 28 dalam seri Belajar Query SQL MySQL! Kita sudah jauh banget — dari SELECT dasar, JOIN, hingga subquery di artikel sebelumnya (Artikel 23). Sekarang giliran UNION MySQL dan UNION ALL — dua operator yang membiarkan kamu menumpuk hasil dari beberapa query sekaligus.
Di artikel ini kamu akan belajar perbedaan UNION vs UNION ALL, aturan wajib yang harus dipatuhi, cara menyortir hasil gabungan, dan kapan masing-masing operator ini paling tepat dipakai — semuanya dengan studi kasus toko online yang langsung bisa kamu coba.
UNION sudah ada dalam standar SQL sejak SQL-86 — artinya operator ini sudah eksis lebih dari 35 tahun! Meski terlihat sederhana, UNION adalah fondasi dari banyak laporan bisnis kompleks. Sistem reporting besar seperti Google Analytics dan Tableau secara internal menggunakan prinsip UNION untuk menggabungkan data dari berbagai sumber.
1. Apa Itu UNION MySQL? Konsep & Aturan Wajib
Kalau JOIN menggabungkan data secara horizontal (menambah kolom), maka UNION MySQL menggabungkan data secara vertikal (menumpuk baris). Analoginya: JOIN itu seperti menggabungkan dua lembar kertas secara sejajar, sedangkan UNION itu seperti menumpuk dua tumpukan kertas jadi satu.
-- Sintaks dasar UNION (menghapus duplikat) SELECT kolom1, kolom2, ... -- Query pertama FROM tabel_a UNION SELECT kolom1, kolom2, ... -- Query kedua (jumlah kolom harus sama!) FROM tabel_b; -- Sintaks UNION ALL (TIDAK menghapus duplikat, lebih cepat) SELECT kolom1, kolom2, ... FROM tabel_a UNION ALL SELECT kolom1, kolom2, ... FROM tabel_b; -- Aturan wajib: -- 1. Jumlah kolom di setiap SELECT harus sama -- 2. Tipe data tiap kolom harus kompatibel -- 3. Nama kolom hasil diambil dari SELECT pertama -- 4. ORDER BY hanya boleh di akhir query terakhir
๐ Contoh Dasar: Gabungkan daftar nama pelanggan dan nama supplier
-- Gabungkan nama dari dua tabel berbeda SELECT nama, 'Pelanggan' AS tipe FROM pelanggan UNION SELECT nama_supplier, 'Supplier' AS tipe FROM supplier ORDER BY nama;
| nama | tipe |
|---|---|
| Andi Saputra | Pelanggan |
| Budi Santoso | Pelanggan |
| CV Maju Jaya | Supplier |
| PT Elektronik Nusantara | Supplier |
| Rina Dewi | Pelanggan |
* Hasil diurutkan berdasarkan nama, digabung dari dua tabel berbeda dalam satu output.
Tambahkan kolom literal seperti 'Pelanggan' AS tipe untuk memberi label asal data setiap baris — sangat berguna saat hasil UNION digabung dari tabel-tabel dengan struktur berbeda agar tetap bisa dibedakan.
2. UNION vs UNION ALL — Kapan Pakai Mana?
Ini adalah pertanyaan nomor satu yang selalu muncul: "UNION biasa atau UNION ALL?" Perbedaannya satu hal tapi dampaknya besar: UNION secara otomatis menghapus baris duplikat dari hasil gabungan (mirip seperti SELECT DISTINCT), sedangkan UNION ALL menjaga semua baris termasuk yang duplikat.
Analoginya: UNION itu seperti gabungin dua daftar tamu undangan dan coret nama yang dobel. UNION ALL itu gabungin semua apa adanya — nama dobel tetap dua kali muncul. Konsekuensinya: UNION lebih lambat karena MySQL harus melakukan pengecekan duplikat, sementara UNION ALL lebih cepat karena langsung tumpuk saja.
๐ Contoh: Produk dari dua gudang — lihat perbedaan UNION vs UNION ALL
-- Data dari dua gudang, beberapa produk ada di keduanya -- Dengan UNION: duplikat dihapus SELECT id_produk, nama_produk FROM gudang_jakarta UNION SELECT id_produk, nama_produk FROM gudang_surabaya; -- Dengan UNION ALL: duplikat TETAP ada SELECT id_produk, nama_produk FROM gudang_jakarta UNION ALL SELECT id_produk, nama_produk FROM gudang_surabaya;
Hasil UNION (5 baris)
| id_produk | nama_produk |
|---|---|
| P001 | Laptop ProMax |
| P002 | Smartphone UltraX |
| P003 | Headphone BassMax |
| P004 | Charger Turbo |
| P005 | Kamera Mirrorless |
Hasil UNION ALL (7 baris)
| id_produk | nama_produk |
|---|---|
| P001 | Laptop ProMax |
| P002 | Smartphone UltraX |
| P003 | Headphone BassMax |
| P001 | Laptop ProMax ⚠️ |
| P004 | Charger Turbo |
| P002 | Smartphone UltraX ⚠️ |
| P005 | Kamera Mirrorless |
⚠️ Baris merah = duplikat dari gudang ke-2
UNION (tanpa ALL) melakukan operasi sorting dan deduplication yang cukup berat. Jika kamu yakin data tidak ada duplikat — atau memang butuh semua duplikat — selalu pakai UNION ALL. Di tabel berjuta baris, perbedaan kecepatannya bisa signifikan.
3. UNION MySQL untuk Laporan Gabungan — Studi Kasus Toko Online
Mari kita lihat penggunaan nyata UNION di konteks toko online. Misalnya kamu perlu membuat laporan aktivitas gabungan: tampilkan semua transaksi (pesanan yang selesai dan yang dibatalkan) dalam satu tabel laporan dengan kolom status yang jelas.
๐ Contoh: Laporan gabungan pesanan selesai + pesanan dibatalkan
-- Laporan: semua pesanan selesai dan dibatalkan dalam satu view SELECT id_pesanan, nama AS nama_pelanggan, total_harga, tanggal, 'Selesai' AS status_pesanan FROM pesanan_selesai ps JOIN pelanggan p ON ps.id_pelanggan = p.id_pelanggan UNION ALL SELECT id_pesanan, nama AS nama_pelanggan, total_harga, tanggal, 'Dibatalkan' AS status_pesanan FROM pesanan_batal pb JOIN pelanggan p ON pb.id_pelanggan = p.id_pelanggan ORDER BY tanggal DESC; -- ORDER BY hanya di bagian paling akhir!
| id_pesanan | nama_pelanggan | total_harga | tanggal | status_pesanan |
|---|---|---|---|---|
| ORD-0091 | Budi Santoso | Rp 8.750.000 | 2024-03-15 | Selesai |
| ORD-0088 | Rina Dewi | Rp 450.000 | 2024-03-14 | Dibatalkan |
| ORD-0085 | Andi Saputra | Rp 12.500.000 | 2024-03-12 | Selesai |
| ORD-0081 | Siti Rahayu | Rp 175.000 | 2024-03-10 | Dibatalkan |
Klausa ORDER BY hanya boleh ditulis satu kali di bagian paling akhir setelah semua blok SELECT. MySQL akan mengurutkan seluruh hasil gabungan. Jika kamu mau mengurutkan per blok saja, bungkus tiap blok dalam subquery dengan alias terlebih dahulu.
4. UNION dengan Lebih dari Dua Query & Menggunakan LIMIT
UNION tidak terbatas dua query saja — kamu bisa menumpuk tiga, empat, bahkan lebih banyak query sekaligus. Selama aturan jumlah kolom dan tipe data terpenuhi, MySQL akan memprosesnya satu per satu dari atas ke bawah.
๐ Contoh: Top 3 produk terlaris dari tiga kategori berbeda
-- Ambil 1 produk terlaris dari masing-masing 3 kategori ( SELECT nama_produk, kategori, SUM(qty) AS total_terjual FROM pesanan JOIN produk USING(id_produk) WHERE kategori = 'Elektronik' GROUP BY id_produk ORDER BY total_terjual DESC LIMIT 1 ) UNION ALL ( SELECT nama_produk, kategori, SUM(qty) AS total_terjual FROM pesanan JOIN produk USING(id_produk) WHERE kategori = 'Fashion' GROUP BY id_produk ORDER BY total_terjual DESC LIMIT 1 ) UNION ALL ( SELECT nama_produk, kategori, SUM(qty) AS total_terjual FROM pesanan JOIN produk USING(id_produk) WHERE kategori = 'Aksesoris' GROUP BY id_produk ORDER BY total_terjual DESC LIMIT 1 ); -- Catatan: setiap blok dikurung agar ORDER BY + LIMIT per blok valid
| nama_produk | kategori | total_terjual |
|---|---|---|
| Smartphone UltraX | Elektronik | 247 |
| Kaos Polos Premium | Fashion | 189 |
| Charger Turbo 65W | Aksesoris | 134 |
Untuk menggunakan ORDER BY dan LIMIT per blok SELECT (bukan untuk keseluruhan hasil), bungkus setiap blok dalam tanda kurung ( ). Tanpa kurung, MySQL akan menganggap ORDER BY berlaku untuk semua hasil gabungan.
๐งช Panduan Praktikum: UNION dari Nol
Buat Dua Tabel Sederhana untuk Latihan
CREATE TABLE pelanggan_lama ( id INT PRIMARY KEY, nama VARCHAR(100), kota VARCHAR(50) ); CREATE TABLE pelanggan_baru ( id INT PRIMARY KEY, nama VARCHAR(100), kota VARCHAR(50) ); INSERT INTO pelanggan_lama VALUES (1,'Andi','Jakarta'), (2,'Budi','Bandung'), (3,'Citra','Surabaya'); INSERT INTO pelanggan_baru VALUES (3,'Citra','Surabaya'), (4,'Dewi','Medan'), (5,'Eko','Yogyakarta');
Coba UNION — Lihat Duplikat Dihapus
-- Hasilnya 5 baris (Citra hanya muncul sekali)
SELECT nama, kota FROM pelanggan_lama
UNION
SELECT nama, kota FROM pelanggan_baru;
Coba UNION ALL — Lihat Perbedaannya
-- Hasilnya 6 baris (Citra muncul dua kali!)
SELECT nama, kota FROM pelanggan_lama
UNION ALL
SELECT nama, kota FROM pelanggan_baru;
Tantangan: Tambahkan Kolom Label & Urutkan
SELECT nama, kota, 'Lama' AS segmen FROM pelanggan_lama UNION SELECT nama, kota, 'Baru' AS segmen FROM pelanggan_baru ORDER BY kota ASC, nama ASC;
๐ Ringkasan: UNION vs UNION ALL vs JOIN
Tabel ini merangkum kapan kamu harus memilih operator mana:
| Aspek | UNION | UNION ALL | JOIN |
|---|---|---|---|
| Arah penggabungan | Vertikal (tumpuk baris) | Vertikal (tumpuk baris) | Horizontal (tambah kolom) |
| Duplikat | ✅ Dihapus otomatis | ⚠️ Tetap ada | Tergantung kondisi ON |
| Performa | ⚠️ Lebih lambat (dedup) | ✅ Lebih cepat | ✅ Cepat dengan index |
| Syarat kolom | Jumlah & tipe harus sama | Jumlah & tipe harus sama | Butuh kolom relasi (key) |
| Use case ideal | Gabung + bersihkan duplikat | Laporan log/audit lengkap | Relasi antar tabel (FK) |
| ORDER BY | Hanya di akhir query | Hanya di akhir query | Di mana saja |
Di proyek nyata, UNION sering dipakai untuk membuat virtual unified table dari beberapa tabel terpisah (misalnya tabel log per bulan atau tabel arsip per tahun). Daripada membuat VIEW resmi, developer kadang langsung embed UNION sebagai subquery di dalam FROM untuk laporan ad-hoc yang cepat.
Nama kolom di hasil UNION selalu diambil dari SELECT pertama. Jadi kalau query pertama punya kolom bernama tgl_pesan dan query kedua punya tgl_batal, hasilnya akan bernama tgl_pesan. Gunakan alias (AS nama_kolom) di query pertama untuk memberi nama yang tepat:
SELECT tgl_pesan AS tanggal_aktivitas, 'Pesan' AS jenis FROM pesanan UNION ALL SELECT tgl_batal -- kolom ini otomatis ikut nama "tanggal_aktivitas", 'Batal' FROM pembatalan;
Artikel Berikutnya dalam Seri
Artikel 25: VIEW di MySQL — Membuat Tabel Virtual yang Bisa Dipakai Ulang
Sudah capek nulis query panjang yang sama berulang kali? VIEW adalah jawabannya! Pelajari cara membuat tabel virtual yang menyimpan query kompleks dan bisa dipanggil seperti tabel biasa kapanpun kamu butuhkan.
Baca Artikel 25 →