Coba bayangin kamu punya ratusan struk belanja dari toko yang berbeda-beda. Kalau disuruh tahu "bulan ini belanja paling banyak di mana?" — kamu pasti kelompokkan dulu per toko, baru total-in. Nah, itulah persis cara kerja GROUP BY HAVING MySQL. Dua klausa yang mengubah database kamu dari sekadar lemari arsip jadi mesin laporan otomatis. 📊
Di artikel ke-15 dari seri 28 artikel Belajar Query SQL MySQL ini, kita akan kupas tuntas cara kerja GROUP BY dan HAVING — dua klausa yang jadi pasangan tak terpisahkan di dunia query SQL. Kalau di [LINK ARTIKEL SEBELUMNYA] artikel ke-14 kita belajar fungsi agregasi, sekarang kita bawa fungsi itu ke level berikutnya dengan pengelompokan data yang powerful.
Kamu akan paham: kapan pakai GROUP BY, kenapa HAVING beda dari WHERE, dan bagaimana kombinasi keduanya menghasilkan laporan bisnis yang sesungguhnya. Semua lewat studi kasus toko online yang nyata!
FAKTA MENARIK
Hampir setiap dashboard laporan bisnis — dari e-commerce, perbankan, hingga startup teknologi — menggunakan kombinasi GROUP BY dan fungsi agregasi di balik layarnya. Artinya, menguasai klausa ini sama artinya kamu siap kerja di posisi data analyst atau backend developer mana pun!
Sintaks Lengkap & Urutan Eksekusi Query
Sebelum mulai, penting banget kamu pahami urutan eksekusi SQL — karena ini menentukan kenapa HAVING beda dari WHERE. SQL tidak dieksekusi dari atas ke bawah seperti kamu baca; ada urutannya sendiri yang wajib kamu tahu!
SELECT kolom_group, FUNGSI_AGREGASI(kolom) -- ④ Pilih kolom & hitung FROM nama_tabel -- ① Ambil dari tabel WHERE kondisi_baris -- ② Filter baris SEBELUM dikelompokkan GROUP BY kolom_group -- ③ Kelompokkan data HAVING kondisi_agregasi -- ⑤ Filter kelompok SETELAH diagregasi ORDER BY kolom DESC; -- ⑥ Urutkan hasil akhir
🔄 Urutan Eksekusi SQL (bukan urutan penulisan!)
GROUP BY: Mengelompokkan Data Seperti Sortir Surat
Bayangin kamu tukang pos yang punya tumpukan surat — kamu sortir per kelurahan dulu sebelum dikirim. GROUP BY bekerja persis begitu: ia mengambil baris-baris data dan menggabungkan baris yang punya nilai sama di kolom tertentu menjadi satu kelompok, supaya fungsi agregasi bisa dihitung per kelompok.
Kita pakai data tabel pesanan dari toko online kita. Ini datanya:
| id_pesanan | id_pelanggan | kategori | total_harga | status |
|---|---|---|---|---|
| 1 | C001 | Elektronik | 12.500.000 | selesai |
| 2 | C002 | Aksesori | 935.000 | selesai |
| 3 | C001 | Elektronik | 4.200.000 | proses |
| 4 | C003 | Aksesori | 185.000 | selesai |
| 5 | C002 | Elektronik | 750.000 | batal |
| 6 | C003 | Aksesori | 320.000 | selesai |
Contoh 1: Total Penjualan per Kategori
SELECT kategori, COUNT(*) AS jumlah_pesanan, SUM(total_harga) AS total_penjualan FROM pesanan GROUP BY kategori ORDER BY total_penjualan DESC;
📊 Output:
| kategori | jumlah_pesanan | total_penjualan |
|---|---|---|
| Elektronik | 3 | 17.450.000 |
| Aksesori | 3 | 1.440.000 |
Contoh 2: Ringkasan Belanja per Pelanggan
SELECT id_pelanggan, COUNT(*) AS total_pesanan, SUM(total_harga) AS total_belanja, AVG(total_harga) AS rata_rata_belanja FROM pesanan GROUP BY id_pelanggan ORDER BY total_belanja DESC;
📊 Output:
| id_pelanggan | total_pesanan | total_belanja | rata_rata_belanja |
|---|---|---|---|
| C001 | 2 | 16.700.000 | 8.350.000,00 |
| C002 | 2 | 1.685.000 | 842.500,00 |
| C003 | 2 | 505.000 | 252.500,00 |
TIP PRAKTIS
Kolom yang ada di SELECT tapi bukan hasil fungsi agregasi, wajib ada di GROUP BY. Contoh: kalau kamu SELECT kategori, COUNT(*), maka kategori harus masuk ke GROUP BY. Melanggar aturan ini adalah error paling umum pemula!
HAVING: Filter Setelah Pengelompokan dalam GROUP BY HAVING MySQL
Kalau WHERE itu penjaga pintu masuk — menyaring siapa boleh masuk — maka HAVING itu penjaga pintu keluar: menyaring kelompok mana yang boleh tampil di hasil akhir. HAVING hanya bisa bekerja setelah GROUP BY karena ia memfilter berdasarkan hasil agregasi, bukan baris individual.
Perbedaan paling krusial: kamu tidak bisa menulis WHERE SUM(total_harga) > 1000000 karena WHERE belum tahu nilai SUM saat ia dieksekusi. Kamu harus pakai HAVING SUM(total_harga) > 1000000.
Contoh 3: Pelanggan dengan Total Belanja di Atas 1 Juta
SELECT id_pelanggan, COUNT(*) AS total_pesanan, SUM(total_harga) AS total_belanja FROM pesanan GROUP BY id_pelanggan HAVING SUM(total_harga) > 1000000 ORDER BY total_belanja DESC;
📊 Output:
| id_pelanggan | total_pesanan | total_belanja |
|---|---|---|
| C001 ✅ | 2 | 16.700.000 |
| C002 ✅ | 2 | 1.685.000 |
C003 tidak muncul karena total belanjanya (505.000) tidak memenuhi kondisi HAVING.
PERINGATAN — Jangan Tukar WHERE dan HAVING!
Menulis WHERE SUM(total_harga) > 1000000 akan menghasilkan error karena WHERE tidak bisa memfilter hasil fungsi agregasi. Selalu gunakan HAVING untuk filter berbasis hasil agregasi, dan WHERE untuk filter berbasis nilai kolom biasa.
Kombinasi WHERE + GROUP BY + HAVING: Trio Paling Powerful
Di sinilah kekuatan GROUP BY HAVING MySQL benar-benar terasa — ketika kamu kombinasikan ketiganya. WHERE menyaring data mentah dulu, GROUP BY mengelompokkannya, lalu HAVING memfilter hasilnya. Ini adalah pola yang paling sering muncul di laporan bisnis nyata.
Contoh 4: Laporan Penjualan Selesai per Kategori (Hanya yang > 500rb)
-- WHERE: filter hanya pesanan 'selesai' -- GROUP BY: kelompokkan per kategori -- HAVING: tampilkan hanya yg total > 500.000 SELECT kategori, COUNT(*) AS jumlah_transaksi, SUM(total_harga) AS total_penjualan FROM pesanan WHERE status = 'selesai' GROUP BY kategori HAVING SUM(total_harga) > 500000 ORDER BY total_penjualan DESC;
📊 Output:
| kategori | jumlah_transaksi | total_penjualan |
|---|---|---|
| Elektronik | 1 | 12.500.000 |
| Aksesori | 3 | 1.440.000 |
TIP PRAKTIS
Kamu bisa menggunakan alias dari SELECT di dalam HAVING di beberapa versi MySQL. Contoh: HAVING total_penjualan > 500000 setelah mendefinisikan SUM(...) AS total_penjualan. Ini membuat query lebih bersih dan mudah dibaca!
🚀 Panduan Praktikum Step-by-Step
Ikuti langkah-langkah ini untuk langsung praktik di MySQL-mu sendiri dari nol:
Siapkan Tabel dan Data
Buat tabel pesanan dan isi dengan data sampel di atas. Gunakan tabel dari artikel sebelumnya jika sudah ada.
CREATE TABLE pesanan ( id_pesanan INT PRIMARY KEY AUTO_INCREMENT, id_pelanggan VARCHAR(10), kategori VARCHAR(50), total_harga DECIMAL(15,2), status VARCHAR(20) );
Insert Data Sampel
Masukkan 6 baris data pesanan persis seperti tabel di atas untuk hasil yang konsisten.
INSERT INTO pesanan (id_pelanggan, kategori, total_harga, status) VALUES ('C001', 'Elektronik', 12500000, 'selesai'), ('C002', 'Aksesori', 935000, 'selesai'), ('C001', 'Elektronik', 4200000, 'proses'), ('C003', 'Aksesori', 185000, 'selesai'), ('C002', 'Elektronik', 750000, 'batal'), ('C003', 'Aksesori', 320000, 'selesai');
Coba GROUP BY Dasar
Mulai dengan query sederhana untuk menghitung jumlah pesanan per status. Amati output-nya.
SELECT status, COUNT(*) AS jumlah FROM pesanan GROUP BY status;
Tambahkan HAVING untuk Filter
Sekarang tambahkan HAVING untuk hanya menampilkan status yang jumlah pesanannya lebih dari 1. Bandingkan hasilnya dengan dan tanpa HAVING.
SELECT status, COUNT(*) AS jumlah FROM pesanan GROUP BY status HAVING COUNT(*) > 1;
📋 WHERE vs HAVING: Tabel Perbandingan Lengkap
| Aspek | WHERE | HAVING |
|---|---|---|
| Waktu eksekusi | Sebelum GROUP BY (awal) | Setelah GROUP BY (akhir) |
| Memfilter | Baris individual | Kelompok (hasil GROUP BY) |
| Bisa pakai fungsi agregasi? | ❌ Tidak | ✅ Ya |
| Butuh GROUP BY? | ❌ Tidak | ✅ Ya (biasanya) |
| Contoh kondisi | WHERE status = 'selesai' | HAVING SUM(harga) > 1000000 |
| Performa | ⚡ Lebih cepat | 🐢 Lebih lambat (jalankan setelah agregasi) |
💡 Tips & Insight dari Lapangan
💡 TIP #1 — Filter Awal Pakai WHERE untuk Performa Lebih Baik
Kalau bisa filter dengan WHERE, lakukan itu dulu sebelum GROUP BY. Karena WHERE menyaring baris lebih awal, GROUP BY punya lebih sedikit data untuk diproses. Ini bisa drastis mempercepat query di tabel yang punya jutaan baris. Kombinasikan keduanya: WHERE status='selesai' GROUP BY kategori HAVING SUM(...)>x.
💡 TIP #2 — GROUP BY Bisa Pakai Beberapa Kolom Sekaligus
Kamu bisa kelompokkan berdasarkan lebih dari satu kolom. Contoh: GROUP BY id_pelanggan, kategori akan menghasilkan kelompok per kombinasi pelanggan + kategori — cocok untuk laporan detail!
SELECT id_pelanggan, kategori, SUM(total_harga) AS total FROM pesanan GROUP BY id_pelanggan, kategori;
🔥 INSIGHT TRAINER
Di dunia kerja nyata, pola WHERE + GROUP BY + HAVING adalah backbone dari hampir semua query laporan. Kalau kamu sudah bisa menggabungkan ketiganya dengan lancar, kamu sudah level "Data Analyst Junior" yang siap pakai. Langkah berikutnya? Belajar JOIN untuk menggabungkan beberapa tabel!
✅ Kesimpulan
Selamat! Kamu baru saja naik level dalam penguasaan GROUP BY HAVING MySQL! Ini poin-poin kunci yang perlu kamu simpan:
- → GROUP BY mengelompokkan baris-baris dengan nilai kolom yang sama menjadi satu kelompok
- → HAVING memfilter kelompok berdasarkan hasil fungsi agregasi — tidak bisa digantikan WHERE
- → WHERE dieksekusi sebelum GROUP BY, HAVING sesudahnya — urutan ini tidak bisa ditukar
- → Kolom non-agregasi di SELECT wajib ada di GROUP BY
- → GROUP BY bisa pakai banyak kolom untuk granularitas laporan yang lebih detail
Ingat, seorang developer yang bisa menghasilkan laporan analitik dengan query yang bersih dan efisien adalah aset berharga di mana pun ia bekerja. Dan kamu sudah satu langkah lebih dekat ke sana! 🚀
💬 Ada query GROUP BY yang bikin kamu bingung? Tanya di kolom komentar, kita bahas bareng! Share artikel ini ke teman-teman yang sedang belajar SQL — biar makin banyak yang naik level. Dan jangan lupa bookmark halaman ini sebagai referensi! 🔖
Artikel Selanjutnya — 16 dari 28
JOINS di MySQL: Menggabungkan Data dari Beberapa Tabel
Pelajari INNER JOIN, LEFT JOIN, RIGHT JOIN, dan FULL JOIN untuk menggabungkan tabel-tabel yang saling berkaitan — kunci dari query database yang sesungguhnya!