Fungsi Agregasi

COUNT, SUM, AVG, MIN, dan MAX beserta perlakuannya terhadap NULL.

Daftar isi

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.

sql Tiga bentuk COUNT pada data yang memuat 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;
text Keluaran
8
5
5

Bandingkan 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.

sql Total dan rata-rata denda
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;
text Keluaran
5.0|1.0

Total 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.

sql AVG dibandingkan pembagian manual
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;
text Keluaran
1.0|0.625

Kolom 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.

sql Agregasi pada input kosong milik Farhan
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;
text Keluaran
0||
0.0

Baris 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.

sql Rentang denda pada seluruh data dan pada grup Budi
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;
text Keluaran
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.

sql Penggabungan nilai menjadi satu string
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;
text Keluaran
Ali,Budi,Citra,Dewi,Eka,Farhan
1,2,3,4,5
0.5,1.0,0.5,2.0,1.0

Keluaran 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.

FungsiBaris dengan NULLInput kosong tanpa baris
COUNT(*)tetap dihitungmenghasilkan 0
COUNT(kolom)diabaikanmenghasilkan 0
COUNT(DISTINCT kolom)diabaikanmenghasilkan 0
SUM(kolom)diabaikanmenghasilkan NULL
AVG(kolom)diabaikanmenghasilkan NULL
MIN(kolom) dan MAX(kolom)diabaikanmenghasilkan NULL
GROUP_CONCAT(kolom)diabaikanmenghasilkan 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, dan COUNT(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#