stdsquare²
🎓 Kelas
stdsquare / materi / slides / pertemuan-14
Tema
Japan
Arcade
Dark Retro
Font
‹ Daftar slide Pertemuan 14: Subquery bersarang dan kondisi logika kompleks
Prodi Bisnis Digital · FEB UNDIP

Sistem Database

Pertemuan 14: Subquery Bersarang dan Kondisi Logika Kompleks

Menulis query di dalam query untuk menjawab pertanyaan bisnis berlapis — dari "siapa pelanggan di atas rata-rata" sampai "kombinasi syarat majemuk" pada data toko daring.

RPS minggu 15 · 2×50 menit
Bagian 1 dari 3
Mengenal Subquery
Apa itu query di dalam query, kapan dipakai, dan bagaimana database mengeksekusinya.

Tujuan Pembelajaran Hari Ini

SUB-CPMK
4
Kompetensi yang dilatih
Menulis subquery pada klausa WHERE, SELECT, dan FROM; membedakan subquery biasa dengan correlated subquery; menyusun kondisi logika majemuk (AND/OR/NOT) yang benar; dan mengenali jebakan umum (NULL, subquery multi-baris).
SETELAH PERTEMUAN INI
Bisa
Menjawab pertanyaan bisnis berlapis
Anda dapat mengubah pertanyaan seperti "pelanggan mana yang belanjanya di atas rata-rata kotanya sendiri" menjadi satu query SQL yang benar dan efisien, tanpa menghitung manual di luar database.

Dari JOIN (P13) ke Subquery: Kenapa Perlu?

Pertemuan lalu Anda belajar JOIN untuk menggabungkan tabel secara horizontal (menambah kolom dari tabel lain). Subquery menjawab kebutuhan berbeda: menjawab pertanyaan yang butuh hasil query lain sebagai pembanding.

JOIN — gabung tabel

"Tampilkan nama pelanggan beserta detail transaksinya."

Kolom dari 2 tabel digabung jadi 1 baris hasil.

Subquery — pembanding bertingkat

"Tampilkan pelanggan yang transaksinya lebih besar dari rata-rata semua transaksi."

Butuh hasil query lain (rata-rata) sebagai syarat.

Keduanya sering dikombinasikan dalam praktik: JOIN untuk menggabung tabel, subquery untuk syarat bertingkat di dalamnya.

Anatomi Subquery: Query di Dalam Query

Subquery (kueri bersarang) adalah perintah SELECT yang diletakkan di dalam perintah SQL lain, biasanya diapit tanda kurung. Query di bagian dalam disebut inner query, query pembungkusnya disebut outer query.

OUTER QUERYSELECT nama FROM pelangganWHERE total_belanja > (INNER QUERY (subquery)SELECT AVG(total_belanja) FROM transaksi);① dieksekusi lebih dulu
Aturan emas: inner query selalu dieksekusi lebih dulu, hasilnya baru dipakai outer query.

Subquery di WHERE — Nilai Tunggal

Kalau inner query mengembalikan satu nilai saja (scalar), subquery bisa dipakai dengan operator perbandingan biasa: =, >, <, >=, <=.

SELECT nama, kota
FROM pelanggan
WHERE total_belanja > (
  SELECT AVG(total_belanja) FROM transaksi
);
Jika inner query ternyata mengembalikan lebih dari satu baris, database akan menolak dengan error — subquery scalar wajib menghasilkan tepat satu nilai.

Subquery dengan IN / NOT IN

Kalau inner query mengembalikan banyak baris (satu kolom), gunakan IN atau NOT IN untuk mencocokkan salah satu dari daftar tersebut.

IN — cocok salah satu
SELECT nama FROM pelanggan
WHERE customer_id IN (
  SELECT customer_id FROM transaksi
  WHERE kategori = 'Elektronik'
);
NOT IN — hati-hati NULL
SELECT nama FROM pelanggan
WHERE customer_id NOT IN (
  SELECT customer_id FROM transaksi
  WHERE customer_id IS NOT NULL
);
Jebakan klasik: jika daftar hasil subquery mengandung satu saja nilai NULL (kosong/tak diketahui), seluruh NOT IN akan mengembalikan hasil kosong tanpa error — solusinya selalu saring IS NOT NULL di dalam subquery.

Hitung dari Nol #1 — AVG Lewat Subquery Scalar

Tabel transaksi Toko Beriman punya 5 baris. Kita hitung manual apa yang dilakukan subquery AVG, lalu bandingkan tiap transaksi terhadapnya.

LangkahPerhitunganNilai
1. Jumlahkan seluruh total (5 transaksi)150.000 + 220.000 + 95.000 + 310.000 + 175.000Rp 950.000
2. Hitung jumlah baris (COUNT)5 transaksi5
3. Bagi total dengan jumlah baris (AVG)950.000 ÷ 5Rp 190.000
4. Filter outer query: total > 190.000220.000 & 310.000 memenuhi syarat2 transaksi lolos
HASIL AKHIR SUBQUERY
Rp 190.000
Nilai AVG yang dipakai outer query sebagai batas filter
Bagian 2 dari 3
Correlated Subquery & Logika Kompleks
Subquery yang berjalan ulang untuk tiap baris, plus cara menyusun syarat majemuk yang benar.

EXISTS / NOT EXISTS — Beda dengan IN

EXISTS hanya mengecek apakah subquery menghasilkan baris atau tidak (benar/salah), tanpa peduli isinya — sering lebih efisien daripada IN untuk tabel besar.

SELECT nama FROM pelanggan p
WHERE EXISTS (
  SELECT 1 FROM transaksi t
  WHERE t.customer_id = p.customer_id
    AND t.kategori = 'Elektronik'
);
Perhatikan t.customer_id = p.customer_id — subquery ini merujuk tabel di luar dirinya (p). Ini ciri khas correlated subquery, dibahas slide berikutnya.
SELECT 1 dipakai sebagai kebiasaan umum — isi kolomnya tidak penting, karena EXISTS hanya cek ada/tidaknya baris.

Correlated Subquery: Jalan Ulang Tiap Baris

Subquery biasa dijalankan satu kali untuk seluruh query. Correlated subquery merujuk kolom dari outer query, sehingga dijalankan ulang untuk setiap baris outer query.

Baris 1: Ani (kota Semarang)Baris 2: Budi (kota Solo)Baris 3: Citra (kota Semarang)Subquery jalan utk Semarang → cek AVG kota ituSubquery jalan utk Solo → cek AVG kota ituSubquery jalan LAGI utk Semarang → dipanggil ulang

Hitung dari Nol #2 — Correlated Subquery

Cari pelanggan yang jumlah transaksinya di atas rata-rata jumlah transaksi seluruh pelanggan. Data: A=4, B=2, C=6, D=3 transaksi.

LangkahPerhitunganNilai
1. Jumlahkan transaksi seluruh pelanggan4 + 2 + 6 + 315 transaksi
2. Hitung jumlah pelangganA, B, C, D4 pelanggan
3. Rata-rata transaksi per pelanggan (AVG)15 ÷ 43,75 transaksi
4. Correlated subquery cek tiap pelanggan > 3,75A:4✓ B:2✗ C:6✓ D:3✗2 pelanggan lolos
PELANGGAN LOLOS FILTER
A & C
Jumlah transaksi mereka melebihi rata-rata 3,75

Coba Sendiri: Jalankan Subquery Scalar dan Correlated Bertahap

Klik langkah demi langkah untuk melihat subquery scalar dieksekusi dulu, lalu bandingkan dengan correlated subquery yang berjalan ulang tiap baris.

Subquery di SELECT dan FROM

Di SELECT — kolom scalar
SELECT nama,
  (SELECT AVG(total) FROM transaksi) AS avg_semua
FROM pelanggan;

Subquery jadi kolom tambahan di tiap baris hasil.

Di FROM — derived table
SELECT kota, jml
FROM (
  SELECT kota, COUNT(*) AS jml
  FROM pelanggan GROUP BY kota
) AS ringkasan_kota
WHERE jml > 5;

Subquery jadi tabel sementara (derived table) yang bisa di-SELECT lagi.

Kondisi Logika Kompleks: AND / OR / NOT

Ketika WHERE punya lebih dari satu syarat, urutan evaluasi (precedence) mengikuti aturan: NOT dulu, lalu AND, baru OR. Tanpa tanda kurung, hasil bisa tidak sesuai maksud Anda.

Tanpa kurung — ambigu
WHERE kota = 'Semarang'
   OR kota = 'Solo'
  AND total > 200000;

Dibaca database sebagai: Semarang (apa saja) ATAU (Solo DAN total>200rb) — bukan maksud Anda!

Dengan kurung — jelas
WHERE (kota = 'Semarang'
    OR kota = 'Solo')
  AND total > 200000;

Sekarang jelas: (Semarang ATAU Solo) DAN total>200rb.

Kebiasaan wajib: setiap kali menggabung OR dengan AND, selalu bungkus dengan tanda kurung sesuai maksud Anda — jangan andalkan urutan default.

CASE WHEN — Logika Kondisional Bertingkat

CASE WHEN adalah "if-else" di dalam SQL — mengubah nilai kolom jadi kategori berdasarkan beberapa syarat berurutan.

SELECT nama,
  CASE
    WHEN total > 300000 THEN 'Pelanggan Premium'
    WHEN total > 150000 THEN 'Pelanggan Reguler'
    ELSE 'Pelanggan Baru'
  END AS segmen
FROM transaksi;
Syarat dicek berurutan dari atas ke bawah; begitu satu WHEN terpenuhi, sisanya diabaikan. ELSE menampung yang tidak cocok syarat mana pun.
Bagian 3 dari 3
Praktik & Kesalahan Umum
Menghindari jebakan klasik, lalu mempraktikkan semuanya pada satu studi kasus utuh.

Kesalahan Umum yang Wajib Dihindari

NULL di NOT IN
Satu nilai NULL di daftar subquery membuat seluruh NOT IN kosong senyap. Selalu tambahkan IS NOT NULL di dalam subquery.
Subquery scalar >1 baris
Operator =, > hanya untuk satu nilai. Kalau inner query bisa mengembalikan banyak baris, ganti jadi IN atau tambah LIMIT 1 dengan urutan yang jelas.
Correlated subquery lambat
Dijalankan ulang tiap baris — pada tabel besar (jutaan baris) bisa jadi lambat. Pertimbangkan JOIN + GROUP BY sebagai alternatif jika performa jadi masalah.
Kebiasaan aman: uji dulu inner query sendiri (jalankan terpisah) sebelum menempelkannya ke outer query.

Studi Kasus: Toko Beriman (Tokopedia)

Tabel pelanggan(customer_id, nama, kota) dan transaksi(order_id, customer_id, kategori, total). Kerjakan tiga soal berikut secara berkelompok (15 menit):

Soal Latihan
  • Soal 1: Tampilkan pelanggan yang total belanjanya di atas rata-rata seluruh transaksi (subquery scalar di WHERE).
  • Soal 2: Tampilkan pelanggan yang pernah bertransaksi kategori "Fashion" DAN berasal dari kota Semarang ATAU Solo (subquery IN/EXISTS + kurung logika yang benar).
  • Soal 3: Tampilkan pelanggan yang jumlah transaksinya di atas rata-rata jumlah transaksi kotanya sendiri (correlated subquery).
Kumpulkan hasil query (screenshot + penjelasan logika) sebagai bahan diskusi 10 menit terakhir sesi.

Rangkuman: Cheat Sheet Subquery

BentukKapan DipakaiContoh Operator
Scalar di WHEREBandingkan dengan satu nilai (AVG, MAX, MIN)=, >, <
IN / NOT INCocokkan terhadap daftar hasil subqueryIN, NOT IN (+ IS NOT NULL)
EXISTS / NOT EXISTSCek ada/tidaknya baris, sering lebih cepatEXISTS
Correlated subquerySyarat bergantung pada baris outer querymerujuk tabel outer di dalam WHERE
SELECT / FROMKolom tambahan, atau tabel sementara (derived table)alias wajib untuk subquery di FROM

Penutup: Menuju UAS

Minggu Depan

Review komprehensif seluruh materi Sistem Database (P1–P14) sebagai persiapan UAS — dari ER Diagram, normalisasi, DDL/DML, JOIN, hingga subquery hari ini.

TUGAS SEBELUM PERTEMUAN BERIKUT
3 Query
Selesaikan Soal Latihan (slide 18)
Kumpulkan ketiga query beserta penjelasan singkat logikanya melalui platform kelas, paling lambat sebelum sesi review minggu depan.