Di dunia nyata, data jarang disimpan dalam satu tabel. Data pelanggan disimpan terpisah dari data pesanan, data produk terpisah dari data kategori. Nah, ketika Anda perlu menampilkan informasi yang menyatu dari beberapa tabel sekaligus, di sinilah perintah JOIN berperan. JOIN adalah salah satu keterampilan paling penting yang harus dikuasai siapa pun yang serius belajar MySQL.
Pada artikel ini kita akan membedah empat jenis JOIN yang paling sering dipakai — INNER, LEFT, RIGHT, dan CROSS — lengkap dengan tabel contoh, hasil query, dan kapan sebaiknya masing-masing digunakan.

Menyiapkan Tabel Contoh
Agar mudah dipahami, kita pakai dua tabel sederhana: pelanggan dan pesanan. Silakan jalankan skrip berikut untuk membuatnya.
CREATE TABLE pelanggan (
id INT PRIMARY KEY AUTO_INCREMENT,
nama VARCHAR(60),
kota VARCHAR(40)
);
CREATE TABLE pesanan (
id INT PRIMARY KEY AUTO_INCREMENT,
pelanggan_id INT,
produk VARCHAR(60),
total INT
);
INSERT INTO pelanggan (nama, kota) VALUES
('Rani', 'Bandung'),
('Dimas', 'Surabaya'),
('Sari', 'Medan'),
('Bagas', 'Bandung');
INSERT INTO pesanan (pelanggan_id, produk, total) VALUES
(1, 'Keyboard', 250000),
(1, 'Mouse', 120000),
(2, 'Monitor', 1500000),
(4, 'Headset', 300000);
Perhatikan bahwa pelanggan Sari belum pernah memesan apa pun, dan ada pesanan yang menunjuk ke pelanggan_id tertentu. Perbedaan inilah yang nanti membuat hasil tiap jenis JOIN berbeda.
INNER JOIN: Hanya yang Cocok di Kedua Tabel
INNER JOIN mengembalikan baris hanya jika ada pasangan yang cocok di kedua tabel. Kalau sebuah baris di tabel kiri tidak punya pasangan di tabel kanan (atau sebaliknya), baris itu tidak akan muncul.
SELECT p.nama, p.kota, o.produk, o.total FROM pelanggan AS p INNER JOIN pesanan AS o ON o.pelanggan_id = p.id;
Hasilnya:
| nama | kota | produk | total |
|---|---|---|---|
| Rani | Bandung | Keyboard | 250000 |
| Rani | Bandung | Mouse | 120000 |
| Dimas | Surabaya | Monitor | 1500000 |
| Bagas | Bandung | Headset | 300000 |
Sari tidak muncul karena tidak punya pesanan. Kata kunci AS di atas dipakai untuk memberi alias (nama singkat) pada tabel supaya query lebih ringkas — p untuk pelanggan dan o untuk pesanan.
LEFT JOIN: Semua Baris Tabel Kiri
LEFT JOIN mengembalikan seluruh baris dari tabel kiri, ditambah data dari tabel kanan bila ada pasangannya. Jika tidak ada pasangan, kolom dari tabel kanan diisi NULL.
SELECT p.nama, o.produk, o.total FROM pelanggan AS p LEFT JOIN pesanan AS o ON o.pelanggan_id = p.id;
| nama | produk | total |
|---|---|---|
| Rani | Keyboard | 250000 |
| Rani | Mouse | 120000 |
| Dimas | Monitor | 1500000 |
| Sari | NULL | NULL |
| Bagas | Headset | 300000 |
Sekarang Sari ikut tampil meski kolom produk dan total-nya NULL. LEFT JOIN sangat berguna saat Anda ingin menjawab pertanyaan seperti “siapa saja pelanggan yang belum pernah memesan?” — tinggal tambahkan WHERE o.id IS NULL.
SELECT p.nama FROM pelanggan AS p LEFT JOIN pesanan AS o ON o.pelanggan_id = p.id WHERE o.id IS NULL;
Query di atas akan menghasilkan satu baris: Sari.
RIGHT JOIN: Kebalikan LEFT JOIN
RIGHT JOIN adalah cerminan LEFT JOIN — ia menjamin semua baris tabel kanan ikut tampil. Secara praktik, RIGHT JOIN jarang dipakai karena hampir selalu bisa ditulis ulang menjadi LEFT JOIN dengan menukar posisi tabel, yang biasanya lebih mudah dibaca.
SELECT p.nama, o.produk FROM pelanggan AS p RIGHT JOIN pesanan AS o ON o.pelanggan_id = p.id;
Karena semua pesanan pada contoh kita punya pelanggan yang valid, hasilnya sama dengan INNER JOIN. Namun seandainya ada pesanan dengan pelanggan_id yang tidak terdaftar, baris itu tetap muncul dengan kolom pelanggan bernilai NULL.
CROSS JOIN: Semua Kombinasi
CROSS JOIN menghasilkan perkalian kartesian — setiap baris tabel kiri dipasangkan dengan setiap baris tabel kanan. Jika tabel kiri punya 4 baris dan kanan 4 baris, hasilnya 16 baris. CROSS JOIN tidak memakai klausa ON.
SELECT u.ukuran, w.warna FROM ukuran AS u CROSS JOIN warna AS w;
Contoh pemakaian nyata: membuat daftar seluruh kombinasi varian produk (ukuran × warna) untuk sebuah katalog. Hati-hati, pada tabel besar CROSS JOIN bisa menghasilkan jutaan baris dan membebani server.
Menggabungkan Tiga Tabel Sekaligus
JOIN tidak dibatasi dua tabel. Anda bisa merangkai beberapa JOIN berturut-turut. Misalnya menambahkan tabel kota untuk mengambil nama provinsi:
SELECT p.nama, o.produk, k.provinsi FROM pelanggan AS p INNER JOIN pesanan AS o ON o.pelanggan_id = p.id INNER JOIN kota AS k ON k.nama = p.kota;
Kuncinya: setiap JOIN baru selalu diikuti klausa ON yang menjelaskan hubungan antar-tabel.
JOIN Digabung dengan Agregasi
Kekuatan JOIN semakin terasa ketika dipadukan dengan GROUP BY. Contoh: menghitung total belanja per pelanggan.
SELECT p.nama, SUM(o.total) AS total_belanja FROM pelanggan AS p LEFT JOIN pesanan AS o ON o.pelanggan_id = p.id GROUP BY p.id, p.nama ORDER BY total_belanja DESC;
Dengan LEFT JOIN, pelanggan yang belum memesan tetap tampil dengan total NULL (bisa diubah jadi 0 memakai COALESCE(SUM(o.total), 0)).
Ringkasan Jenis JOIN
| Jenis | Baris yang dikembalikan | Kapan dipakai |
|---|---|---|
| INNER JOIN | Hanya yang cocok di kedua tabel | Butuh data yang pasti berpasangan |
| LEFT JOIN | Semua kiri + kanan yang cocok | Ingin menampilkan semua data induk |
| RIGHT JOIN | Semua kanan + kiri yang cocok | Jarang; kebalikan LEFT |
| CROSS JOIN | Semua kombinasi (kartesian) | Membuat matriks/varian kombinasi |
Kesalahan Umum yang Perlu Dihindari
- Lupa klausa ON pada INNER/LEFT JOIN sehingga tanpa sengaja terjadi CROSS JOIN dan baris membengkak.
- Menaruh filter tabel kanan di WHERE, bukan di ON pada LEFT JOIN. Menulis
WHERE o.total > 0diam-diam mengubah LEFT JOIN menjadi seperti INNER JOIN karena baris NULL ikut tersaring. Kalau ingin memfilter tapi tetap mempertahankan baris NULL, taruh kondisinya diON. - Kolom ambigu. Jika nama kolom sama di dua tabel (misalnya
id), selalu beri prefix alias sepertip.id.
Contoh Kasus Nyata: Laporan Penjualan Toko
Bayangkan Anda diminta membuat laporan “10 produk terlaris beserta jumlah pembelinya”. Datanya tersebar di tiga tabel: produk, detail_pesanan, dan pesanan. Dengan JOIN, laporan itu cukup satu query:
SELECT pr.nama_produk,
COUNT(DISTINCT ps.pelanggan_id) AS jumlah_pembeli,
SUM(dp.qty) AS total_terjual
FROM produk AS pr
INNER JOIN detail_pesanan AS dp ON dp.produk_id = pr.id
INNER JOIN pesanan AS ps ON ps.id = dp.pesanan_id
GROUP BY pr.id, pr.nama_produk
ORDER BY total_terjual DESC
LIMIT 10;
Tanpa JOIN, Anda harus menembak database berkali-kali dari kode PHP dan menggabungkannya secara manual — jauh lebih lambat dan boros memori. Inilah alasan JOIN begitu penting: memindahkan pekerjaan berat penggabungan data ke sisi database yang memang dioptimalkan untuk itu.
Penutup
JOIN mengubah beberapa tabel terpisah menjadi satu tampilan data yang utuh dan bermakna. Mulailah dari INNER JOIN dan LEFT JOIN karena keduanya menutup 90% kebutuhan sehari-hari, lalu naik ke penggabungan banyak tabel dan agregasi. Latih terus dengan skema tabel Anda sendiri agar semakin terbiasa.
Referensi: untuk pendalaman lebih lanjut, kunjungi dokumentasi resmi MySQL.

