Belajar dengan membaca secara berurutan

GROUP BY dan HAVING — Agregat per Grup

Pelajari SQL GROUP BY dan HAVING: agregat per grup, menyaring grup dengan HAVING, dan perbedaannya dengan WHERE — dipraktikkan pada data nilai CSV, langsung di browser kamu.

Data yang dipakai di artikel ini — tabel score

Di artikel sebelumnya kamu menciutkan seluruh tabel menjadi satu nilai. `GROUP BY` di artikel ini (pengelompokan — mengumpulkan baris yang punya nilai sama ke dalam satu grup) menjalankan agregat per grup dan mengembalikan satu baris agregat per grup. Selain itu, `HAVING` memungkinkan kamu menyaring hasil agregat, seperti "hanya grup yang rata-ratanya 80 atau lebih".

Subjeknya adalah tabel score yang sama seperti sebelumnya (30 baris = 10 orang × 3 mata pelajaran). Mengelompokkan berdasarkan name menghasilkan 10 grup, dan mengelompokkan berdasarkan subject menghasilkan 3 grup.

Sebelum masuk ke latihan, lihat dulu definisi kolom dan contoh data pada tabel score.

① Gunakan PRAGMA table_info(score); untuk memeriksa nama kolom, tipe, dan kunci primer.

② Gunakan SELECT * FROM score LIMIT 5; untuk melihat pratinjau 5 baris data pertama.

SQL Editor

Jalankan query untuk melihat hasil

GROUP BY — mengagregasi per grup

Saat kamu menulis GROUP BY kolom, baris yang punya nilai sama di kolom itu dikumpulkan ke dalam satu grup, dan fungsi agregat dihitung sekali per grup. Dengan SELECT name, AVG(score) FROM score GROUP BY name;, 3 baris dengan nama yang sama (satu per mata pelajaran) membentuk satu grup, dan kamu mendapat satu baris rata-rata per nama. Satu-satunya "kolom biasa" yang bisa kamu taruh di SELECT adalah kolom yang disebut di `GROUP BY`; kolom lain harus dibungkus dalam fungsi agregat (karena nilainya tidak tunggal di dalam satu grup).

GROUP BY name
Baris asli (30)GROUP BY nameAgregat grupAlice Math 92Alice English 85Alice Science 78Grup AliceAlice / AVG 85.0
3 baris dengan nama yang sama (satu per mata pelajaran) menciut menjadi satu grup, dan AVG(score) dihitung per grup. Dengan 10 orang, hasilnya 10 baris.
-- Jumlah / rata-rata / nilai tertinggi per mata pelajaran (3 grup per subject)
SELECT
  subject,
  COUNT(*)             AS row_count,
  ROUND(AVG(score), 1) AS avg_score,
  MAX(score)           AS top_score
FROM score
GROUP BY subject;

Bayangkan kebutuhan "saya ingin daftar rata-rata nilai setiap siswa". (Jalankan dengan benar maka penjelasan akan muncul.)

① Kelompokkan tabel score berdasarkan nama.

② Untuk setiap grup, ambil nama sebagai name, jumlah mata pelajaran yang ditempuh sebagai subjects, dan rata-rata nilai sebagai avg_score, dalam urutan itu.

③ Bulatkan rata-rata ke 2 angka desimal. Urutan tidak ditentukan.

SQL Editor

Jalankan query untuk melihat hasil

HAVING — menyaring hasil agregat

Setelah agregat grup, kadang kamu ingin menyaring berdasarkan nilai agregat, seperti "hanya tampilkan grup yang rata-ratanya 80 atau lebih". Kamu tidak bisa melakukan ini dengan WHERE. WHERE adalah klausa yang menilai baris individual sebelum pengelompokan, jadi agregat grup seperti AVG(score) belum dihitung. Di situlah `HAVING` berperan. HAVING ditulis setelah GROUP BY dan menilai kondisinya terhadap hasil agregat grup. Menulis HAVING AVG(score) >= 80 hanya menyisakan grup yang rata-ratanya 80 atau lebih.

Setelah GROUP BY, saring dengan HAVING
score 30 barisGROUP BY name(10 grup)HAVINGAVG(score) >= 80Tersisa 6 grupDinilai setelah agregasi
GROUP BY mengagregasi menjadi 10 grup, lalu HAVING AVG(score) >= 80 menilai grup yang sudah diagregasi dan hanya menyisakan yang memenuhi kondisi.
-- Hanya nama yang rata-ratanya melebihi 85 (HAVING menilai nilai agregat)
SELECT
  name,
  ROUND(AVG(score), 2) AS avg_score
FROM score
GROUP BY name
HAVING AVG(score) > 85;

Bayangkan kebutuhan "saya ingin mendaftar hanya siswa berprestasi dengan rata-rata nilai 80 atau lebih".

① Kelompokkan tabel score berdasarkan nama.

② Untuk setiap grup, ambil nama sebagai name dan rata-rata nilai sebagai avg_score (dibulatkan ke 2 angka desimal).

③ Sisakan hanya grup yang rata-rata nilainya 80 atau lebih. Urutan tidak ditentukan.

SQL Editor

Jalankan query untuk melihat hasil

WHERE vs. HAVING — menyaring baris, atau menyaring grup

WHERE dan HAVING keduanya penyaring, tetapi mereka bekerja pada waktu yang berbeda. WHERE menilai baris individual dan membuangnya sebelum pengelompokan. HAVING menilai per grup dan membuangnya setelah pengelompokan dan agregasi. Urutan eksekusinya adalah FROMWHEREGROUP BYHAVINGSELECTORDER BY.

Kamu juga bisa memakai keduanya sekaligus. Dalam kasus itu alurnya adalah "persempit baris target dengan WHERE, lalu kelompokkan, lalu saring hasil agregat dengan HAVING". Misalnya, untuk mendapat "orang yang rata-rata per namanya 80 atau lebih, hanya mempertimbangkan Math dan English", kamu mempersempit baris dengan WHERE subject IN ('Math','English') dan mempersempit grup dengan HAVING AVG(score) >= 80.

WHERE menyaring baris, HAVING menyaring grup
Baris asli (30)Baris yang gagaldibuang di siniWHEREmenilai barispada kolom biasaGROUP BY namemengelompokkan barisHAVINGmenilai gruppada nilai agregatGrup yang gagaldibuang di siniGrup yang tersisaadalah hasilnyaSemua baris masukBaris dibuangHanya baris tersisaSetelah agregasiGrup dibuangGrup tersisa
WHERE menilai baris pada kolom biasa dan membuangnya sebelum pengelompokan, sedangkan HAVING menilai grup pada nilai agregat (AVG, dll.) dan membuangnya setelah pengelompokan. Inti pentingnya adalah di mana hal-hal dibuang. Contoh: WHERE subject='Math' (menyaring baris) dan HAVING AVG(score)>=80 (menyaring grup).
-- Pakai WHERE dan HAVING bersama
-- Kecualikan Science, sisakan hanya nama yang rata-ratanya 80 atau lebih
SELECT
  name,
  ROUND(AVG(score), 2) AS avg_two
FROM score
WHERE subject <> 'Science'
GROUP BY name
HAVING AVG(score) >= 80;

Bayangkan kebutuhan "hanya mempertimbangkan dua mata pelajaran Math dan English, saya ingin orang yang rata-rata per namanya 85 atau lebih".

① Dari tabel score, sisakan hanya baris yang subject-nya Math atau English (Science di luar cakupan).

② Kelompokkan baris yang tersisa berdasarkan nama dan ambil nama sebagai name dan rata-rata nilai dua mata pelajaran sebagai avg_two (dibulatkan ke 2 angka desimal).

③ Lalu sisakan hanya grup yang rata-ratanya 85 atau lebih. Urutan tidak ditentukan.

SQL Editor

Jalankan query untuk melihat hasil

Bayangkan kebutuhan "saya ingin menampilkan rata-rata per mata pelajaran sebagai peringkat, tertinggi dulu".

① Kelompokkan tabel score berdasarkan mata pelajaran.

② Untuk setiap grup, ambil mata pelajaran sebagai subject, jumlah siswa yang menempuhnya sebagai students, dan rata-rata nilai sebagai avg_score (dibulatkan ke 2 angka desimal), dalam urutan itu.

③ Urutkan mereka dari rata-rata tertinggi ke terendah.

SQL Editor

Jalankan query untuk melihat hasil
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Saat kamu menentukan GROUP BY name, berapa banyak baris hasilnya (tabel score / 10 nama berbeda)?

Soal 2Saat kamu ingin mengekstrak "hanya orang yang rata-rata per namanya 80 atau lebih", kondisi 80 atau lebih masuk ke klausa mana?

Soal 3Pernyataan mana yang dengan benar menjelaskan perbedaan antara WHERE dan HAVING?