GROUP BY, HAVING & FILTER: Laporan per Kelompok

Mengelompokkan baris dan menghitung ringkasan per kelompok dengan GROUP BY, menyaring kelompok dengan HAVING, serta agregat bersyarat dengan FILTER khas PostgreSQL.

Part 14 dari 25 ± 40 menit Gratis

Analogi: GROUP BY itu seperti memilah cucian ke keranjang berbeda (putih, warna, gelap), baru kemudian menghitung isi tiap keranjang. WHERE menyaring baju sebelum dimasukkan keranjang, HAVING menyaring keranjang setelah terisi ("hanya tampilkan keranjang yang beratnya di atas 3 kg").

GROUP BY: satu ringkasan per kelompok

Agregat tanpa GROUP BY meringkas seluruh tabel menjadi satu angka. Dengan GROUP BY, tabel dibagi menjadi kelompok, lalu setiap kelompok diringkas sendiri-sendiri.

SELECT kota, COUNT(*) AS jumlah
FROM pelanggan
GROUP BY kota;
    kota    | jumlah
------------+--------
 Jakarta    |      3
 Bandung    |      2
 Surabaya   |      1
 ...

Analogi: bayangkan kartu pelanggan ditaruh ke dalam kotak per kota. GROUP BY = memilah kartu ke dalam kotak. COUNT = menghitung isi tiap kotak.

Aturan emas GROUP BY

Setiap kolom di SELECT harus salah satu dari dua: (1) ada di GROUP BY, atau (2) dibungkus fungsi agregat. Kalau tidak, PostgreSQL menolak dengan error column "..." must appear in the GROUP BY clause or be used in an aggregate function.

SELECT kategori_id, COUNT(*) AS jumlah_buku, SUM(stok) AS total_stok
FROM buku
GROUP BY kategori_id
ORDER BY kategori_id;

HAVING: menyaring kelompok

WHERE menyaring baris sebelum dikelompokkan. HAVING menyaring kelompok setelah dihitung:

SELECT kategori_id, COUNT(*) AS jumlah_buku
FROM buku
GROUP BY kategori_id
HAVING COUNT(*) > 1;      -- hanya kategori yang punya lebih dari 1 buku
WHEREHAVING
Dikerjakansebelum GROUP BYsesudah GROUP BY
Menyaringbariskelompok
Boleh pakai agregat?tidakya

Urutan lengkap penulisan: SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT.

Mengelompokkan lebih dari satu kolom

SELECT kota, status_kirim, COUNT(*) FROM ... GROUP BY kota, status_kirim;

Mengelompokkan berdasarkan hasil fungsi

Gabungkan dengan DATE_TRUNC untuk laporan bulanan:

SELECT DATE_TRUNC('month', tanggal) AS bulan, COUNT(*) AS jumlah_pesanan
FROM pesanan
GROUP BY DATE_TRUNC('month', tanggal)
ORDER BY bulan;

FILTER: agregat bersyarat (khas PostgreSQL)

Ingin menghitung beberapa kategori sekaligus dalam satu baris? Gunakan FILTER (WHERE ...) pada agregat:

SELECT COUNT(*) FILTER (WHERE status = 'lunas')    AS lunas,
       COUNT(*) FILTER (WHERE status = 'menunggu') AS menunggu,
       COUNT(*) FILTER (WHERE status = 'batal')    AS batal
FROM pesanan;

Lebih rapi daripada SUM(CASE WHEN ... THEN 1 ELSE 0 END) dan sering dipakai untuk dashboard.

Kasus nyata: kategori buku mana yang paling laris dan mana yang stoknya menumpuk

SELECT k.nama AS kategori,
       COUNT(*)          AS jumlah_judul,
       SUM(b.stok)       AS total_stok
FROM buku b
JOIN kategori k ON k.id = b.kategori_id
GROUP BY k.nama
HAVING SUM(b.stok) > 50
ORDER BY total_stok DESC;

Laporan seperti ini membantu tim pembelian memutuskan kategori mana yang perlu dipromosikan agar stoknya berputar.

Kesalahan yang sering terjadi

  • Menaruh kolom di SELECT yang tidak ada di GROUP BY dan bukan agregat. PostgreSQL akan menolaknya.
  • Memakai HAVING untuk syarat baris biasa. Lebih efisien memakai WHERE bila memungkinkan.
  • Lupa bahwa GROUP BY memperlakukan NULL sebagai satu kelompok sendiri.

Praktikkan langsung, gratis

Tulis dan jalankan kode langsung di browser, dapatkan penilaian otomatis. Daftar gratis kapan saja untuk menyimpan progres dan meraih sertifikat.

Coba latihan sekarang, tanpa daftar
Bagikan: WhatsApp Facebook LinkedIn X