Subquery: Query di Dalam Query
Memakai hasil sebuah query sebagai bahan query lain: subquery di WHERE (skalar dan IN), EXISTS, dan di FROM, serta kapan memilih subquery atau JOIN.
Pertanyaan yang butuh dua langkah
"Produk apa saja yang harganya di atas rata-rata?" Untuk menjawabnya kamu harus (1) menghitung rata-rata harga, lalu (2) mencari produk di atas angka itu. Tanpa subquery, kamu harus menjalankan dua query dan menyalin angkanya secara manual. Dengan subquery, keduanya digabung:
SELECT nama, harga
FROM produk
WHERE harga > (SELECT AVG(harga) FROM produk);
Query di dalam kurung dikerjakan lebih dulu, hasilnya (24.307,69) dipakai oleh query luar. Rata-rata harga selalu mengikuti data terbaru — tidak perlu ditulis manual.
Jenis subquery
1. Subquery skalar: menghasilkan satu nilai
Bisa dipakai di mana saja ada nilai tunggal: WHERE, SELECT, bahkan SET pada UPDATE.
SELECT nama, harga,
harga - (SELECT AVG(harga) FROM produk) AS selisih_dari_rata
FROM produk;
2. Subquery daftar dengan IN
-- produk yang pernah dipesan
SELECT nama FROM produk
WHERE id IN (SELECT produk_id FROM detail_pesanan);
-- produk yang BELUM pernah dipesan
SELECT nama FROM produk
WHERE id NOT IN (SELECT produk_id FROM detail_pesanan);
Jebakan NOT IN + NULL: jika subquery menghasilkan satu saja nilai NULL, NOT IN tidak mengembalikan baris apa pun (logika tiga nilai!). Untuk "yang tidak ada", NOT EXISTS atau LEFT JOIN ... IS NULL lebih aman.
3. EXISTS: "apakah ada?"
SELECT pl.nama
FROM pelanggan pl
WHERE EXISTS (SELECT 1 FROM pesanan p WHERE p.pelanggan_id = pl.id);
Subquery ini berkorelasi: ia merujuk pl.id dari query luar, jadi dievaluasi untuk setiap pelanggan. EXISTS hanya peduli "ada atau tidak", dan berhenti begitu menemukan satu baris, sehingga biasanya efisien. Kebalikannya: NOT EXISTS.
4. Subquery di FROM (tabel turunan)
SELECT AVG(jumlah_pesanan) AS rata_pesanan_per_pelanggan
FROM (
SELECT pelanggan_id, COUNT(*) AS jumlah_pesanan
FROM pesanan
GROUP BY pelanggan_id
) AS ringkasan;
Hasil subquery diperlakukan sebagai tabel sementara, dan wajib diberi alias (AS ringkasan). Berguna untuk agregat dua tingkat: rata-rata dari jumlah, dan sejenisnya.
Subquery atau JOIN?
| Pakai subquery bila... | Pakai JOIN bila... |
|---|---|
| Hanya perlu menyaring berdasar hasil query lain | Perlu menampilkan kolom dari tabel lain |
| Membandingkan dengan nilai agregat (rata-rata, maksimum) | Menggabungkan banyak tabel untuk laporan |
Pertanyaan "ada/tidak ada" (EXISTS) | Performa jadi prioritas dan datanya besar |
Banyak soal bisa dijawab dengan keduanya. Pilih yang paling mudah dibaca, lalu ukur kecepatannya bila datanya besar.