Bab 12: JOIN (Menggabungkan Data dari Banyak Tabel)
- Notasi Crow's Foot pada ERD (Entity Relationship Diagram) untuk membaca relasi data.
- Empat jenis JOIN utama: INNER JOIN, LEFT JOIN, RIGHT JOIN, dan FULL OUTER JOIN.
- Penanganan nilai NULL hasil LEFT/RIGHT JOIN menggunakan fungsi COALESCE.
- Teknik mengombinasikan 3 tabel atau lebih secara berurutan dalam satu query SQL.
Kenapa JOIN Dibutuhkan
Pada Bab 9, kamu sudah mempelajari bahwa database relasional sengaja memisahkan data ke dalam beberapa tabel
berbeda, seperti tabel pelanggan, produk, dan pesanan pada Belanjain,
untuk menghindari redundansi data. Namun pemisahan ini menimbulkan konsekuensi baru, yaitu ketika kamu ingin
melihat informasi yang lengkap, misalnya nama pelanggan sekaligus nama produk yang mereka pesan, informasi
tersebut sebenarnya tersebar di beberapa tabel berbeda, bukan berada dalam satu tabel yang sama.
JOIN adalah perintah SQL yang memungkinkan kamu menggabungkan baris-baris dari dua tabel atau lebih menjadi satu hasil tampilan, berdasarkan kolom penghubung yang sama, biasanya berupa relasi Primary Key dan Foreign Key. Tanpa JOIN, kamu hanya bisa melihat data pesanan dalam bentuk ID Pelanggan dan ID Produk yang berupa angka tanpa makna, namun dengan JOIN, angka-angka tersebut bisa "diterjemahkan" menjadi nama pelanggan dan nama produk yang sebenarnya.
Membaca ERD dengan Notasi Crow's Foot
Sebelum masuk ke penulisan query JOIN, penting memahami cara membaca ERD, yaitu diagram visual yang menggambarkan struktur tabel dalam sebuah database beserta relasi antar tabelnya. Notasi crow's foot (kaki gagak) adalah cara paling umum untuk menggambarkan kardinalitas antar tabel, dinamai demikian karena simbol yang dipakai untuk menandakan hubungan "banyak" terlihat seperti kaki burung gagak yang bercabang tiga.
Pada database Belanjain, garis yang menghubungkan PELANGGAN dan PESANAN menunjukkan
relasi satu ke banyak (sesuai pembahasan kardinalitas di Bab 9): satu pelanggan bisa memiliki banyak pesanan,
namun satu pesanan hanya dilakukan oleh satu pelanggan. Pola yang sama berlaku antara PRODUK dan
PESANAN. Simbol PK di samping sebuah kolom menandakan Primary Key, sementara FK menandakan
Foreign Key yang merujuk ke tabel lain, persis seperti yang sudah dibahas di Bab 9.
Struktur Dasar Penulisan JOIN
Struktur umum penulisan JOIN dalam SQL adalah sebagai berikut:
SELECT kolom_yang_diinginkan
FROM tabel_pertama
JOIN tabel_kedua ON tabel_pertama.kolom_penghubung = tabel_kedua.kolom_penghubung;
Klausa ON adalah bagian yang menentukan berdasarkan kolom apa kedua tabel tersebut dihubungkan,
biasanya berupa kesamaan antara Primary Key di satu tabel dengan Foreign Key di tabel lainnya. Sebagai
ilustrasi paling dasar, untuk menampilkan nama pelanggan beserta nilai transaksi dari tabel
pesanan dan pelanggan milik Belanjain, querynya ditulis sebagai:
SELECT pelanggan.nama, pesanan.nilai_transaksi
FROM pesanan
JOIN pelanggan ON pesanan.id_pelanggan = pelanggan.id_pelanggan;
Perhatikan penulisan pelanggan.nama dan pesanan.nilai_transaksi, yaitu penulisan
nama kolom yang didahului nama tabelnya, dipisahkan tanda titik. Penulisan seperti ini penting terutama ketika
kedua tabel yang digabungkan memiliki nama kolom yang sama, misalnya kedua tabel sama-sama memiliki kolom
id_pelanggan, sehingga SQL perlu tahu persis kolom dari tabel mana yang dimaksud.
INNER JOIN: Hanya Data yang Cocok di Kedua Tabel
INNER JOIN hanya menampilkan baris-baris yang memiliki kecocokan di kedua tabel yang digabungkan. Jika sebuah baris di tabel pertama tidak memiliki pasangan yang cocok di tabel kedua, atau sebaliknya, baris tersebut tidak akan ikut ditampilkan sama sekali dalam hasil query.
Sebagai ilustrasi dalam konteks Belanjain, bayangkan tabel pelanggan memiliki 1.000 pelanggan
terdaftar, namun hanya 800 di antaranya yang pernah melakukan pemesanan (tercatat di tabel
pesanan), sementara 200 pelanggan lainnya baru mendaftar namun belum pernah berbelanja sama
sekali. Jika kamu menggunakan INNER JOIN antara tabel pelanggan dan pesanan,
hasilnya hanya akan menampilkan 800 pelanggan yang memang memiliki riwayat pesanan, sementara 200 pelanggan
yang belum pernah berbelanja tidak akan muncul sama sekali dalam hasil, karena mereka tidak memiliki baris
yang cocok di tabel pesanan.
SELECT pelanggan.nama, pesanan.nilai_transaksi, pesanan.tanggal_pesanan
FROM pelanggan
INNER JOIN pesanan ON pelanggan.id_pelanggan = pesanan.id_pelanggan;
LEFT JOIN: Seluruh Data Tabel Kiri, Dilengkapi yang Cocok dari Kanan
LEFT JOIN menampilkan seluruh baris dari tabel pertama (tabel yang disebut di sisi kiri, yaitu setelah FROM), ditambah data yang cocok dari tabel kedua jika memang ada kecocokannya. Jika sebuah baris di tabel kiri tidak memiliki pasangan yang cocok di tabel kanan, baris tersebut tetap ditampilkan, namun kolom-kolom yang seharusnya berasal dari tabel kanan akan berisi nilai NULL (kosong).
Melanjutkan contoh sebelumnya, jika kamu ingin menampilkan seluruh 1.000 pelanggan Belanjain, termasuk 200
pelanggan yang belum pernah berbelanja, kamu menggunakan LEFT JOIN dengan tabel pelanggan di sisi
kiri:
SELECT pelanggan.nama, pesanan.nilai_transaksi, pesanan.tanggal_pesanan
FROM pelanggan
LEFT JOIN pesanan ON pelanggan.id_pelanggan = pesanan.id_pelanggan;
Hasil query ini akan menampilkan seluruh 1.000 pelanggan. Untuk 800 pelanggan yang memiliki riwayat pesanan,
kolom nilai_transaksi dan tanggal_pesanan akan terisi sesuai data pesanan mereka.
Namun untuk 200 pelanggan yang belum pernah berbelanja, kedua kolom tersebut akan menampilkan NULL, karena
memang tidak ada data pesanan yang cocok untuk mereka. LEFT JOIN sangat berguna justru ketika kamu ingin
mengetahui data yang "hilang" seperti ini, misalnya untuk mengidentifikasi pelanggan yang belum pernah
berbelanja sebagai target kampanye pemasaran khusus.
RIGHT JOIN: Seluruh Data Tabel Kanan, Dilengkapi yang Cocok dari Kiri
RIGHT JOIN bekerja dengan logika yang persis berkebalikan dari LEFT JOIN, yaitu menampilkan seluruh baris dari tabel kedua (tabel di sisi kanan), ditambah data yang cocok dari tabel pertama jika ada. Penulisannya adalah:
SELECT pelanggan.nama, pesanan.nilai_transaksi
FROM pelanggan
RIGHT JOIN pesanan ON pelanggan.id_pelanggan = pesanan.id_pelanggan;
Query ini akan menampilkan seluruh baris dari tabel pesanan (tabel di sisi kanan), dilengkapi
nama pelanggan yang cocok dari tabel pelanggan. Pada praktiknya, RIGHT JOIN jauh lebih jarang
dipakai dibanding LEFT JOIN, karena hasil yang sama sebenarnya bisa dicapai dengan menukar urutan tabel dan
menggunakan LEFT JOIN. Sebagai ilustrasi, query RIGHT JOIN di atas menghasilkan output yang identik dengan
SELECT pelanggan.nama, pesanan.nilai_transaksi FROM pesanan LEFT JOIN pelanggan ON pesanan.id_pelanggan = pelanggan.id_pelanggan;.
Karena kesetaraan ini, banyak Data Analyst yang lebih terbiasa selalu menggunakan LEFT JOIN dan cukup menukar
urutan tabelnya sesuai kebutuhan, dibanding harus mengingat dua jenis JOIN yang berbeda arah. Meski demikian,
penting tetap memahami RIGHT JOIN karena kamu mungkin menemukannya dalam query yang ditulis orang lain.
FULL OUTER JOIN: Seluruh Data dari Kedua Tabel
FULL OUTER JOIN menggabungkan logika LEFT JOIN dan RIGHT JOIN sekaligus, yaitu menampilkan seluruh baris dari kedua tabel, baik yang memiliki kecocokan maupun yang tidak. Jika sebuah baris di salah satu tabel tidak memiliki pasangan di tabel lainnya, kolom-kolom yang berasal dari tabel yang tidak memiliki pasangan tersebut akan berisi NULL.
SELECT pelanggan.nama, pesanan.nilai_transaksi
FROM pelanggan
FULL OUTER JOIN pesanan ON pelanggan.id_pelanggan = pesanan.id_pelanggan;
Sebagai ilustrasi kapan FULL OUTER JOIN berguna, bayangkan selain 200 pelanggan yang belum pernah berbelanja,
ada juga kondisi anomali di mana beberapa baris pada tabel pesanan memiliki
id_pelanggan yang sudah tidak terdaftar lagi di tabel pelanggan, misalnya karena
akun pelanggan tersebut sudah dihapus dari sistem namun riwayat pesanannya masih tersimpan. FULL OUTER JOIN
akan menampilkan kedua kondisi anomali ini sekaligus dalam satu hasil, yaitu pelanggan tanpa pesanan (kolom
pesanan NULL) maupun pesanan tanpa pelanggan yang valid (kolom pelanggan NULL), sehingga sangat berguna untuk
audit data secara menyeluruh, mengecek konsistensi antar tabel.
Ringkasan Perilaku Keempat Jenis JOIN
| Jenis JOIN | Hasil |
|---|---|
| INNER JOIN | Hanya baris yang cocok di kedua tabel |
| LEFT JOIN | Seluruh baris tabel kiri, NULL pada kolom kanan jika tidak cocok |
| RIGHT JOIN | Seluruh baris tabel kanan, NULL pada kolom kiri jika tidak cocok |
| FULL OUTER JOIN | Seluruh baris dari kedua tabel, NULL di sisi yang tidak cocok |
Menangani NULL dari Hasil LEFT JOIN dan RIGHT JOIN
Nilai NULL yang muncul akibat LEFT JOIN, RIGHT JOIN, maupun FULL OUTER JOIN perlu ditangani dengan hati-hati, karena NULL bukan sekadar "kosong" seperti string kosong atau angka nol, melainkan representasi "tidak ada nilai sama sekali" yang memiliki perilaku khusus dalam SQL. Sebagai ilustrasi, jika kamu mencoba menjumlahkan kolom yang berisi NULL menggunakan SUM, NULL tersebut akan diabaikan secara otomatis dan tidak dihitung sebagai nol, sesuai perilaku yang sudah dibahas pada Bab 11 mengenai fungsi agregasi.
Untuk kebutuhan tampilan yang lebih rapi, terutama pada laporan yang akan dibaca oleh tim non-teknis, NULL sebaiknya diganti dengan nilai yang lebih bermakna, misalnya angka nol untuk kolom numerik atau keterangan seperti "Belum Pernah Berbelanja" untuk kolom teks. SQL menyediakan fungsi yang bisa menggantikan NULL dengan nilai pengganti tertentu, sehingga hasil LEFT JOIN yang tadinya menampilkan NULL bisa diubah menjadi keterangan yang lebih informatif, misalnya:
SELECT
pelanggan.nama,
COALESCE(SUM(pesanan.nilai_transaksi), 0) AS total_belanja
FROM pelanggan
LEFT JOIN pesanan ON pelanggan.id_pelanggan = pesanan.id_pelanggan
GROUP BY pelanggan.nama;
Fungsi COALESCE pada contoh di atas akan mengganti hasil NULL (yang muncul untuk pelanggan tanpa
riwayat pesanan) menjadi angka 0, sehingga kolom total_belanja selalu menampilkan angka, bukan
kosong yang bisa membingungkan pembaca laporan.
Misi Query Tiga Tabel: Customers, Orders, Products
Untuk mengaplikasikan pemahaman JOIN secara menyeluruh, mari bayangkan skenario yang melibatkan penggabungan tiga tabel sekaligus, bukan hanya dua. Tim manajemen Belanjain ingin melihat laporan lengkap yang menampilkan nama pelanggan, nama produk yang dipesan, beserta nilai transaksinya, untuk seluruh pesanan yang tercatat di sistem.
Karena tabel pesanan terhubung dengan tabel pelanggan melalui
id_pelanggan, dan juga terhubung dengan tabel produk melalui id_produk,
kamu perlu menggabungkan ketiga tabel ini sekaligus dalam satu query, dengan cara menuliskan JOIN lebih dari
satu kali secara berurutan:
SELECT
pelanggan.nama AS nama_pelanggan,
produk.nama_produk,
pesanan.jumlah,
pesanan.jumlah * produk.harga AS total_nilai
FROM pesanan
JOIN pelanggan ON pesanan.id_pelanggan = pelanggan.id_pelanggan
JOIN produk ON pesanan.id_produk = produk.id_produk
ORDER BY total_nilai DESC;
Perhatikan bagaimana tabel pesanan dijadikan tabel utama yang di-JOIN dua kali secara berurutan,
pertama dengan tabel pelanggan, kemudian dengan tabel produk, masing-masing
menggunakan klausa ON yang berbeda sesuai kolom penghubungnya masing-masing. Pola menggabungkan
lebih dari dua tabel seperti ini sangat umum dalam pekerjaan nyata seorang Data Analyst, karena laporan bisnis
yang bermakna sering kali membutuhkan informasi yang tersebar di banyak tabel berbeda sekaligus, bukan hanya
dua tabel saja.
- Kategori JOIN: INNER (hanya irisan), LEFT (seluruh tabel kiri), RIGHT (seluruh tabel kanan), FULL OUTER (gabungan seluruh baris).
- Equi-Join & Klausa ON: Menghubungkan tabel menggunakan kesamaan nilai Primary Key = Foreign Key.
- Imputasi NULL: Menggunakan `COALESCE(kolom, nilai_pengganti)` agar output angka/teks tidak kosong.
- Multi-Table JOIN: Menggabungkan 3+ tabel secara berantai (pesanan → pelanggan & pesanan → produk) untuk laporan lengkap.