Foto oleh Myburgh Roux via Pexels

Data pada aplikasi nyata jarang hanya tersimpan dalam satu table saja — informasi pelanggan, pesanan, dan produk biasanya terpisah di table berbeda yang saling berelasi demi menghindari duplikasi data. JOIN adalah cara SQL Server menggabungkan data dari beberapa table sekaligus berdasarkan kolom yang saling berhubungan.

Artikel ini fokus membahas INNER JOIN sebagai jenis JOIN paling dasar dan paling sering dipakai, lengkap dengan contoh menggabungkan lebih dari dua table sekaligus.

Mengapa JOIN Dibutuhkan

Desain database yang baik memisahkan data ke table berbeda untuk menghindari duplikasi (disebut normalisasi). Misalnya, data pelanggan disimpan di table Customers sementara data pesanan di table Orders yang hanya menyimpan CustomerId sebagai referensi, bukan menyalin seluruh data pelanggan di setiap baris order.

Sintaks INNER JOIN

Menggabungkan Orders dan Customers

SELECT o.OrderId, c.FullName, o.TotalAmount FROM Orders o INNER JOIN Customers c ON o.CustomerId = c.CustomerId; -- Expected: setiap baris order muncul lengkap dengan nama pelanggannya, -- hanya untuk order yang CustomerId-nya ADA di table Customers

INNER JOIN hanya mengembalikan baris yang memiliki pasangan cocok di kedua table. Jika sebuah order memiliki CustomerId yang tidak ditemukan di table Customers (misalnya karena data pelanggan sudah dihapus), baris tersebut tidak akan muncul sama sekali di hasil.

JOIN dengan Lebih dari Dua Table

Menggabungkan empat table sekaligus

SELECT o.OrderId, c.FullName, p.ProductName FROM Orders o INNER JOIN Customers c ON o.CustomerId = c.CustomerId INNER JOIN OrderItems oi ON oi.OrderId = o.OrderId INNER JOIN Products p ON p.ProductId = oi.ProductId; -- Expected: satu baris untuk setiap kombinasi order-produk, -- sehingga satu order dengan 3 produk akan muncul sebagai 3 baris

Memberi Alias pada Table yang Di-JOIN

Perhatikan bahwa setiap table di atas diberi alias pendek seperti o, c, dan p. Kebiasaan ini sangat penting pada query dengan banyak JOIN karena membuat penulisan kolom jauh lebih ringkas, dan wajib dilakukan ketika dua table yang di-JOIN memiliki nama kolom yang sama.

Alias menghindari ambiguitas nama kolom yang sama

-- Tanpa alias, nama kolom ambigu akan menyebabkan error SELECT CustomerId FROM Orders JOIN Customers ON ...; -- Error: Ambiguous column name 'CustomerId' -- Dengan alias, jelas kolom dari table mana yang dimaksud SELECT o.CustomerId FROM Orders o JOIN Customers c ON o.CustomerId = c.CustomerId;

JOIN dengan Kondisi Tambahan Selain Kolom Kunci

Kondisi ON pada JOIN tidak harus hanya membandingkan kolom primary key dan foreign key — kondisi tambahan juga bisa disertakan langsung di dalam ON untuk menyaring data sejak proses penggabungan, bukan belakangan di WHERE.

Kondisi tambahan di dalam klausa ON

SELECT o.OrderId, c.FullName FROM Orders o INNER JOIN Customers c ON o.CustomerId = c.CustomerId AND c.IsActive = 1; -- Expected: hanya order dari customer yang MASIH AKTIF -- yang muncul di hasil, difilter sejak proses JOIN

Menempatkan filter tambahan di ON alih-alih di WHERE menghasilkan hasil yang sama pada INNER JOIN, namun menjadi penting dibedakan ketika beralih ke LEFT JOIN, karena posisi filter bisa mengubah hasil akhir secara signifikan.

Sintaks JOIN Lama (Comma Join) vs ANSI JOIN dan Alasan Menghindarinya

Perbandingan comma join lama dengan ANSI INNER JOIN

-- Gaya lama (comma join) - DIHINDARI SELECT o.OrderID, c.CustomerName FROM Orders o, Customers c WHERE o.CustomerID = c.CustomerID; -- Gaya ANSI JOIN - STANDAR yang direkomendasikan SELECT o.OrderID, c.CustomerName FROM Orders o INNER JOIN Customers c ON o.CustomerID = c.CustomerID;

Sebelum standar ANSI SQL-92 diadopsi secara luas, penggabungan table dilakukan dengan menuliskan beberapa nama table dipisahkan koma pada FROM, lalu kondisi penggabungannya diletakkan di WHERE bersamaan dengan kondisi filter lainnya. Gaya ini masih bisa dijalankan di SQL Server saat ini, namun sangat tidak disarankan karena mencampur logika penggabungan table dengan logika filter data dalam satu klausa WHERE yang sama, membuat query sulit dibaca terutama saat melibatkan banyak table.

Sintaks ANSI JOIN yang memisahkan kondisi penggabungan ke klausa ON tersendiri membuat maksud setiap bagian query lebih jelas: FROM dan JOIN menjelaskan table apa saja yang digabung dan bagaimana caranya, sementara WHERE murni berisi kriteria penyaringan baris. Pemisahan ini juga mengurangi risiko lupa menuliskan kondisi penggabungan, kesalahan yang pada comma join akan menghasilkan cross join tanpa disengaja.

Selain lebih mudah dibaca, sintaks ANSI JOIN juga wajib dipakai ketika ingin menggunakan OUTER JOIN seperti LEFT JOIN atau RIGHT JOIN, karena gaya comma join lama tidak memiliki cara standar untuk menyatakan jenis join selain INNER JOIN; inilah alasan utama mengapa seluruh dokumentasi dan contoh kode modern SQL Server secara konsisten memakai sintaks ANSI JOIN.

Self-Join untuk Membandingkan Baris dalam Table yang Sama

Self-join memakai alias table untuk relasi atasan-bawahan

-- Self-join untuk mencari pasangan karyawan dengan atasan langsungnya SELECT e.NamaKaryawan AS Karyawan, m.NamaKaryawan AS Atasan FROM dbo.Karyawan e INNER JOIN dbo.Karyawan m ON e.AtasanID = m.KaryawanID; -- Hasil, contoh: -- Karyawan Atasan -- Rina Budi -- Dedi Budi -- Budi Siti

Self-join adalah teknik menggabungkan sebuah table dengan dirinya sendiri, dipakai ketika ada relasi antarbaris dalam table yang sama, seperti struktur organisasi di mana kolom AtasanID pada table Karyawan merujuk ke KaryawanID pada baris lain di table yang sama. Karena SQL tidak mengizinkan merujuk table yang sama dua kali tanpa pembeda, self-join wajib memakai alias berbeda untuk setiap kemunculan table, seperti e untuk employee dan m untuk manager pada contoh di atas.

Di luar struktur organisasi, self-join juga umum dipakai untuk mencari data duplikat dalam table, membandingkan baris yang berurutan secara kronologis seperti mencari selisih harga antara transaksi hari ini dan transaksi sebelumnya dari pelanggan yang sama, atau mendeteksi pasangan baris yang saling bertabrakan seperti jadwal ruangan yang beririsan waktu. Logikanya tetap sama: table yang sama diperlakukan seolah dua sumber data berbeda lewat alias, lalu dihubungkan dengan kondisi JOIN yang relevan.

Performa self-join sangat bergantung pada keberadaan indeks pada kolom yang dipakai sebagai kondisi penggabungan, dalam contoh di atas yaitu AtasanID dan KaryawanID, karena tanpa indeks yang memadai, SQL Server harus melakukan nested loop atau hash join yang memindai table yang sama berulang kali. Pada struktur hierarki berjenjang banyak, seperti mencari seluruh bawahan hingga level ke-n, self-join biasa pun memiliki keterbatasan dan sebaiknya digantikan dengan recursive Common Table Expression yang dirancang khusus untuk data hierarkis.

Urutan Penulisan JOIN saat Menggabungkan Lebih dari Dua Table

Menggabungkan tiga table berantai

-- Menggabungkan tiga table: Pesanan, Pelanggan, dan Kota SELECT o.OrderID, c.CustomerName, k.NamaKota FROM dbo.Orders o INNER JOIN dbo.Customers c ON o.CustomerID = c.CustomerID INNER JOIN dbo.Kota k ON c.KotaID = k.KotaID WHERE o.TotalHarga > 500000; -- Expected: setiap JOIN berantai menambah satu set kolom -- dari table yang baru digabungkan

Saat lebih dari dua table perlu digabungkan, setiap klausa JOIN tambahan dapat merujuk ke table mana pun yang sudah disebutkan sebelumnya dalam query, tidak harus selalu table yang pertama. Pada contoh di atas, table Kota digabungkan berdasarkan KotaID milik table Customers, bukan langsung ke table Orders, karena relasi antara Orders dan Kota memang tidak langsung melainkan melalui Customers sebagai penghubung.

Urutan penulisan JOIN dalam query tidak selalu menentukan urutan eksekusi fisik, karena Query Optimizer bebas menyusun ulang urutan penggabungan table berdasarkan statistik dan estimasi biaya yang paling efisien, selama hasil akhirnya tetap benar secara logika. Namun menuliskan JOIN secara berurutan mengikuti alur relasi data tetap penting demi keterbacaan, terutama ketika query melibatkan lima table atau lebih dengan kombinasi INNER dan OUTER JOIN sekaligus.

Kesalahan Umum yang Sering Terjadi

Lupa memberi kondisi ON yang benar pada JOIN

JOIN tanpa kondisi ON yang tepat (atau salah menyebut kolom) bisa menghasilkan cartesian product — setiap baris table pertama dipasangkan dengan setiap baris table kedua, menghasilkan jumlah baris yang jauh lebih banyak dari yang diharapkan.

Mengira INNER JOIN akan tetap menampilkan semua data table utama

Berbeda dengan LEFT JOIN, INNER JOIN akan menghilangkan baris yang tidak memiliki pasangan di table lain, sehingga data yang terlihat 'hilang' sebenarnya memang sengaja disaring oleh INNER JOIN.

Kapan Pendekatan Ini Tidak Cocok Dipakai

INNER JOIN cocok dipakai ketika memang hanya data yang saling berelasi yang relevan ditampilkan, namun jika ada kebutuhan menampilkan seluruh data dari salah satu table meski tidak memiliki pasangan (misalnya daftar semua pelanggan termasuk yang belum pernah order), INNER JOIN bukan pilihan yang tepat dan LEFT JOIN yang akan dibahas selanjutnya lebih sesuai.

Ringkasan

INNER JOIN adalah jenis penggabungan table paling umum dipakai karena hanya menampilkan data yang benar-benar saling berelasi. Untuk kasus di mana data yang tidak berpasangan tetap perlu ditampilkan, materi berikutnya akan membahas LEFT JOIN, RIGHT JOIN, dan FULL JOIN.

Seri Belajar SQL Server:

← Sebelumnya: Logika Kondisional dengan CASE WHEN

→ Selanjutnya: Memahami LEFT JOIN RIGHT JOIN dan FULL JOIN