Inilah yang menjadikan SQL tampak mengerikan sekaligus mengagumkan, karena dalam kueri kita masih bisa memasukkan kueri lagi. Istilah kerennya
subquery. Subkueri bisa diletakkan pada klausa FROM, WHERE, dan HAVING. Kita bahas subkueri pada klausa WHERE dulu (klausa HAVING mirip kan dengan WHERE

).
Nah, contoh kasus kita tadi, mencari tanggal penjualan tertinggi, bisa ditulis ulang seperti ini:
Pilih no faktur dan tanggalnya
dari tabel faktur penjualan
yang kuantitas penjualannya tertinggi.
Bisa terjemahkan ke SQL?
SELECT NoFaktur, Tanggal
FROM FakturPenjualan
WHERE TotalQty = ...
Waduh, lanjutannya bagaimana? Tahu kan cara mendapatkan nilai penjualan maksimum?
SELECT Max(TotalQty)
FROM FakturPenjualan;
Nah, klausa WHERE kita jadi seperti ini deh:
WHERE TotalQty =
(SELECT Max(TotalQty)
FROM FakturPenjualan)
SQL kita selengkapnya jadi seperti ini:
SELECT NoFaktur, Tanggal
FROM FakturPenjualan
WHERE TotalQty =
(SELECT Max(TotalQty)
FROM FakturPenjualan);
Dapat deh

Nah, dari sini, kita dapat format umum untuk Min() dan Max(), boleh dihapalkan kalau perlu:
SELECT kolom_lain, kolom_pembanding_untuk_min_max
FROM tabel
WHERE kolom_pembanding_untuk_min_max = (SELECT Min|Max(kolom_pembanding_untuk_min_max) FROM tabel);
Sekarang kita coba kasus yang lebih kompleks. Coba cari barang apa saja yang sudah terjual lebih dari 10. SQL-nya?
SELECT NamaBarang
FROM Barang
WHERE KodeBarang IN
(
SELECT KodeBarang
FROM DetailFakturPenjualan
GROUP BY KodeBarang
HAVING Sum(Qty) > 10
);
Nah apa tuh operator IN? Kok nggak pakai = saja? Pakai = memang bisa, tapi kueri itu akan error andaikan subkueri kita menghasilkan lebih dari satu data (row). Menggunakan operator IN berarti kita meminta KodeBarang
ada di dalam hasil subkueri kita. Untuk membuktikan, silakan ganti IN dengan = dan ganti salah satu detail faktur penjualan sehingga ada barang lain yang terjual lebih dari 10.
Sebetulnya masih ada dua lagi operator untuk subkueri, yaitu ANY dan ALL, tapi ini agak jarang dipakai. Sementara gunakan IN saja dulu

Bingung? Nii satu contoh lagi. Coba tambahkan dulu satu penjualan baru (isi sembarang) dengan pembelian 5 buah pulpen. Hanya saja, karena toko stash sedang ada diskon 10%, harganya menjadi 1800. Nah, sekarang, kita tahu ada beberapa barang yang harga jualnya tidak sesuai dengan harga di tabel Barang. Dari kumpulan barang itu, cari yang total selisih harganya paling besar, karena stash ingin tahu barang mana yang paling bikin dia rugi dan seberapa besar kerugiannya

Kalau kesulitan membangun sebuah subkueri utuh, pecah-pecah saja menjadi beberapa bagian yang mudah dibuat lebih dulu. Misalnya seperti ini:
1. Cari dulu barang dan selisih total untuk tiap barang:
SELECT b.KodeBarang, Sum(d.Qty * b.HargaBarang - d.Subtotal) AS TotalSelisihHarga
FROM Barang b, DetailFakturPenjualan d
WHERE b.KodeBarang = d.KodeBarang
GROUP BY b.KodeBarang;
Ternyata operasi matematika bisa juga ya dilakukan

misalkan saja aku anggap hasilnya ini A.
2. Ambil nilai maksimumnya. Masih ingat ya cara ambil nilai maksimum?
SELECT b.NamaBarang, A.TotalSelisihHarga
FROM Barang b, A
WHERE b.KodeBarang = A.KodeBarang AND A.TotalSelisihHarga =
(SELECT Max(TotalSelisihHarga) FROM A)
Beberapa yang teliti mungkin bertanya-tanya, TotalSelisihHarga itu kan harusnya fungsi agregat, wong pakai Sum(). Kenapa syaratnya bisa ditaruh klausa WHERE??? Well, karena subkueri kita diletakkan di klausa FROM, hasil subkueri itu dianggap sebagai tabel baru. Dia tidak peduli apakah kolom itu hasil fungsi agregat atau tidak. Makanya kita bisa taruh di klausa WHERE

Jadi deh

tinggal mengganti A di klausa FROM dengan hasil dari nomor 1. Jadinya memang panjang:
SELECT b.NamaBarang, a.TotalSelisihHarga
FROM Barang b,
(
SELECT b.KodeBarang, Sum(d.Qty * b.HargaBarang - d.Subtotal) AS TotalSelisihHarga
FROM Barang b, DetailFakturPenjualan d
WHERE b.KodeBarang = d.KodeBarang
GROUP BY b.KodeBarang
) AS a
WHERE b.KodeBarang = a.KodeBarang AND a.TotalSelisihHarga =
(
SELECT Max(TotalSelisihHarga) FROM
(
SELECT b.KodeBarang, Sum(d.Qty * b.HargaBarang - d.Subtotal) AS TotalSelisihHarga
FROM Barang b, DetailFakturPenjualan d
WHERE b.KodeBarang = d.KodeBarang
GROUP BY b.KodeBarang
)
);
Ini sekaligus memberikan contoh bahwa subkueri bisa juga diletakkan di klausa FROM, dan hasilnya dianggap sebagai sebuah tabel tersendiri.
Beberapa manajer basis data mengizinkan kita langsung menggunakan tabel baru hasil subkueri dalam klausa FROM, jadi kueri berikut sah:
SELECT b.NamaBarang, A.TotalSelisihHarga
FROM Barang b,
(
SELECT b.KodeBarang, Sum(d.Qty * b.HargaBarang - d.Subtotal) AS TotalSelisihHarga
FROM Barang b, DetailFakturPenjualan d
WHERE b.KodeBarang = d.KodeBarang
GROUP BY b.KodeBarang
) AS A
WHERE b.KodeBarang = A.KodeBarang AND A.TotalSelisihHarga = (SELECT Max(TotalSelisihHarga) FROM A);
Nanti aku konfirmasikan ulang apa benar kueri ini bisa dijalankan. Di Access pasti error

Terlihat mengerikan? Mungkin, tapi dengan banyak latihan, subkueri bisa jadi menyenangkan

Sekarang, coba isi data lebih banyak lagi, dan coba cari tanggal berapa yang memiliki total nilai transaksi di bawah rata-rata harian
