Topik ini membahas rantai join tiga tabel atau lebih, yaitu cara menjawab pertanyaan yang datanya tersebar di beberapa tabel sekaligus. Kasus utamanya adalah merangkai anggota, peminjaman, dan buku untuk menjawab siapa meminjam buku apa. Gaya penulisan yang terbaca, penggunaan alias, serta peringatan resmi atas USING dan NATURAL JOIN dibahas pada dataset yang sama dengan topik lain pada modul ini.
Merantai tiga tabel#
Rantai join dibaca sebagai operasi berpasangan yang diulang, yaitu SQLite menggabungkan dua tabel pertama menjadi hasil antara, kemudian menggabungkan hasil antara itu dengan tabel ketiga, dan seterusnya. Setiap sambungan membawa kondisi ON sendiri. Jalankan query berikut yang ditulis tanpa alias agar mekanismenya terlihat panjang.
CREATE TABLE buku (id INTEGER PRIMARY KEY, judul TEXT);
CREATE TABLE anggota (id INTEGER PRIMARY KEY, nama TEXT);
CREATE TABLE peminjaman (id INTEGER PRIMARY KEY, id_buku INTEGER, id_anggota INTEGER, tanggal_pinjam TEXT);
INSERT INTO buku VALUES
(1, 'Dasar Algoritma'), (2, 'Peta Langit'), (3, 'Kode dan Sandi'),
(4, 'Sejarah Kertas'), (5, 'Jejak Angin'), (6, 'Arsip Suara');
INSERT INTO anggota VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman VALUES
(1, 1, 1, '2026-03-02'), (2, 3, 2, '2026-03-04'),
(3, 1, 3, '2026-03-06'), (4, 99, 4, '2026-03-09'),
(5, 5, 5, '2026-03-11');
SELECT anggota.nama, peminjaman.tanggal_pinjam, buku.judul
FROM anggota
JOIN peminjaman ON peminjaman.id_anggota = anggota.id
JOIN buku ON buku.id = peminjaman.id_buku
ORDER BY peminjaman.id;Ali|2026-03-02|Dasar Algoritma
Budi|2026-03-04|Kode dan Sandi
Citra|2026-03-06|Dasar Algoritma
Eka|2026-03-11|Jejak AnginSetiap baris hasil kini memuat nama anggota, tanggal peminjaman, dan judul buku, meskipun ketiga informasi tersebut tidak tersimpan secara lengkap dalam satu tabel. Hal ini karena tabel peminjaman hanya menyimpan id_anggota dan id_buku sebagai referensi ke tabel lain. Sambungan pertama memasangkan data peminjaman dengan anggota melalui kondisi peminjaman.id_anggota = anggota.id. Selanjutnya, sambungan kedua menghubungkan hasil penggabungan tersebut dengan tabel buku melalui kondisi buku.id = peminjaman.id_buku. Baris peminjaman dengan id_buku 99 kembali tidak muncul karena tidak ditemukan buku yang cocok. Akibatnya, hasil penggabungan hanya terdiri atas empat baris, sama seperti hasil INNER JOIN dua tabel pada topik sebelumnya.
Alias satu huruf yang bermakna#
Menulis nama tabel lengkap pada query tiga tabel membuat setiap kondisi memanjang dan sulit dipindai. Alias memperpendeknya dengan menamai setiap tabel sekali pada FROM, kemudian nama pendek itu digunakan di seluruh query. Jalankan versi alias berikut yang hasilnya dibandingkan langsung dengan query sebelumnya.
CREATE TABLE buku (id INTEGER PRIMARY KEY, judul TEXT);
CREATE TABLE anggota (id INTEGER PRIMARY KEY, nama TEXT);
CREATE TABLE peminjaman (id INTEGER PRIMARY KEY, id_buku INTEGER, id_anggota INTEGER, tanggal_pinjam TEXT);
INSERT INTO buku VALUES
(1, 'Dasar Algoritma'), (2, 'Peta Langit'), (3, 'Kode dan Sandi'),
(4, 'Sejarah Kertas'), (5, 'Jejak Angin'), (6, 'Arsip Suara');
INSERT INTO anggota VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman VALUES
(1, 1, 1, '2026-03-02'), (2, 3, 2, '2026-03-04'),
(3, 1, 3, '2026-03-06'), (4, 99, 4, '2026-03-09'),
(5, 5, 5, '2026-03-11');
SELECT a.nama, p.tanggal_pinjam, b.judul
FROM anggota a
JOIN peminjaman p ON p.id_anggota = a.id
JOIN buku b ON b.id = p.id_buku
ORDER BY p.id;Ali|2026-03-02|Dasar Algoritma
Budi|2026-03-04|Kode dan Sandi
Citra|2026-03-06|Dasar Algoritma
Eka|2026-03-11|Jejak AnginKeluarannya identik dengan query sebelumnya karena alias hanya mengubah penulisan dan bukan maknanya. Huruf a, p, dan b dipilih dari huruf awal anggota, peminjaman, dan buku, sehingga pembaca dapat menebak tabel yang dirujuk dari setiap awalan tanpa membuka FROM. Hindari alias yang tidak berhubungan dengan tabelnya, misalnya x dan y, karena kejelasan lebih penting daripada kependekan semata. Dengan alias, kondisi p.id_anggota = a.id jauh lebih ringkas dibaca daripada bentuk panjangnya, dan perbedaannya semakin terasa ketika jumlah tabel bertambah.
Gaya penulisan yang mudah dibaca#
Kueri multitable yang mudah diperiksa mengikuti beberapa kebiasaan penulisan yang dapat diterapkan sejak awal. Susun FROM mulai dari tabel utama, kemudian tambahkan tabel pelengkap. Tuliskan setiap JOIN pada baris tersendiri dengan indentasi, letakkan kondisi ON tepat di bawah sambungannya, dan cantumkan kolom hasil secara eksplisit. Urutan sambungan dapat diubah tanpa memengaruhi hasil INNER JOIN, tetapi urutan yang mengikuti alur data lebih mudah dipahami, misalnya anggota, kemudian peminjaman, lalu buku. Kebiasaan ini bukan ketentuan SQLite, melainkan konvensi penulisan yang membuat kueri panjang lebih mudah diperiksa dan diaudit.
Gaya penulisan yang konsisten juga memudahkan pengembangan kueri, misalnya ketika menambahkan tabel keempat atau mengganti INNER JOIN dengan LEFT JOIN pada salah satu sambungan. Perubahan semacam itu lebih mudah diperiksa apabila posisi setiap sambungan terlihat jelas. Seluruh contoh dalam modul ini mengikuti gaya penulisan yang sama sehingga hasilnya dapat dibandingkan secara langsung antartopik.
Baris tanpa pasangan dalam rantai JOIN#
Ketika salah satu sambungan diganti dengan LEFT JOIN, baris yang tidak menemukan pasangan pada sambungan tersebut tetap ditampilkan. Kolom dari tabel di sisi kanan akan bernilai NULL. Jalankan kueri berikut, yang menggunakan LEFT JOIN pada kedua sambungannya.
CREATE TABLE buku (id INTEGER PRIMARY KEY, judul TEXT);
CREATE TABLE anggota (id INTEGER PRIMARY KEY, nama TEXT);
CREATE TABLE peminjaman (id INTEGER PRIMARY KEY, id_buku INTEGER, id_anggota INTEGER, tanggal_pinjam TEXT);
INSERT INTO buku VALUES
(1, 'Dasar Algoritma'), (2, 'Peta Langit'), (3, 'Kode dan Sandi'),
(4, 'Sejarah Kertas'), (5, 'Jejak Angin'), (6, 'Arsip Suara');
INSERT INTO anggota VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman VALUES
(1, 1, 1, '2026-03-02'), (2, 3, 2, '2026-03-04'),
(3, 1, 3, '2026-03-06'), (4, 99, 4, '2026-03-09'),
(5, 5, 5, '2026-03-11');
SELECT a.nama, p.tanggal_pinjam, b.judul
FROM anggota a
LEFT JOIN peminjaman p ON p.id_anggota = a.id
LEFT JOIN buku b ON b.id = p.id_buku
ORDER BY a.id;Ali|2026-03-02|Dasar Algoritma
Budi|2026-03-04|Kode dan Sandi
Citra|2026-03-06|Dasar Algoritma
Dewi|2026-03-09|
Eka|2026-03-11|Jejak Angin
Farhan||Keluaran memuat enam baris, satu untuk setiap anggota. Farhan tampil dengan kolom tanggal dan judul yang kosong karena tidak memiliki peminjaman, sedangkan Dewi menampilkan tanggal pinjamnya tetapi judul yang kosong karena id_buku 99 tidak ditemukan. Perbedaan keduanya memperlihatkan bahwa pada rantai LEFT JOIN, setiap sambungan dapat gagal secara terpisah dan meninggalkan NULL pada titik kegagalannya. Pola LEFT JOIN dengan IS NULL tetap dapat dipasang pada rantai ini untuk membedakan kedua keadaan tersebut.
USING dan NATURAL JOIN#
SQLite menyediakan dua bentuk singkat untuk menggabungkan tabel pada kolom bernama sama, yaitu USING dan NATURAL JOIN. Keduanya sah digunakan apabila dipahami persis, tetapi keduanya menyembunyikan kolom pemicunya sehingga mudah menyesatkan. Jalankan query berikut pada tabel buku dan peminjaman yang sama-sama memiliki kolom id.
CREATE TABLE buku (id INTEGER PRIMARY KEY, judul TEXT);
CREATE TABLE anggota (id INTEGER PRIMARY KEY, nama TEXT);
CREATE TABLE peminjaman (id INTEGER PRIMARY KEY, id_buku INTEGER, id_anggota INTEGER, tanggal_pinjam TEXT);
INSERT INTO buku VALUES
(1, 'Dasar Algoritma'), (2, 'Peta Langit'), (3, 'Kode dan Sandi'),
(4, 'Sejarah Kertas'), (5, 'Jejak Angin'), (6, 'Arsip Suara');
INSERT INTO anggota VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman VALUES
(1, 1, 1, '2026-03-02'), (2, 3, 2, '2026-03-04'),
(3, 1, 3, '2026-03-06'), (4, 99, 4, '2026-03-09'),
(5, 5, 5, '2026-03-11');
SELECT COUNT(*) FROM buku JOIN peminjaman USING (id);
SELECT COUNT(*) FROM buku NATURAL JOIN peminjaman;
SELECT id, judul FROM buku JOIN peminjaman USING (id) ORDER BY id;5
5
1|Dasar Algoritma
2|Peta Langit
3|Kode dan Sandi
4|Sejarah Kertas
5|Jejak AnginUSING (id) memasangkan buku.id dengan peminjaman.id, padahal kedua id bermakna berbeda, yaitu pengenal buku dan pengenal peminjaman. Hasilnya lima pasangan semu, sedangkan jawaban yang benar untuk pertanyaan pasangan buku dan peminjaman adalah empat. NATURAL JOIN menimbulkan bahaya yang sama karena secara otomatis menggunakan semua kolom bernama sama tanpa menyebutkannya, dan daftar pada query ketiga memperlihatkan pasangan yang tidak bermakna itu. Query yang berjalan lancar tanpa pesan error tetapi menjawab pertanyaan yang salah merupakan kegagalan yang paling sulit ditemukan.
Bentuk USING dan NATURAL JOIN tetap perlu dikenali karena keduanya banyak ditemui pada query yang ditulis orang lain. Apabila keduanya dipakai, pastikan kolom pemicunya memang bermakna sama di kedua tabel dan ingat bahwa SELECT * menampilkan kolom pemicu itu satu kali saja. Aturan yang paling aman untuk seluruh pekerjaan tetap ON eksplisit pada setiap sambungan.
Ringkasan#
- Rantai tiga tabel tersusun dari sambungan berpasangan berurutan, masing-masing dengan kondisi ON-nya sendiri.
- Alias satu huruf yang bermakna memperpendek query multi tabel tanpa mengubah hasilnya.
- Pada rantai LEFT JOIN, setiap sambungan dapat gagal secara terpisah dan meninggalkan
NULLpada titik kegagalannya. - USING dan NATURAL JOIN menyembunyikan kolom pemicunya, sehingga ON eksplisit menjadi pilihan yang paling aman.
Referensi#
- SELECT — Dokumentasi SQLite — Sintaks USING, NATURAL JOIN, dan penilaian beberapa operator join berurutan pada FROM.