GROUP BY SQL Adalah: Cara Kerja + Fungsi Agregat (COUNT, SUM, AVG)
GROUP BY SQL adalah cara meringkas banyak baris jadi satu baris per grup. Pelajari fungsi agregat COUNT, SUM, AVG, MIN, MAX, plus beda WHERE vs HAVING.
Pembuat Hyper Sheets & BelajarWeb.dev
GROUP BY adalah klausa SQL yang meringkas (menggulung) banyak baris yang berbagi nilai sama menjadi satu baris per grup, biasanya dipasangkan dengan fungsi agregat seperti COUNT, SUM, atau AVG untuk menghitung satu nilai ringkasan per grup. Kalau SELECT biasa menjawab “tunjukkan barisnya”, maka GROUP BY menjawab pertanyaan yang lebih menarik: “berapa total penjualan per kota?”, “berapa rata-rata harga per kategori?”, “produk mana yang paling laku?”, pertanyaan yang jawabannya adalah ringkasan, bukan baris mentah.
Kalau kamu sudah nyaman membaca data dengan SELECT tapi bingung bagaimana cara menghitung “per sesuatu”, artikel ini jembatannya. Kita bahas berurutan: cara GROUP BY meruntuhkan baris jadi grup, lima fungsi agregat inti (COUNT/SUM/AVG/MIN/MAX), aturan wajib “setiap kolom non-agregat harus masuk GROUP BY”, beda WHERE vs HAVING, urutan klausa yang benar, sampai menggabungkannya dengan ORDER BY untuk membuat peringkat. Semua contoh memakai satu tabel kecil penjualan supaya gampang diikuti, tinggal bayangkan (atau jalankan) di MySQL, PostgreSQL, atau SQLite.
GROUP BY SQL Adalah… (Cara Meruntuhkan Baris jadi Grup)
GROUP BY <kolom> mengambil semua baris yang punya nilai sama di kolom itu dan meruntuhkannya jadi satu baris hasil per nilai unik. Bayangkan tabel penjualan yang mencatat tiap transaksi: beberapa baris berasal dari kota Jakarta, beberapa dari Bandung, satu dari Surabaya. GROUP BY kota mengumpulkan baris-baris itu berdasarkan kotanya, lalu, dengan bantuan fungsi agregat, memampatkan tiap kelompok jadi satu baris ringkasan.
Kalau kamu sudah paham dasar SELECT ... FROM, GROUP BY adalah langkah lanjutannya (kalau belum, baca dulu SELECT SQL adalah untuk fondasinya). Sintaks dasarnya begini:
SELECT kolom_grup, FUNGSI_AGREGAT(kolom_lain)
FROM tabel
GROUP BY kolom_grup;
Supaya semua contoh bisa kamu jalankan sendiri, kita pakai satu tabel penjualan. Buat dulu skemanya:
CREATE TABLE penjualan (
id INTEGER PRIMARY KEY,
kota TEXT NOT NULL,
produk TEXT NOT NULL,
jumlah INTEGER NOT NULL,
harga INTEGER NOT NULL
);
INSERT INTO penjualan (id, kota, produk, jumlah, harga) VALUES
(1, 'Jakarta', 'Kaos', 3, 75000),
(2, 'Jakarta', 'Topi', 2, 60000),
(3, 'Jakarta', 'Hoodie', 1, 250000),
(4, 'Bandung', 'Kaos', 5, 75000),
(5, 'Bandung', 'Botol', 2, 90000),
(6, 'Surabaya', 'Jaket', 4, 400000);
Sekarang contoh GROUP BY pertama yang nyata: hitung berapa transaksi dan berapa total unit terjual per kota.
SELECT kota, COUNT(*) AS jumlah_transaksi, SUM(jumlah) AS total_unit
FROM penjualan
GROUP BY kota;
Hasilnya tiga baris, satu per kota:
| kota | jumlah_transaksi | total_unit |
|---|---|---|
| Jakarta | 3 | 6 |
| Bandung | 2 | 7 |
| Surabaya | 1 | 4 |
Perhatikan apa yang terjadi: enam baris transaksi runtuh jadi tiga baris ringkasan. Tiga baris Jakarta menjadi satu baris dengan COUNT(*) = 3 (jumlah baris) dan SUM(jumlah) = 6 (3 + 2 + 1). Diagram berikut memperlihatkan proses “runtuh” ini secara visual, perhatikan warna grup, supaya kamu bisa melihat baris mana bergabung ke mana:
| kota | produk | jumlah |
|---|---|---|
| Jakarta | Kaos | 3 |
| Jakarta | Topi | 2 |
| Jakarta | Hoodie | 1 |
| Bandung | Kaos | 5 |
| Bandung | Botol | 2 |
| Surabaya | Jaket | 4 |
| kota | COUNT(*) | SUM(jumlah) |
|---|---|---|
| Jakarta | 3 | 6 |
| Bandung | 2 | 7 |
| Surabaya | 1 | 4 |
COUNT(*) menghitung jumlah baris, SUM(jumlah) menjumlahkan nilainya per grup.Inti yang perlu melekat: GROUP BY menentukan bagaimana baris dikelompokkan, dan fungsi agregat menentukan nilai apa yang dihitung untuk tiap kelompok. Tanpa fungsi agregat, GROUP BY cuma menghapus duplikat; kekuatan sesungguhnya muncul saat keduanya dipakai bersama.
Lima Fungsi Agregat Inti: COUNT, SUM, AVG, MIN, MAX
Fungsi agregat mengambil banyak nilai dari satu grup dan memampatkannya jadi satu nilai, dan lima yang paling sering kamu pakai adalah COUNT, SUM, AVG, MIN, dan MAX. Masing-masing menjawab pertanyaan ringkasan yang berbeda. Ini peta cepatnya:
| Fungsi | Apa yang dihitung per grup | Contoh pertanyaan |
|---|---|---|
COUNT(*) |
Jumlah baris dalam grup | “Berapa transaksi per kota?” |
SUM(kolom) |
Total penjumlahan nilai kolom | “Berapa total unit terjual per kota?” |
AVG(kolom) |
Rata-rata nilai kolom | “Berapa harga rata-rata per kategori?” |
MIN(kolom) |
Nilai terkecil dalam grup | “Berapa harga termurah per kota?” |
MAX(kolom) |
Nilai terbesar dalam grup | “Berapa transaksi terbesar per kota?” |
Contoh yang memakai semuanya sekaligus dalam satu query:
SELECT
kota,
COUNT(*) AS transaksi,
SUM(jumlah) AS total_unit,
AVG(harga) AS harga_rata,
MIN(harga) AS termurah,
MAX(harga) AS termahal
FROM penjualan
GROUP BY kota;
Untuk Jakarta, misalnya: COUNT(*) = 3, SUM(jumlah) = 6, AVG(harga) = rata-rata dari 75000, 60000, 250000, MIN(harga) = 60000, MAX(harga) = 250000. Satu baris ringkasan, lima sudut pandang berbeda tentang grup itu.
Dua catatan penting soal COUNT. Pertama, COUNT(*) menghitung semua baris di grup, termasuk yang berisi NULL. Sedangkan COUNT(kolom) hanya menghitung baris yang kolomnya bukan NULL, berguna kalau kamu ingin tahu “berapa baris yang punya nilai di kolom ini”. Kedua, COUNT(DISTINCT kolom) menghitung berapa banyak nilai unik, misalnya COUNT(DISTINCT produk) per kota menghitung berapa jenis produk berbeda yang terjual di tiap kota.
Aturan Wajib: Setiap Kolom Non-Agregat Harus Ada di GROUP BY
Aturan paling sering bikin pemula tersandung: setiap kolom di SELECT yang tidak dibungkus fungsi agregat wajib muncul di klausa GROUP BY. Alasannya logis kalau dipikir: setelah baris diruntuhkan jadi satu baris per grup, database harus tahu nilai tunggal apa yang ditampilkan untuk tiap kolom. Kolom yang di-GROUP BY jelas nilainya (itu kunci grupnya). Kolom yang diagregat juga jelas (satu nilai hasil hitungan). Tapi kolom lain? Database tidak tahu baris mana yang harus dipilih.
Contoh yang salah:
-- SALAH: produk tidak diagregat dan tidak ada di GROUP BY
SELECT kota, produk, SUM(jumlah)
FROM penjualan
GROUP BY kota;
Jakarta punya tiga produk berbeda (Kaos, Topi, Hoodie) yang runtuh jadi satu baris, jadi produk mana yang harus ditampilkan? Di PostgreSQL dan SQL Server query ini langsung ditolak dengan error. Di MySQL (mode default modern) juga ditolak; di mode lama MySQL diam-diam memilih salah satu nilai secara sembarang, yang justru lebih berbahaya karena hasilnya kelihatan benar padahal acak.
Perbaikannya tergantung maksudmu. Kalau kamu ingin ringkasan per kombinasi kota dan produk, masukkan keduanya ke GROUP BY:
-- BENAR: grup per (kota, produk)
SELECT kota, produk, SUM(jumlah) AS total
FROM penjualan
GROUP BY kota, produk;
Ini menghasilkan satu baris per pasangan unik kota-produk, grupnya jadi lebih halus. GROUP BY dengan beberapa kolom mengelompokkan berdasarkan kombinasi nilai-nilainya, bukan tiap kolom sendiri-sendiri.
WHERE vs HAVING: Menyaring Baris vs Menyaring Grup
Perbedaan WHERE dan HAVING: WHERE menyaring baris sebelum pengelompokan terjadi, sedangkan HAVING menyaring grup setelah agregasi selesai dihitung. Inilah salah satu sumber kebingungan terbesar seputar GROUP BY, tapi begitu kamu paham kapan masing-masing dijalankan, semuanya jadi masuk akal. Kuncinya adalah urutan: WHERE bekerja di data mentah dulu, GROUP BY meruntuhkan yang tersisa, lalu HAVING menyeleksi hasil grup.
WHERE |
HAVING |
|
|---|---|---|
| Menyaring apa? | Baris individual | Grup (hasil agregasi) |
| Kapan dijalankan? | Sebelum GROUP BY |
Setelah GROUP BY |
| Boleh pakai fungsi agregat? | Tidak (SUM(), COUNT() dilarang) |
Ya, justru itu gunanya |
| Contoh | WHERE harga > 50000 |
HAVING SUM(jumlah) > 5 |
Contoh yang memakai keduanya sekaligus: dari transaksi dengan harga di atas 50.000 saja (WHERE), tampilkan kota yang total unitnya lebih dari 5 (HAVING).
SELECT kota, SUM(jumlah) AS total_unit
FROM penjualan
WHERE harga > 50000 -- saring BARIS dulu: buang transaksi murah
GROUP BY kota
HAVING SUM(jumlah) > 5; -- saring GRUP: hanya kota dengan total > 5
Alurnya: WHERE harga > 50000 membuang baris murah sebelum apa pun dikelompokkan. Baris yang lolos lalu diruntuhkan per kota oleh GROUP BY. Baru setelah SUM(jumlah) dihitung per kota, HAVING menyisakan grup yang totalnya lebih dari 5. Menaruh SUM(jumlah) > 5 di WHERE akan error, di titik WHERE dijalankan, agregat belum dihitung sama sekali.
Urutan Klausa yang Benar
Urutan penulisan klausa dalam query dengan GROUP BY itu baku dan tidak boleh ditukar: SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY. Menukar urutannya, misalnya menaruh WHERE setelah GROUP BY, atau ORDER BY sebelum HAVING, akan menghasilkan syntax error. Kabar baiknya, urutan ini juga kira-kira mencerminkan urutan eksekusi logisnya, jadi menghafalnya sekaligus membantumu memahami cara query bekerja.
SELECT kota, SUM(jumlah) AS total -- 5. kolom apa yang ditampilkan
FROM penjualan -- 1. dari tabel mana
WHERE harga > 50000 -- 2. saring baris
GROUP BY kota -- 3. kelompokkan
HAVING SUM(jumlah) > 5 -- 4. saring grup
ORDER BY total DESC; -- 6. urutkan hasil
Menggabungkan GROUP BY dengan ORDER BY untuk Membuat Peringkat
Kombinasi GROUP BY untuk meringkas lalu ORDER BY untuk mengurutkan adalah pola paling produktif untuk menjawab pertanyaan “yang mana paling …”. Setelah tiap grup punya nilai agregat, kamu tinggal mengurutkannya untuk menemukan pemuncaknya. Contoh: kota mana yang total penjualannya (rupiah) paling besar?
SELECT kota, SUM(jumlah * harga) AS total_rupiah
FROM penjualan
GROUP BY kota
ORDER BY total_rupiah DESC;
ORDER BY total_rupiah DESC mengurutkan grup dari yang terbesar ke terkecil, jadi baris pertama adalah kota dengan penjualan tertinggi. Tambahkan LIMIT 1 di akhir dan kamu langsung dapat satu kota juara, pola “top-N per grup” yang muncul di hampir semua laporan bisnis.
Kalau query analitikmu mulai bertingkat, misalnya “ambil 2 produk teratas per kategori”, kamu akan butuh alat yang menyimpan hasil GROUP BY sebagai langkah antara sebelum diurutkan dan disaring lagi. Di situlah CTE SQL adalah masuk: ia membungkus hasil agregasi jadi langkah bernama yang bisa kamu proses lebih lanjut. GROUP BY dan CTE sangat sering berpasangan di dunia kerja.
Kesalahan Umum Saat Memakai GROUP BY
Kesalahan paling sering: menaruh kolom non-agregat di SELECT tanpa memasukkannya ke GROUP BY, dan mencampur WHERE dengan HAVING. Berikut daftar ringkasnya:
- Kolom non-agregat lupa dimasukkan ke
GROUP BY. Error paling umum, sudah dibahas di atas. Setiap kolomSELECTyang tidak diagregat wajib ada diGROUP BY. - Memakai fungsi agregat di
WHERE.WHERE SUM(jumlah) > 5selalu error, karenaWHEREberjalan sebelum agregasi. Pindahkan keHAVING. - Salah urutan klausa.
GROUP BYharus setelahWHEREdan sebelumHAVING/ORDER BY. Menukarnya = syntax error. - Lupa
COUNT(*)vsCOUNT(kolom).COUNT(*)menghitung semua baris;COUNT(kolom)melewati baris yang kolomnyaNULL. Kalau angka countmu terasa kurang, cekNULL.
Klausa mana yang menyaring GRUP berdasarkan hasil agregat (misalnya menyisakan kota dengan SUM(jumlah) > 5), setelah GROUP BY selesai dijalankan?
FAQ Seputar GROUP BY SQL
GROUP BY SQL adalah apa?
GROUP BY adalah klausa SQL yang mengelompokkan baris-baris yang punya nilai sama di satu atau beberapa kolom, lalu meruntuhkan tiap kelompok jadi satu baris ringkasan. Ia hampir selalu dipasangkan dengan fungsi agregat (COUNT, SUM, AVG, MIN, MAX) yang menghitung satu nilai per grup, misalnya total penjualan per kota atau rata-rata harga per kategori.
Apa beda WHERE dan HAVING?
WHERE menyaring baris sebelum pengelompokan dan tidak boleh memakai fungsi agregat. HAVING menyaring grup setelah agregasi selesai dan justru dirancang untuk memakai fungsi agregat, seperti HAVING SUM(jumlah) > 5. Aturan praktisnya: syarat tentang baris asli pakai WHERE, syarat tentang hasil hitungan per grup pakai HAVING.
Kenapa muncul error “must appear in the GROUP BY clause”?
Karena ada kolom di SELECT yang tidak dibungkus fungsi agregat dan juga tidak ada di daftar GROUP BY. Setelah baris diruntuhkan jadi satu per grup, database tidak tahu nilai tunggal apa yang harus ditampilkan untuk kolom itu. Solusinya: tambahkan kolom tersebut ke GROUP BY, atau bungkus dengan fungsi agregat seperti MAX().
Apa beda COUNT(*) dan COUNT(kolom)?
COUNT(*) menghitung semua baris dalam grup, termasuk yang mengandung NULL. COUNT(kolom) hanya menghitung baris yang nilai kolomnya bukan NULL. Untuk menghitung nilai unik, pakai COUNT(DISTINCT kolom).
Langkah Selanjutnya
Kamu sekarang sudah pegang seluruh dasar GROUP BY: cara meruntuhkan baris jadi grup, lima fungsi agregat inti, aturan wajib kolom non-agregat, beda WHERE vs HAVING, urutan klausa, sampai pola GROUP BY + ORDER BY untuk membuat peringkat. Seperti biasa, yang membedakan paham dan bisa adalah latihan, dan GROUP BY termasuk topik yang cepat melekat begitu kamu menulisnya beberapa kali dengan data sungguhan.
Mulai dari lesson GROUP BY di Hyper Sheets yang latihannya langsung dinilai di browser. Kalau kamu merasa fondasi SELECT-nya masih goyang, mundur sebentar ke SELECT SQL adalah; dan begitu query analitikmu mulai bertingkat, lanjutkan ke CTE SQL adalah yang membungkus hasil GROUP BY jadi pipeline langkah demi langkah. Selamat ngoding!