Halo Sobat Data! Pas kita kerja bareng database relasional, kita nggak cuma sekadar nampilin data baris demi baris. Kadang kita butuh angka ringkasan (summary metrics) buat bantu ambil keputusan bisnis. Contohnya: Berapa total transaksi bulan ini? Berapa rata-rata belanja tiap pengguna? Atau kategori produk mana yang paling laku?
Nah, buat menjawab pertanyaan-pertanyaan itu, SQL punya Fungsi Agregasi yang dipasangkan dengan klausa GROUP BY dan HAVING.
1. Apa Itu Agregasi, GROUP BY, dan HAVING?
1. Fungsi Agregasi (Aggregate Functions)
Fungsi agregasi adalah fungsi yang mengambil banyak baris data (multiple rows) dari suatu kolom, lalu mengolahnya jadi satu nilai ringkasan saja.
Beberapa fungsi agregasi yang paling sering dipakai:
SUM(): Menghitung total jumlah numerik.AVG(): Menghitung nilai rata-rata.COUNT(): Menghitung jumlah baris data.MIN()/MAX(): Mencari nilai terkecil atau terbesar.
2. Klausa GROUP BY
GROUP BY dipakai buat mengelompokkan baris-baris data yang punya nilai sama di kolom tertentu, sehingga tampil sebagai baris ringkasan (summary rows).
3. Klausa HAVING
HAVING adalah filter khusus buat menyaring hasil kelompok data yang sudah dihitung oleh fungsi agregasi dan GROUP BY.
2. Kenapa dan Kapan Kita Pakai?
Kenapa Harus Pakai GROUP BY?
Kalau kamu pakai SUM() atau AVG() tanpa GROUP BY, database cuma bakal memberikan satu baris total dari seluruh data di tabel. Kalau kamu mau memecah total tersebut berdasarkan kategori tertentu (misalnya total penjualan per kota, per status, atau per kategori produk), kamu wajib menambahkan GROUP BY.
Bedanya HAVING sama WHERE Apa?
Ini pertanyaan yang sering banget ditanyakan pemula: “Kenapa harus ada HAVING kalau sudah ada WHERE ?”
WHERE: Menyaring data mentah sebelum proses pengelompokan dilakukan. Klausa ini nggak bisa memproses fungsi agregasi.HAVING: Menyaring hasil kelompok data setelah proses pengelompokan dan kalkulasi agregasi selesai.
| Perbandingan | WHERE | HAVING |
| Fungsi Utama | Menyaring baris data mentah (raw row). | Menyaring hasil kelompok agregasi. |
| Pakai Agregasi? | Nggak bisa pakai SUM(), AVG(), dll. | Bisa / Wajib pakai fungsi agregasi. |
| Urutan Kerja | Dijalankan sebelum GROUP BY. | Dijalankan setelah GROUP BY. |
3. Langkah Praktis dan Contoh Query
Yuk, langsung kita praktikkan pakai skenario database toko online!
Langkah 1 : Buat Database & Tabel Sampel (DDL & DML)
Sebelum mulai coba-coba kueri, bikin dulu database toko_online_db beserta 4 tabel dan data uji cobanya di MySQL, PostgreSQL, atau SQL Server milik kamu.
Query SQL
-- 1. Membuat & Menggunakan Database
CREATE DATABASE IF NOT EXISTS toko_online_db;
USE toko_online_db;
-- 2. Membersihkan Tabel Lama (jika ada)
DROP TABLE IF EXISTS order_items;
DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS products;
DROP TABLE IF EXISTS customers;
-- 3. Membuat Tabel Customers
CREATE TABLE customers (
customer_id INT PRIMARY KEY AUTO_INCREMENT,
customer_name VARCHAR(100) NOT NULL,
city VARCHAR(50) NOT NULL
);
-- 4. Membuat Tabel Products
CREATE TABLE products (
product_id INT PRIMARY KEY AUTO_INCREMENT,
product_name VARCHAR(100) NOT NULL,
category VARCHAR(50) NOT NULL
);
-- 5. Membuat Tabel Orders
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT NOT NULL,
order_date DATE NOT NULL,
status VARCHAR(20) NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
-- 6. Membuat Tabel Order Items
CREATE TABLE order_items (
item_id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
price DECIMAL(12, 2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(order_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
-- 7. Insert Data Sampel Customers
INSERT INTO customers (customer_id, customer_name, city) VALUES
(1, 'Budi Santoso', 'Jakarta'),
(2, 'Siti Aminah', 'Bandung'),
(3, 'Dewi Lestari', 'Surabaya'),
(4, 'Eko Prasetyo', 'Medan'),
(5, 'Rina Wijaya', 'Jakarta');
-- 8. Insert Data Sampel Products
INSERT INTO products (product_id, product_name, category) VALUES
(101, 'Laptop Gaming X', 'Elektronik'),
(102, 'Smartphone Pro', 'Elektronik'),
(103, 'Headset Wireless', 'Aksoris'),
(104, 'Mouse Ergonomis', 'Aksesoris'),
(105, 'Kemeja Casual', 'Pakaian'),
(106, 'Celana Chino', 'Pakaian'),
(107, 'Kopi Arabika 500g', 'Makanan & Minuman');
-- 9. Insert Data Sampel Orders
INSERT INTO orders (order_id, customer_id, order_date, status) VALUES
(1001, 1, '2024-01-10', 'Completed'),
(1002, 2, '2024-01-12', 'Completed'),
(1003, 1, '2024-01-15', 'Cancelled'),
(1004, 3, '2024-01-18', 'Completed'),
(1005, 4, '2024-01-20', 'Completed'),
(1006, 5, '2024-01-22', 'Pending'),
(1007, 2, '2024-01-25', 'Completed');
-- 10. Insert Data Sampel Order Items
INSERT INTO order_items (item_id, order_id, product_id, quantity, price) VALUES
(1, 1001, 101, 1, 12000000.00),
(2, 1001, 104, 2, 250000.00),
(3, 1002, 103, 5, 500000.00),
(4, 1002, 105, 10, 150000.00),
(5, 1003, 102, 1, 7000000.00),
(6, 1004, 105, 25, 150000.00),
(7, 1004, 106, 20, 200000.00),
(8, 1004, 107, 15, 80000.00),
(9, 1005, 102, 2, 7000000.00),
(10, 1005, 107, 10, 80000.00),
(11, 1006, 104, 30, 250000.00),
(12, 1007, 103, 20, 500000.00),
(13, 1007, 106, 15, 200000.00);Berikut adalah gambaran bentuk tabel beserta isi data sampel setelah script SQL di atas dijalankan:
1. Tabel customers (Data Pelanggan)

2. Tabel products (Data Produk)

3. Tabel orders (Data Transaksi Utama)

4. Tabel order_items (Rincian Barang per Transaksi)

Langkah 2 : Mengelompokkan Data Pakai GROUP BY
Studi Kasus: Kita mau tahu berapa total produk terjual dan total pendapatan untuk tiap-tiap kategori produk.
Query SQL:
SELECT
p.category AS kategori_produk,
SUM(oi.quantity) AS total_unit_terjual,
SUM(oi.quantity * oi.price) AS total_pendapatan
FROM order_items oi
JOIN products p ON oi.product_id = p.product_id
GROUP BY p.category;
Output :

Penjelasan :
- Hasil Kelompok: Data berhasil dikelompokkan per kategori. Elektronik meraih pendapatan tertinggi (Rp 33 juta dari 4 unit), sedangkan Pakaian paling laris secara kuantitas (70 unit).
- Cara Kerja SQL: SQL mengumpulkan baris dengan nama kategori yang sama persis, lalu
SUM(quantity)menjumlahkan unit barang, danSUM(quantity * price)mengalikan harga per baris sebelum menjumlahkan total pendapatannya.
Langkah 3 : Menyaring Hasil Agregasi Pakai HAVING
Studi Kasus: Manajemen cuma mau lihat kategori produk yang total pendapatannya di atas Rp 10.000.000.
Query SQL:
SELECT
p.category AS kategori_produk,
SUM(oi.quantity * oi.price) AS total_pendapatan
FROM order_items oi
JOIN products p ON oi.product_id = p.product_id
GROUP BY p.category
HAVING SUM(oi.quantity * oi.price) > 10000000;Output :

Penjelasan :
- Hasil Filter HAVING: Output hanya menampilkan 3 kategori—Elektronik (Rp 33 juta), Aksoris (Rp 12,5 juta), dan Pakaian (Rp 12,25 juta)—karena total pendapatannya berhasil menembus angka di atas Rp 10.000.000.
- Data yang Tereliminasi: Kategori Aksesoris (Rp 8 juta) dan Makanan & Minuman (Rp 2 juta) otomatis dibuang dari tabel hasil karena nilainya tidak memenuhi kriteria
> 10000000. - Fungsi Utama HADIRNYA HAVING: Klausa
HAVINGbekerja menyaring data setelah pengelompokan dan perhitungan total pendapatan selesai dilakukan olehGROUP BY.
Langkah 4 : Gabungan WHERE, GROUP BY, dan HAVING (Kasus Studi Nyata)
Studi Kasus Real-World: Tampilkan daftar kategori produk dengan ketentuan:
- Cuma menghitung transaksi yang statusnya ‘Completed‘.
- Total produk yang terjual minimal 50 unit.
- Urutkan dari penjualan unit terbanyak.
Query SQL:
SELECT
p.category AS kategori_produk,
SUM(oi.quantity) AS total_unit_terjual,
SUM(oi.quantity * oi.price) AS total_pendapatan
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
WHERE o.status = 'Completed' -- 1. Filter transaksi mentah
GROUP BY p.category -- 2. Kelompokkan per kategori
HAVING SUM(oi.quantity) >= 50 -- 3. Filter kelompok dengan total unit >= 50
ORDER BY total_unit_terjual DESC; -- 4. Urutkan hasil akhirOutput :

Penjelasan:
- Hasil Filter Berlapis: Output hanya menyisakan 1 baris, yaitu kategori Pakaian (70 unit terjual, pendapatan Rp 12,25 juta), karena hanya kategori ini yang lolos semua syarat kombinasi kueri.
- Peran Kombinasi Klausa:
WHERE: Membuang data transaksi mentah yang tidak berstatus ‘Completed’ (transaksi Pending dan Cancelled diabaikan).HAVING: Menyaring hasil kelompok yang total penjualan unitnya minimal 50 (>= 50). Kategori lain seperti Aksesoris (35 unit) otomatis tersenggol keluar.ORDER BY: Mengurutkan tampilan akhir berdasarkan jumlah unit terbanyak secara menurun (descending).
Kesimpulan
Klausa GROUP BY dan HAVING merupakan komponen penting dalam SQL untuk menyusun laporan analitis. Pemahaman utama dalam penggunaannya terletak pada perbedaan alur evaluasi data:
WHERE: Digunakan untuk mengeliminasi baris data mentah (raw data) sebelum proses kalkulasi atau pengelompokan dilakukan.HAVING: Digunakan untuk menyaring kelompok data berdasarkan hasil perhitungan agregasi (sepertiSUM,COUNT, atauAVG).
Dengan mengombinasikan JOIN, WHERE, GROUP BY, dan HAVING secara tepat, kueri yang dihasilkan tidak hanya presisi secara logika bisnis, tetapi juga lebih efisien dari segi performa database.
Penulis : Abryan Yoga Pratama
