Fungsi agregasi (aggregate function) membaca sekumpulan baris dan mengembalikan satu nilai ringkas untuk baris-baris tersebut, misalnya banyaknya baris, total, atau rata-rata. Topik ini membahas COUNT, SUM, AVG, MIN, MAX, dan GROUP_CONCAT pada tabel peminjaman yang memuat nilai NULL, lengkap dengan keluaran nyata dari setiap query. Perlakuan setiap fungsi terhadap NULL menjadi fokus utama karena kesalahan membaca perlakuan tersebut sering menghasilkan angka laporan yang keliru. Setiap blok SQL pada modul ini memuat pembuatan tabelnya sendiri, sehingga dapat dijalankan langsung dengan sqlite3 :memory: tanpa berkas basis data.
Menghitung baris dengan COUNT#
COUNT menghitung banyaknya baris atau nilai, dan bentuk argumennya menentukan apa yang dihitung. COUNT(*) menghitung seluruh baris tanpa memandang isi kolomnya, sedangkan COUNT(kolom) hanya menghitung baris yang kolom tersebut tidak bernilai NULL. COUNT(DISTINCT kolom) menambahkan satu lapis lagi dengan hanya menghitung nilai berbeda yang tidak NULL. Ketiganya dibuktikan pada tabel peminjaman berikut yang memuat delapan baris, dengan tiga di antaranya berdenda NULL.
CREATE TABLE anggota (
id INTEGER PRIMARY KEY,
nama TEXT NOT NULL
);
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
denda REAL
);
INSERT INTO anggota (id, nama) VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam, denda) VALUES
(1, 1, 1, '2026-03-02', 0.5),
(2, 1, 3, '2026-03-04', 1.0),
(3, 2, 2, '2026-03-05', NULL),
(4, 3, 1, '2026-03-09', 0.5),
(5, 3, 4, '2026-03-12', 2.0),
(6, 4, 5, '2026-03-16', NULL),
(7, 5, 3, '2026-03-19', 1.0),
(8, 5, 6, '2026-03-23', NULL);
SELECT COUNT(*) FROM peminjaman;
SELECT COUNT(denda) FROM peminjaman;
SELECT COUNT(DISTINCT id_anggota) FROM peminjaman;8
5
5Bandingkan ketiga angka pada keluaran di atas. COUNT(*) menghasilkan 8 karena seluruh baris dihitung, termasuk baris yang dendanya NULL. COUNT(denda) menghasilkan 5 karena tiga baris dikeluarkan dari perhitungan, dan COUNT(DISTINCT id_anggota) menghasilkan 5 karena hanya lima anggota yang pernah meminjam. Anggota bernama Farhan tidak pernah muncul pada tabel peminjaman, sehingga Farhan tidak ikut terhitung pada dua bentuk terakhir. Pemilihan bentuk yang keliru adalah sumber angka laporan yang tidak cocok dengan harapan.
SUM dan AVG#
SUM menjumlahkan nilai yang bukan NULL pada satu kolom, sedangkan AVG menghitung rata-ratanya. Kedua fungsi mengabaikan baris yang bernilai NULL sepenuhnya, sehingga hasilnya dihitung hanya dari nilai yang benar-benar tercatat. Query berikut menampilkan total dan rata-rata denda pada seluruh peminjaman.
CREATE TABLE anggota (
id INTEGER PRIMARY KEY,
nama TEXT NOT NULL
);
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
denda REAL
);
INSERT INTO anggota (id, nama) VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam, denda) VALUES
(1, 1, 1, '2026-03-02', 0.5),
(2, 1, 3, '2026-03-04', 1.0),
(3, 2, 2, '2026-03-05', NULL),
(4, 3, 1, '2026-03-09', 0.5),
(5, 3, 4, '2026-03-12', 2.0),
(6, 4, 5, '2026-03-16', NULL),
(7, 5, 3, '2026-03-19', 1.0),
(8, 5, 6, '2026-03-23', NULL);
SELECT SUM(denda), AVG(denda) FROM peminjaman;5.0|1.0Total 5.0 diperoleh dari lima nilai denda yang ada, yaitu 0.5, 1.0, 0.5, 2.0, dan 1.0. Rata-rata 1.0 didapat karena pembaginya adalah COUNT(denda) yang bernilai 5, bukan COUNT(*) yang bernilai 8. Perbedaan itu terlihat lebih jelas ketika rata-rata dibandingkan dengan pembagian manual terhadap seluruh baris.
CREATE TABLE anggota (
id INTEGER PRIMARY KEY,
nama TEXT NOT NULL
);
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
denda REAL
);
INSERT INTO anggota (id, nama) VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam, denda) VALUES
(1, 1, 1, '2026-03-02', 0.5),
(2, 1, 3, '2026-03-04', 1.0),
(3, 2, 2, '2026-03-05', NULL),
(4, 3, 1, '2026-03-09', 0.5),
(5, 3, 4, '2026-03-12', 2.0),
(6, 4, 5, '2026-03-16', NULL),
(7, 5, 3, '2026-03-19', 1.0),
(8, 5, 6, '2026-03-23', NULL);
SELECT AVG(denda), SUM(denda) / COUNT(*) FROM peminjaman;1.0|0.625Kolom kedua pada keluaran di atas adalah SUM(denda) / COUNT(*), yaitu 5.0 dibagi 8 yang menghasilkan 0.625. Angka ini menjawab pertanyaan yang berbeda, yakni rata-rata denda per peminjaman termasuk peminjaman tanpa denda, sedangkan AVG(denda) menjawab rata-rata per peminjaman yang didenda. Tentukan dahulu pertanyaan yang ingin dijawab, kemudian pilih bentuk perhitungannya.
Input kosong dan fungsi COALESCE#
Pada input yang tidak memiliki satu pun nilai non-NULL, perilaku antarfungsi terpecah. COUNT tetap mengembalikan angka 0, sedangkan SUM, AVG, MIN, dan MAX mengembalikan NULL karena tidak ada nilai yang bisa diolah. Anggota Farhan tidak memiliki baris peminjaman sama sekali, sehingga query dengan syarat id_anggota = 6 mengolah input kosong.
CREATE TABLE anggota (
id INTEGER PRIMARY KEY,
nama TEXT NOT NULL
);
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
denda REAL
);
INSERT INTO anggota (id, nama) VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam, denda) VALUES
(1, 1, 1, '2026-03-02', 0.5),
(2, 1, 3, '2026-03-04', 1.0),
(3, 2, 2, '2026-03-05', NULL),
(4, 3, 1, '2026-03-09', 0.5),
(5, 3, 4, '2026-03-12', 2.0),
(6, 4, 5, '2026-03-16', NULL),
(7, 5, 3, '2026-03-19', 1.0),
(8, 5, 6, '2026-03-23', NULL);
SELECT COUNT(*), SUM(denda), AVG(denda) FROM peminjaman WHERE id_anggota = 6;
SELECT COALESCE(SUM(denda), 0.0) FROM peminjaman WHERE id_anggota = 6;0||
0.0Baris pertama keluaran di atas berbunyi 0||, yaitu angka 0 diikuti dua kolom kosong yang merupakan tampilan NULL pada mode default CLI. Artinya COUNT menghasilkan 0, sedangkan SUM dan AVG menghasilkan NULL. Baris kedua membungkus SUM dengan COALESCE, yaitu fungsi yang mengembalikan argumen pertama yang bukan NULL, sehingga hasil kosong tampil sebagai 0.0.
MIN dan MAX#
MIN dan MAX mencari nilai terkecil dan terbesar dari kolom yang diberikan. Keduanya mengabaikan NULL saat membandingkan, sehingga nilai NULL tidak pernah keluar sebagai hasil kecuali tidak ada nilai lain sama sekali. Query berikut mencari rentang denda pada seluruh peminjaman, lalu pada peminjaman milik Budi yang dendanya tidak pernah tercatat.
CREATE TABLE anggota (
id INTEGER PRIMARY KEY,
nama TEXT NOT NULL
);
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
denda REAL
);
INSERT INTO anggota (id, nama) VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam, denda) VALUES
(1, 1, 1, '2026-03-02', 0.5),
(2, 1, 3, '2026-03-04', 1.0),
(3, 2, 2, '2026-03-05', NULL),
(4, 3, 1, '2026-03-09', 0.5),
(5, 3, 4, '2026-03-12', 2.0),
(6, 4, 5, '2026-03-16', NULL),
(7, 5, 3, '2026-03-19', 1.0),
(8, 5, 6, '2026-03-23', NULL);
SELECT MIN(denda), MAX(denda) FROM peminjaman;
SELECT MIN(denda), MAX(denda) FROM peminjaman WHERE id_anggota = 2;0.5|2.0
|Baris pertama menunjukkan denda terkecil 0.5 dan terbesar 2.0. Baris kedua berupa satu tanda | saja karena kedua kolomnya NULL, yakni Budi hanya memiliki satu peminjaman yang dendanya tidak tercatat. Apabila MIN dan MAX dijalankan pada input yang tidak memuat satu pun baris, keduanya juga mengembalikan NULL dengan pola yang sama seperti SUM dan AVG.
GROUP_CONCAT sebagai pelengkap#
GROUP_CONCAT menggabungkan nilai non-NULL dari satu kolom menjadi satu string yang dipisah koma. Fungsi ini berguna untuk melihat isi sebuah grup secara sekilas tanpa query tambahan. Nilai NULL diabaikan, dan urutan penggabungannya tidak dijamin, sehingga gunakan fungsi ini untuk pemeriksaan cepat, bukan untuk laporan yang urutannya penting.
CREATE TABLE anggota (
id INTEGER PRIMARY KEY,
nama TEXT NOT NULL
);
CREATE TABLE peminjaman (
id INTEGER PRIMARY KEY,
id_anggota INTEGER,
id_buku INTEGER,
tanggal_pinjam TEXT,
denda REAL
);
INSERT INTO anggota (id, nama) VALUES
(1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
(4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman (id, id_anggota, id_buku, tanggal_pinjam, denda) VALUES
(1, 1, 1, '2026-03-02', 0.5),
(2, 1, 3, '2026-03-04', 1.0),
(3, 2, 2, '2026-03-05', NULL),
(4, 3, 1, '2026-03-09', 0.5),
(5, 3, 4, '2026-03-12', 2.0),
(6, 4, 5, '2026-03-16', NULL),
(7, 5, 3, '2026-03-19', 1.0),
(8, 5, 6, '2026-03-23', NULL);
SELECT GROUP_CONCAT(nama) FROM anggota;
SELECT GROUP_CONCAT(DISTINCT id_anggota) FROM peminjaman;
SELECT GROUP_CONCAT(denda) FROM peminjaman;Ali,Budi,Citra,Dewi,Eka,Farhan
1,2,3,4,5
0.5,1.0,0.5,2.0,1.0Keluaran pertama menggabungkan seluruh nama anggota, sedangkan keluaran kedua memakai DISTINCT sehingga setiap id anggota hanya muncul sekali. Keluaran ketiga menunjukkan bahwa lima nilai denda ikut digabung, sedangkan tiga nilai NULL dilewati tanpa meninggalkan jejak koma. Pembatas lain dapat dinyatakan sebagai argumen kedua, misalnya GROUP_CONCAT(nama, ' | ').
Tabel ringkas perlakuan NULL#
Tabel berikut merangkum perlakuan setiap fungsi terhadap NULL pada input biasa dan pada input kosong. Jadikan tabel ini patokan cepat sebelum menafsirkan hasil agregasi yang memuat kolom opsional, karena satu perbedaan perlakuan saja dapat mengubah makna angka laporan.
| Fungsi | Baris dengan NULL | Input kosong tanpa baris |
|---|---|---|
COUNT(*) | tetap dihitung | menghasilkan 0 |
COUNT(kolom) | diabaikan | menghasilkan 0 |
COUNT(DISTINCT kolom) | diabaikan | menghasilkan 0 |
SUM(kolom) | diabaikan | menghasilkan NULL |
AVG(kolom) | diabaikan | menghasilkan NULL |
MIN(kolom) dan MAX(kolom) | diabaikan | menghasilkan NULL |
GROUP_CONCAT(kolom) | diabaikan | menghasilkan NULL |
Satu pola umum terlihat dari tabel di atas. Bentuk yang menghitung baris selalu mengembalikan angka, sedangkan bentuk yang mengolah nilai mengembalikan NULL ketika tidak ada nilai untuk diolah. Karena itu, laporan yang membungkus SUM atau AVG sebaiknya dilengkapi COALESCE apabila angka 0 lebih bermakna daripada kolom kosong.
Kesalahan umum#
Mengira COUNT(denda) menghitung seluruh baris. Penyebabnya adalah kebiasaan membaca COUNT sebagai penghitung baris tanpa memandang bentuk argumennya, padahal argumen kolom menyaring baris yang NULL. Perbaikannya adalah menggunakan COUNT(*) bila yang diinginkan memang banyaknya baris, dan menyimpan COUNT(kolom) untuk menghitung nilai yang tercatat.
Membagi SUM dengan COUNT(*) tanpa sengaja. Pola ini menghasilkan rata-rata yang terlalu kecil karena pembaginya ikut menghitung baris NULL, seperti terlihat pada angka 0.625 di bagian SUM dan AVG. Gunakan AVG atau jadikan COUNT(kolom) sebagai pembagi bila maksudnya adalah rata-rata nilai yang tercatat.
Menyajikan SUM yang bernilai NULL apa adanya pada laporan. Pembaca laporan biasanya menafsirkan sel kosong sebagai data yang hilang, bukan sebagai tidak ada transaksi. Bungkus hasilnya dengan COALESCE(SUM(denda), 0.0) ketika nol adalah makna yang benar.
Ringkasan#
COUNT(*)menghitung seluruh baris,COUNT(kolom)menghitung nilai non-NULL, danCOUNT(DISTINCT kolom)menghitung nilai non-NULL yang berbeda.- SUM dan AVG mengabaikan baris NULL, dan AVG membagi dengan banyaknya nilai tercatat, bukan dengan
COUNT(*). - Pada input kosong, COUNT menghasilkan 0, sedangkan SUM, AVG, MIN, MAX, dan GROUP_CONCAT menghasilkan NULL.
- COALESCE mengubah hasil NULL menjadi nilai pengganti seperti 0.0 agar laporan tidak menyajikan sel kosong.
Referensi#
- Built-in Aggregate Functions — SQLite — Dokumentasi resmi COUNT, SUM, AVG, MIN, MAX, dan GROUP_CONCAT termasuk perlakuannya terhadap NULL.
- SELECT — SQLite — Dokumentasi klausa SELECT yang memuat aturan pemakaian fungsi agregasi di dalam query.