Episode ini membahas konsep join dalam database relasional: INNER JOIN, LEFT RIGHT dan FULL OUTER JOIN, CROSS JOIN, serta SELF JOIN untuk data hierarki, termasuk teknik menggabungkan tiga tabel atau lebih dalam satu query.

Selamat datang di episode 6 series Belajar SQL PostgreSQL! Sejauh ini kita sudah belajar mengelola satu tabel: membuatnya, mengisinya, dan mengolahnya. Tapi inilah saatnya database relasional menunjukkan kekuatan sejatinya: menggabungkan data dari banyak tabel. Inilah yang membedakan database relasional dari sekadar kumpulan file spreadsheet.
Bayangkan kalian punya tabel orders dan tabel customers. Order hanya menyimpan customer_id, bukan nama lengkap customer. Untuk menampilkan "Order #123 milik Budi Santoso", kalian harus menggabungkan kedua tabel berdasarkan relasi foreign key yang sudah kita bangun di episode 2. Itulah pekerjaan JOIN.
Di episode ini, kita akan membahas konsep join secara menyeluruh: INNER JOIN untuk mengambil data yang cocok, LEFT dan RIGHT OUTER JOIN untuk mempertahankan satu sisi, FULL OUTER JOIN untuk semua data, CROSS JOIN untuk kombinasi Cartesian, dan SELF JOIN untuk data hierarki. Kita juga akan belajar menggabungkan tiga tabel atau lebih dalam satu query.
JOIN adalah operasi yang menggabungkan baris dari dua tabel berdasarkan kondisi tertentu — biasanya kecocokan foreign key. Hasilnya adalah baris-baris baru yang menggabungkan kolom dari kedua tabel.
Visualisasi yang paling mudah adalah diagram lingkaran:
SELECT *
FROM orders
JOIN customers ON orders.customer_id = customers.id;Klausa ON menentukan kondisi penggabungan — di sini mencocokkan customer_id pada orders dengan id pada customers. Kata kunci JOIN sendiri identik dengan INNER JOIN.
Tip
Karena kolom gabungan sering punya nama yang sama (misal keduanya punya kolom id), biasakan memakai alias tabel: FROM orders o JOIN customers c ON o.customer_id = c.id. Query jadi lebih pendek dan ambigu kolom hilang.
INNER JOIN adalah tipe join paling umum. Ia hanya mengembalikan baris yang memiliki kecocokan di kedua tabel. Order tanpa customer yang cocok tidak akan muncul.
SELECT
o.id AS order_id,
c.full_name AS customer,
o.total
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id
ORDER BY o.total DESC;LEFT JOIN mengambil SEMUA baris dari tabel kiri, ditambah data yang cocok dari tabel kanan. Jika tidak ada kecocokan, kolom kanan diisi NULL. Pola paling umum untuk menemukan "data tanpa pasangan":
SELECT c.full_name, o.id AS order_id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
ORDER BY c.full_name;Perhatikan: customer yang belum pernah order akan tetap muncul dengan order_id NULL. Ini jawaban query "tampilkan semua customer beserta order mereka — termasuk yang belum pernah order".
SELECT c.full_name
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;Pola LEFT JOIN + WHERE kanan IS NULL adalah idiom klasik untuk menemukan baris kiri yang tidak punya pasangan.
RIGHT JOIN adalah cermin dari LEFT JOIN: semua baris kanan dipertahankan, kiri diisi NULL jika tak cocok. FULL JOIN menggabungkan keduanya: semua baris dari kedua sisi, dengan NULL pada sisi yang tidak cocok.
SELECT c.full_name, o.id AS order_id
FROM orders o
RIGHT JOIN customers c ON o.customer_id = c.id;
SELECT c.full_name, o.id AS order_id
FROM customers c
FULL JOIN orders o ON o.customer_id = c.id;Note
Secara praktis, LEFT JOIN menguasai 95% kebutuhan join di produksi — Anda tinggal menempatkan tabel "utama" di sisi kiri. RIGHT JOIN bisa diganti dengan membalik posisi tabel, dan FULL JOIN jarang dipakai kecuali untuk audit data (mencari data yang hanya ada di satu sisi).
CROSS JOIN menghasilkan kombinasi setiap baris tabel kiri dengan setiap baris tabel kanan — tanpa kondisi ON. Jika tabel kiri punya 10 baris dan kanan 5 baris, hasilnya 50 baris.
SELECT p.name, s.size_label
FROM products p
CROSS JOIN product_sizes s;Contoh di atas cocok untuk generate daftar produk per ukuran. Tapi hati-hati: CROSS JOIN mudah meledak — tabel 1000×1000 menghasilkan 1 juta baris.
Warning
CROSS JOIN adalah salah satu penyebab query "hang" yang paling umum di production — lupa menulis ON pada join biasa akan diam-diam diubah menjadi CROSS JOIN oleh beberapa database, atau menghasilkan hasil yang salah. Selalu periksa bahwa setiap JOIN punya kondisi ON yang benar.
SELF JOIN menggabungkan sebuah tabel dengan dirinya sendiri. Nama yang terdengar aneh ini sangat berguna untuk data hierarki — misal tabel karyawan dengan kolom manager_id yang menunjuk ke karyawan lain, atau kategori yang punya parent kategori.
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
manager_id INTEGER REFERENCES employees(id)
);Untuk menampilkan nama karyawan beserta nama managernya, kita join tabel dengan dirinya sendiri menggunakan alias berbeda:
SELECT
e.name AS karyawan,
m.name AS manager
FROM employees e
LEFT JOIN employees m ON m.id = e.manager_id
ORDER BY m.name NULLS FIRST;Perhatikan dua hal: tabel yang sama di-join dua kali dengan alias e (employee) dan m (manager), dan kita memakai LEFT JOIN agar karyawan tanpa manager (CEO) tetap muncul. Pola SELF JOIN ini juga dipakai untuk struktur kategori bertingkat dan jaringan sosial (relasi "teman dari teman").
Dunia nyata jarang hanya dua tabel. Order terdiri atas order header, order items, dan products. Untuk menampilkan nama produk pada setiap order, kita gabungkan tiga tabel sekaligus:
SELECT
o.id AS order_id,
c.full_name AS customer,
p.name AS product,
oi.quantity
FROM orders o
JOIN customers c ON c.id = o.customer_id
JOIN order_items oi ON oi.order_id = o.id
JOIN products p ON p.id = oi.product_id
WHERE o.id = 123;Setiap JOIN ditambahkan berurutan, dan masing-masing punya kondisi ON yang menghubungkan tabel barunya ke hasil sebelumnya. Tidak ada batas keras jumlah join, namun semakin banyak join semakin besar biaya eksekusi — di episode 15 kita akan belajar menganalisis performanya.
Tip
Untuk menghindari hasil menggelembung (duplikat tak sengaja) pada multi-join, pikirkan dulu arah relasi. Jika satu order punya 3 item, join orders → order_items akan menggandakan baris order menjadi 3. Saat itulah agregasi seperti SUM(oi.quantity) sering dijumlahkan berkali lipat. Pastikan memahami struktur data sebelum menjumlahkan.
| # | Kesalahan | Gejala | Solusi |
|---|---|---|---|
| 1 | Join tanpa ON | Hasil meledak (Cartesian) | Selalu tulis kondisi ON |
| 2 | Memakai INNER JOIN padahal butuh data "kosong" | Baris tanpa pasangan hilang | Ganti ke LEFT JOIN |
| 3 | Lupa alias tabel pada kolom ambigu | Error column reference is ambiguous | Alias tabel dan tulis tabel.kolom |
| 4 | Menjumlahkan setelah multi-join | Angka agregat menggelembung | Agregasi sebelum join, atau pahami struktur data |
Di episode 6 ini kita sudah menguasai join dalam segala bentuknya: INNER JOIN untuk data yang cocok, LEFT/RIGHT/FULL JOIN untuk mempertahankan satu atau kedua sisi, CROSS JOIN untuk kombinasi Cartesian, SELF JOIN untuk data hierarki, serta teknik multi-table join untuk menggabungkan banyak tabel dalam satu query.
Inti yang harus dibawa pulang:
INNER JOIN mengambil irisan; LEFT JOIN mempertahankan tabel kiri.LEFT JOIN ... WHERE kanan IS NULL menemukan data tanpa pasangan.SELF JOIN adalah kunci untuk data hierarki (karyawan-manager, kategori bertingkat).ON — tanpa itu query jadi CROSS JOIN yang berbahaya.Di episode 7 selanjutnya, kita akan memperluas kemampuan query: Subqueries, Set Operations & Expressions — mulai dari subquery di WHERE, FROM, dan SELECT, logika percabangan CASE WHEN, fungsi penanganan NULL seperti COALESCE dan NULLIF, hingga operasi himpunan UNION, INTERSECT, dan EXCEPT. Kalian akan melihat betapa ekspresifnya SQL yang sebenarnya.