Langsung ke konten
Belajar Database

Pengertian dan Contoh Subquery pada MySQL & Oracle

Foto TaufiqOleh Taufiq
Pengertian dan Contoh SUBQUERY pada MYSQL / ORACLE

Halo! Pernahkah Anda buntu saat menulis query SQL karena data tersebar di beberapa tabel dan Anda tidak tahu cara menggabungkannya dalam satu perintah? Atau pernah ingin memfilter data berdasarkan hasil dari query lain? Di sinilah subquery — atau yang sering disebut query bersarang — menjadi senjata andalan. Subquery adalah query SQL yang ditulis di dalam query lain, memungkinkan Anda menjalankan logika kompleks tanpa memecahnya menjadi beberapa perintah terpisah. Artikel ini mengupas tuntas konsep subquery MySQL dan Oracle: mulai dari pengertian, contoh dasar, jenis-jenisnya, perbandingan dengan JOIN, hingga tips performa dan studi kasus nyata. Setelah membaca, Anda akan paham kapan dan bagaimana memakai query bersarang untuk menyelesaikan masalah database sehari-hari dengan lebih efisien.

Subquery MySQL: Kunci untuk Query yang Lebih Cerdas dan Fleksibel

Pernahkah Anda mendapati diri stuck saat menulis query SQL karena datanya tersebar di beberapa tabel dan Anda tidak tahu cara menggabungkannya dalam satu perintah? Atau pernahkah Anda ingin memfilter data berdasarkan hasil dari query lain? Nah, di sinilah subquery (query bersarang) menjadi senjata yang sangat berguna. Query Bersarang memungkinkan Anda menyisipkan satu query di dalam query lain, sehingga Anda bisa menjalankan logika yang lebih kompleks tanpa harus memecahnya menjadi beberapa query terpisah.

Mari kita belajar query bersarang dari nol, memahami cara kerjanya secara mendalam, dan menguasai berbagai jenis query bersarang yang tersedia di MySQL dan Oracle. Di akhir artikel ini, Anda akan memiliki pemahaman solid tentang kapan dan bagaimana menggunakan query bersarang untuk menyelesaikan masalah database sehari-hari dengan lebih efektif dan efisien.

Apa Itu Subquery? Penjelasan Dasar yang Jelas

Query Bersarang (atau sering disebut inner query, nested query, atau subselect) adalah query SQL yang ditulis di dalam query lain yang lebih besar. Query “induk” ini disebut outer query. Query Bersarang dieksekusi terlebih dahulu, dan hasilnya kemudian digunakan oleh outer query untuk melanjutkan pemrosesan data.

Bayangkan seperti rusia doll — ada query di dalam query, dan yang paling dalam dieksekusi duluan. Hasil dari query terdalam dikeluarkan, lalu digunakan oleh query pembungkusnya, dan seterusnya hingga menghasilkan hasil akhir yang Anda inginkan. Konsep ini mirip dengan fungsi dalam pemrograman — Anda bisa memanggil fungsi di dalam fungsi lain untuk membangun logika yang lebih kompleks secara modular dan terstruktur.

Secara umum, query bersarang bisa digunakan di beberapa posisi dalam pernyataan SQL: dalam klausa WHERE untuk memfilter baris, dalam klausa FROM sebagai derived table, dalam klausa SELECT sebagai kolom tambahan, dan dalam klausa HAVING untuk memfilter hasil agregat. Fleksibilitas penempatan inilah yang menjadikan query bersarang sangat powerful.

Sebelum melangkah lebih jauh, pastikan Anda sudah memahami dasar-dasar bahasa basis data, termasuk pengertian DDL dan DML dalam SQL, karena konsep-konsep tersebut menjadi fondasi penting saat menulis query bersarang yang kompleks.

Contoh Dasar Subquery: Menampilkan Nama Kota dari Tabel Lain

Mari kita ambil contoh konkret yang mudah dipahami. Misalkan Anda memiliki dua tabel berikut dalam database perusahaan:

Tabel 1: Identitas (data pegawai)

Nama No_Telp Pekerjaan Kode_Kota
Dwiky0219857348DeveloperJKT01
Ilham0219378474DeveloperJKT01
Wilda0219374556AkuntanBDG01

Tabel 2: Data_Kota (referensi kode kota)

Kode_Kota Nama_Kota
JKT01JAKARTA
BDG01BANDUNG
DPS02DENPASAR

Tabel 1 memiliki data identitas pegawai, tapi hanya menyimpan kode kota (JKT01, BDG01) tanpa nama kota yang lengkap. Untuk menampilkan nama kota yang sesuai, kita perlu mengambil data dari Tabel 2 (Data_Kota). Berikut query dengan subquery yang menyelesaikan masalah ini:

SQL Snippet SQL
SELECT Nama, No_Telp, Pekerjaan, Kode_Kota, ( SELECT T2.Nama_Kota FROM Data_Kota T2 WHERE T1.Kode_Kota = T2.Kode_Kota ) AS Nama_Kota
FROM Identitas T1;

Mari kita bedah query ini baris per baris agar Anda benar-benar memahami apa yang terjadi di dalamnya:

  • SELECT Nama, No_Telp, Pekerjaan, Kode_Kota — Mengambil kolom-kolom dasar dari tabel Identitas (alias T1). Ini adalah bagian outer query yang menentukan kolom apa saja yang akan ditampilkan di hasil akhir.
  • (SELECT T2.Nama_Kota FROM Data_Kota T2 — Ini adalah query bersarang-nya. Ia mengambil kolom Nama_Kota dari tabel Data_Kota yang di-alias sebagai T2.
  • WHERE T1.Kode_Kota = T2.Kode_Kota — Kondisi yang menghubungkan kedua tabel berdasarkan kode kota. Untuk setiap baris di tabel Identitas, query bersarang mencari baris di Data_Kota yang memiliki kode kota yang sama persis.
  • ) AS Nama_Kota — Memberikan nama alias “Nama_Kota” pada kolom hasil query bersarang agar output lebih mudah dibaca dan dipahami.

Hasil yang dihasilkan oleh query tersebut:

Nama No_Telp Pekerjaan Kode_Kota Nama_Kota
Dwiky0219857348DeveloperJKT01JAKARTA
Ilham0219378474DeveloperJKT01JAKARTA
Wilda0219374556AkuntanBDG01BANDUNG

Perhatikan bahwa query bersarang di atas adalah subquery correlated — query bersarang yang merujuk pada kolom dari outer query (T1.Kode_Kota). Query Bersarang semacam ini dieksekusi berulang kali, yaitu sekali untuk setiap baris di outer query, sehingga performanya bisa lambat untuk dataset besar yang memiliki banyak baris.

Jenis-Jenis Subquery yang Perlu Dikuasai

Subquery bisa diklasifikasikan berdasarkan beberapa kriteria. Memahami perbedaan antar jenis subquery ini akan membantu Anda memilih pendekatan yang paling tepat dan efisien untuk setiap situasi.

1. Correlated vs Non-Correlated Query Bersarang

Correlated Query Bersarang adalah query bersarang yang merujuk pada kolom dari outer query. Contohnya adalah contoh di atas, di mana T1.Kode_Kota adalah kolom dari tabel induk. Query Bersarang ini dieksekusi berulang kali — sekali untuk setiap baris di outer query — sehingga bisa menjadi bottleneck performa untuk dataset yang besar dan kompleks.

Non-Correlated Query Bersarang adalah query bersarang yang bisa dijalankan secara independen tanpa merujuk pada outer query. Contoh:

SQL Snippet SQL
SELECT Nama, Pekerjaan
FROM Identitas
WHERE Kode_Kota = ( SELECT Kode_Kota FROM Data_Kota WHERE Nama_Kota = 'JAKARTA'
);

Query di atas bisa dijalankan sendiri — hasilnya adalah “JKT01”. Outer query kemudian menggunakan hasil itu untuk memfilter baris di tabel Identitas. Karena hanya dieksekusi sekali saja, subquery non-correlated umumnya jauh lebih cepat daripada subquery correlated dan lebih disarankan untuk dataset berukuran besar.

2. Scalar Query Bersarang

Scalar subquery mengembalikan satu nilai tunggal — tepatnya satu baris dan satu kolom. Contoh penggunaannya dalam klausa SELECT untuk menambahkan kolom statistik:

SQL Snippet SQL
SELECT Nama, Pekerjaan, ( SELECT COUNT(*) FROM Identitas AS T2 WHERE T2.Pekerjaan = T1.Pekerjaan ) AS Jumlah_Per_Pekerjaan
FROM Identitas T1;

Subquery ini menghitung jumlah pegawai untuk setiap jenis pekerjaan, dan menampilkannya sebagai kolom tambahan di samping nama dan pekerjaan masing-masing. Sangat berguna untuk membuat laporan yang membutuhkan statistik ringkas di samping data detail.

3. Subquery dengan IN dan EXISTS

Klausa IN memeriksa apakah nilai tertentu ada dalam kumpulan hasil query bersarang. Contoh:

SQL Snippet SQL
-- Tampilkan semua pegawai dari kota JAKARTA atau BANDUNG
SELECT Nama, Pekerjaan
FROM Identitas
WHERE Kode_Kota IN ( SELECT Kode_Kota FROM Data_Kota WHERE Nama_Kota IN ('JAKARTA', 'BANDUNG')
);

Sementara EXISTS memeriksa apakah query bersarang menghasilkan minimal satu baris:

SQL Snippet SQL
-- Tampilkan kota yang memiliki minimal satu pegawai
SELECT Nama_Kota
FROM Data_Kota T2
WHERE EXISTS ( SELECT 1 FROM Identitas T1 WHERE T1.Kode_Kota = T2.Kode_Kota
);

EXISTS biasanya lebih cepat dari IN untuk dataset besar karena berhenti segera setelah menemukan kecocokan pertama (short-circuit evaluation), sementara IN harus memproses seluruh hasil query bersarang terlebih dahulu sebelum bisa dibandingkan dengan nilai di outer query.

4. Subquery dalam FROM (Derived Table)

Anda juga bisa menggunakan query bersarang sebagai tabel sementara dalam klausa FROM. Query bersarang seperti ini disebut derived table atau inline view:

SQL Snippet SQL
SELECT Pekerjaan, COUNT(*) AS Jumlah
FROM ( SELECT I.Nama, I.Pekerjaan, DK.Nama_Kota FROM Identitas I INNER JOIN Data_Kota DK ON I.Kode_Kota = DK.Kode_Kota
) AS Gabungan
WHERE Nama_Kota = 'JAKARTA'
GROUP BY Pekerjaan;

Di sini, query bersarang menggabungkan kedua tabel terlebih dahulu, lalu outer query bekerja di atas hasil gabungan tersebut untuk melakukan filtering dan agregasi lebih lanjut. Pendekatan ini sering digunakan untuk query analitik yang membutuhkan beberapa tahap pemrosesan data.

Subquery vs JOIN: Kapan Menggunakan Mana?

Pertanyaan klasik yang sering membingungkan pemula: kapan harus pakai query bersarang dan kapan pakai JOIN? Keduanya bisa menghasilkan output yang sama, tapi ada situasi di mana salah satu lebih tepat dari yang lain berdasarkan kompleksitas dan kebutuhan.

Gunakan JOIN ketika Anda perlu menampilkan kolom dari beberapa tabel dalam satu result set, relasi antar tabel sudah jelas tanpa logika kompleks, dan performa adalah prioritas utama. JOIN umumnya lebih cepat dari query bersarang correlated karena dioptimasi oleh database engine dengan algoritma yang sudah sangat matang.

Gunakan Query Bersarang ketika Anda perlu memfilter data berdasarkan hasil dari query yang kompleks, memerlukan EXISTS atau IN untuk pengecekan keberadaan data secara logis, atau logika yang ingin diekspresikan lebih natural dan mudah dipahami ditulis dalam bentuk query bersarang.

Contoh sederhana menunjukkan bahwa query yang sama bisa ditulis dengan kedua cara:

SQL Snippet SQL
-- Dengan JOIN
SELECT I.Nama, I.Pekerjaan, DK.Nama_Kota
FROM Identitas I
INNER JOIN Data_Kota DK ON I.Kode_Kota = DK.Kode_Kota; -- Dengan Query Bersarang
SELECT Nama, Pekerjaan, (SELECT Nama_Kota FROM Data_Kota T2 WHERE T2.Kode_Kota = T1.Kode_Kota) AS Nama_Kota
FROM Identitas T1;

Keduanya menghasilkan output yang sama, tapi dalam kasus sederhana seperti ini, JOIN umumnya lebih efisien dari segi performa eksekusi di database engine.

Performance Tips: Membuat Subquery MySQL Lebih Cepat

Subquery bisa menjadi bottleneck performa jika tidak digunakan dengan bijak. Berikut tips praktis yang perlu Anda perhatikan agar query bersarang berjalan optimal.

  1. Index kolom yang digunakan dalam WHERE clause — Pastikan kolom yang menjadi kondisi pencocokan (seperti Kode_Kota) memiliki index. Tanpa index, database harus melakukan full table scan untuk setiap eksekusi query bersarang, yang sangat lambat untuk dataset besar.
  2. Hindari query bersarang correlated untuk dataset besar — Karena query bersarang correlated dieksekusi berulang kali untuk setiap baris, pertimbangkan untuk menggantinya dengan JOIN atau derived table untuk dataset yang memiliki ribuan baris atau lebih.
  3. Gunakan EXISTS daripada IN untuk keberadaan data — EXISTS lebih efisien karena berhenti segera setelah menemukan kecocokan pertama, sementara IN harus memproses seluruh hasil query bersarang terlebih dahulu sebelum perbandingan dilakukan.
  4. Gunakan EXPLAIN untuk menganalisis query — Jalankan EXPLAIN sebelum query Anda untuk melihat execution plan dan mengidentifikasi bottleneck potensial yang mungkin tidak terlihat dari kode SQL saja.
SQL Snippet SQL
-- Analisis execution plan untuk melihat performa query
EXPLAIN SELECT Nama, Pekerjaan
FROM Identitas
WHERE Kode_Kota IN ( SELECT Kode_Kota FROM Data_Kota WHERE Nama_Kota = 'JAKARTA'
);

Contoh Praktis: Studi Kasus Subquery MySQL dalam Dunia Nyata

Mari kita lihat penggunaan query bersarang dalam skenario bisnis yang realistis untuk memperkuat pemahaman Anda tentang kapan query bersarang menjadi pilihan terbaik.

Skenario E-commerce: Menampilkan pelanggan yang total belanjanya di atas rata-rata seluruh pelanggan di sistem.

SQL Snippet SQL
-- Query Bersarang non-correlated: hitung rata-rata sekali saja
SELECT customer_name, total_spent
FROM orders
WHERE total_spent > ( SELECT AVG(total_spent) FROM orders
);

Query non-correlated ini hanya dijalankan sekali untuk menghitung rata-rata, kemudian outer query membandingkan setiap baris dengan hasil rata-rata tersebut. Efisien, clean, dan mudah dipahami oleh siapa pun yang membaca kode ini.

Skenario HR: Menampilkan karyawan yang gajinya lebih tinggi dari rata-rata gaji divisi mereka masing-masing.

SQL Snippet SQL
SELECT e.nama, e.divisi, e.gaji
FROM karyawan e
WHERE e.gaji > ( SELECT AVG(e2.gaji) FROM karyawan e2 WHERE e2.divisi = e.divisi -- correlated: referensi ke outer query
);

Di sini query bersarang correlated diperlukan karena rata-rata yang dibandingkan berbeda untuk setiap divisi. Ini adalah contoh tepat di mana query bersarang correlated lebih natural dan expressif dari alternatif JOIN, meskipun dari sisi performa JOIN mungkin lebih cepat untuk dataset besar.

Pitfall yang Sering Terjadi dengan Subquery

Beberapa kesalahan umum yang harus Anda hindari agar query bersarang berjalan dengan benar, efisien, dan tidak menghasilkan output yang menyesatkan.

  • Subquery yang mengembalikan lebih dari satu baris — Jika query bersarang mengembalikan multiple rows, operator seperti = akan error. Gunakan IN, ANY, atau ALL sebagai pengganti, atau pastikan query bersarang hanya menghasilkan satu nilai tunggal dengan agregasi seperti AVG, COUNT, MAX, atau MIN.
  • Lupa mempertimbangkan NULL — Subquery yang hasilnya NULL akan membuat selurang WHERE clause menjadi NULL, bukan true atau false. Pastikan Anda menangani kasus NULL dengan benar menggunakan IS NULL atau IS NOT NULL sesuai kebutuhan logika.
  • Menggunakan query bersarang padahal JOIN lebih tepat — Tidak semua masalah perlu diselesaikan dengan query bersarang. Jika JOIN bisa menyelesaikan masalah dengan lebih efisien dan lebih mudah dibaca, gunakan JOIN sebagai pilihan utama.
  • Nested subquery terlalu dalam — Query bersarang lebih dari dua level akan sangat sulit dibaca, di-debug, dan di-maintain. Pertimbangkan untuk menggunakan temporary table, CTE (Common Table Expressions), atau VIEW sebagai alternatif yang lebih rapi untuk kompleksitas tinggi.

Kesimpulan: Subquery Adalah Alat yang Sangat Powerful

Subquery adalah salah satu fitur paling penting dalam SQL yang memungkinkan Anda menulis query yang lebih kompleks, ekspresif, dan elegan. Dengan memahami berbagai jenis query bersarang — correlated, non-correlated, scalar, EXISTS, IN, dan derived table — serta kapan menggunakannya, Anda akan jauh lebih efektif dan percaya diri dalam bekerja dengan database.

Ingat poin-poin penting berikut ini:

  • Subquery adalah query di dalam query yang dieksekusi terlebih dahulu sebelum outer query memproses hasilnya.
  • Correlated subquery merujuk pada outer query dan dieksekusi berulang kali; non-correlated bisa berjalan mandiri dan umumnya lebih cepat.
  • Gunakan EXISTS untuk pengecekan keberadaan data, IN untuk pencocokan nilai dalam kumpulan data yang sudah diketahui.
  • Selalu pertimbangkan performa — gunakan JOIN jika lebih efisien untuk kasus Anda, terutama untuk dataset yang sangat besar.
  • Gunakan EXPLAIN untuk menganalisis execution plan sebelum mengoptimasi query Anda agar mengetahui bottleneck yang sebenarnya.
  • Hindari query bersarang terlalu dalam — gunakan CTE atau temporary table untuk menangani kompleksitas tinggi dengan lebih rapi.

Hal yang sering ditanyakan seputar Subquery MySQL dan Oracle

Apa yang dimaksud dengan subquery dalam database SQL?

Subquery adalah perintah query SELECT yang berada di dalam query utama (nested query) untuk memfilter atau mengolah data bertingkat.

Apa perbedaan subquery independen dan correlated subquery?

Subquery independen dapat dijalankan terpisah tanpa query luar, sedangkan correlated subquery bergantung pada nilai baris query luar di setiap iterasinya.

Kapan sebaiknya menggunakan JOIN dibanding subquery?

JOIN umumnya memiliki performa eksekusi lebih cepat dan efisien pada database relasional bervolume besar dibanding nested subquery.

Komentar

Memuat komentar…

Tinggalkan Komentar

Alamat email Anda tidak akan dipublikasikan.