Pertanyaan paling sering muncul dalam laporan database berbunyi sederhana: “berapa banyak?”. Berapa jumlah transaksi bulan ini, berapa pelanggan yang benar-benar tercatat namanya, berapa kota berbeda yang kita layani — semuanya dijawab oleh satu fungsi agregasi bernama COUNT. Fungsi agregasi bekerja dengan cara membaca banyak baris sekaligus lalu meringkasnya menjadi satu nilai, berbeda dari fungsi biasa yang memproses satu baris pada satu waktu. Pada chapter ini kita akan bedah tiga bentuk COUNT — COUNT(*), COUNT(kolom), dan COUNT(DISTINCT kolom) — karena ketiganya bisa menghasilkan angka yang berbeda pada tabel yang sama. Sumber perbedaan itu hanya satu: cara tiap varian memperlakukan NULL.
Menyiapkan Tabel Latihan #
Kita pakai satu database latihan bernama belajar_agregasi dengan tabel penjualan berisi dua belas transaksi penjualan kopi. Kolom pelanggan sengaja dibuat boleh NULL — lima transaksi dicatat tanpa nama pelanggan karena dibeli tunai oleh pembeli tanpa kartu member, situasi yang sangat lazim di dunia nyata:
DROP DATABASE IF EXISTS belajar_agregasi;
CREATE DATABASE belajar_agregasi;
USE belajar_agregasi;Output yang Dihasilkan:
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 1 row affected (0.00 sec)
Database changedCatatan 1 warning pada baris pertama muncul karena database belajar_agregasi memang belum ada saat DROP DATABASE IF EXISTS dijalankan; pola ini membuat skrip latihan selalu aman dijalankan berulang kali.
CREATE TABLE penjualan (
id INT AUTO_INCREMENT PRIMARY KEY,
tanggal DATE NOT NULL,
kota VARCHAR(50) NOT NULL,
produk VARCHAR(50) NOT NULL,
jumlah INT NOT NULL,
harga DECIMAL(10,2) NOT NULL,
pelanggan VARCHAR(50) NULL
);
INSERT INTO penjualan (tanggal, kota, produk, jumlah, harga, pelanggan) VALUES
('2026-01-05', 'Jakarta', 'Kopi Gayo', 2, 55000.00, 'Budi'),
('2026-01-05', 'Bandung', 'Teh Melati', 3, 25000.00, 'Siti'),
('2026-01-06', 'Jakarta', 'Teh Melati', 1, 25000.00, NULL),
('2026-01-07', 'Surabaya', 'Kopi Toraja', 5, 62000.00, 'Andi'),
('2026-01-08', 'Bandung', 'Gula Aren', 4, 15000.00, NULL),
('2026-01-09', 'Jakarta', 'Gula Aren', 2, 15000.00, 'Rina'),
('2026-01-10', 'Yogyakarta', 'Kopi Gayo', 3, 55000.00, NULL),
('2026-01-11', 'Surabaya', 'Teh Melati', 2, 25000.00, 'Budi'),
('2026-01-12', 'Yogyakarta', 'Kopi Toraja', 1, 62000.00, NULL),
('2026-01-13', 'Jakarta', 'Kopi Toraja', 4, 62000.00, 'Siti'),
('2026-01-14', 'Bandung', 'Kopi Gayo', 1, 55000.00, NULL),
('2026-01-15', 'Surabaya', 'Gula Aren', 6, 15000.00, 'Rina');Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 12 rows affected (0.00 sec)
Records: 12 Duplicates: 0 Warnings: 0Dari dua belas baris tersebut, tujuh baris memiliki nilai pelanggan dan lima baris bernilai NULL. Kolom tanggal kita isi dengan literal tanggal tetap seperti '2026-01-05' agar seluruh contoh pada chapter ini deterministik — hasilnya sama setiap kali dijalankan. Kolom jumlah dan harga akan menjadi bahan latihan fungsi agregasi lain di chapter-chapter berikutnya.
Menghitung Semua Baris dengan COUNT(*) #
Bentuk paling mendasar menghitung setiap baris tabel, apa pun isinya:
SELECT COUNT(*) AS jumlah_transaksi
FROM penjualan;Output yang Dihasilkan:
+------------------+
| jumlah_transaksi |
+------------------+
| 12 |
+------------------+
1 row in set (0.00 sec)Hasilnya 12 — persis jumlah baris yang kita sisipkan. Tanda bintang pada COUNT(*) tidak berarti “semua kolom” sebagaimana pada SELECT *; bintang di sini berarti “satu baris utuh”, tanpa peduli kolom mana pun yang berisi atau kosong. Sebuah baris dengan pelanggan bernilai NULL tetap dihitung sebagai baris, karena keberadaan baris tersebut tidak bergantung pada isi satu kolom. Inilah alasan COUNT(*) menjadi bentuk yang tepat ketika yang kita maksud benar-benar adalah “jumlah baris”.
COUNT(kolom) Melewatkan Baris Bernilai NULL #
Bentuk kedua menghitung nilai, bukan baris. MySQL membaca kolom yang disebut, lalu menghitung baris yang kolomnya tidak NULL:
SELECT COUNT(*) AS semua_baris,
COUNT(pelanggan) AS baris_dengan_pelanggan
FROM penjualan;Output yang Dihasilkan:
+-------------+------------------------+
| semua_baris | baris_dengan_pelanggan |
+-------------+------------------------+
| 12 | 7 |
+-------------+------------------------+
1 row in set (0.00 sec)Angka pertama 12 dan angka kedua 7 berselisih lima — tepat sebanyak baris dengan pelanggan bernilai NULL. Perilaku ini mengikuti definisi NULL sebagai “nilai yang tidak ada”: sesuatu yang tidak ada tidak bisa dihitung sebagai nilai. Jika kita ingin tahu berapa transaksi yang datanya pelanggannya lengkap, COUNT(pelanggan) menjawabnya langsung tanpa perlu klausa tambahan.
Kebalikan pola yang sama juga berguna: selisih COUNT(*) dan COUNT(kolom) otomatis menjadi jumlah baris yang kosong pada kolom tersebut. Kita tidak perlu menulis WHERE pelanggan IS NULL untuk mendapatkan informasi kelengkapan data — cukup satu query dengan dua agregat.
COUNT pada Hasil Kosong Selalu 0 #
Apa yang terjadi ketika tidak ada satu baris pun yang cocok? Mari kita uji dengan kondisi yang jelas-jelas tidak terpenuhi:
SELECT COUNT(*) AS transaksi_jumlah_besar
FROM penjualan
WHERE jumlah > 100;Output yang Dihasilkan:
+------------------------+
| transaksi_jumlah_besar |
+------------------------+
| 0 |
+------------------------+
1 row in set (0.00 sec)Hasilnya 0, bukan NULL dan bukan himpunan kosong. Perilaku yang sama berlaku pada tabel yang benar-benar kosong. Kita buat tabel penjualan_lama yang strukturnya ada datanya belum pernah diisi:
CREATE TABLE penjualan_lama (
id INT AUTO_INCREMENT PRIMARY KEY,
tanggal DATE NOT NULL
);
SELECT COUNT(*) AS baris_tabel_lama
FROM penjualan_lama;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
+------------------+
| baris_tabel_lama |
+------------------+
| 0 |
+------------------+
1 row in set (0.00 sec)COUNT selalu mengembalikan angka, tidak pernah NULL — sekalipun tidak ada baris sama sekali. Jaminan ini nyaman bagi kode aplikasi: pembacaan kolom hasil COUNT tidak perlu pemeriksaan NULL sebelum dipakai dalam perhitungan. Perhatikan bahwa ini merupakan kekhususan COUNT; fungsi agregasi seperti SUM, AVG, dan MIN justru mengembalikan NULL ketika tidak ada baris yang cocok, sebuah gotcha yang kita bedah tuntas di chapter-chapter selanjutnya.
Menghitung Nilai Berbeda dengan COUNT(DISTINCT) #
Bentuk ketiga menggabungkan penghitungan dengan penyaringan nilai kembar. Kata kunci DISTINCT menyatukan nilai duplikat terlebih dahulu, baru COUNT menghitung sisanya:
SELECT COUNT(DISTINCT kota) AS kota_berbeda,
COUNT(DISTINCT produk) AS produk_berbeda,
COUNT(DISTINCT pelanggan) AS pelanggan_berbeda
FROM penjualan;Output yang Dihasilkan:
+--------------+----------------+-------------------+
| kota_berbeda | produk_berbeda | pelanggan_berbeda |
+--------------+----------------+-------------------+
| 4 | 4 | 4 |
+--------------+----------------+-------------------+
1 row in set (0.00 sec)Empat kota, empat produk, dan empat pelanggan berbeda tercatat pada dua belas transaksi — DISTINCT merangkum variasi data dalam satu angka per kolom. Sama seperti COUNT(kolom), varian DISTINCT ini juga mengabaikan NULL: lima baris tanpa pelanggan tidak menambah angka pelanggan_berbeda. Statistik semacam ini adalah bahan baku laporan “berapa pelanggan unik yang berbelanja bulan ini” yang tidak bisa dijawab dengan COUNT(*) semata.
Membersihkan Database Latihan #
Rangkaian latihan kita selesai dan database latihan boleh dihapus:
DROP DATABASE belajar_agregasi;Output yang Dihasilkan:
Query OK, 2 rows affected (0.00 sec)Respons 2 rows affected menghitung jumlah tabel yang ikut terjatuh bersama database-nya: penjualan dan penjualan_lama. Nama database belajar_agregasi akan kita pakai ulang di chapter-chapter agregasi berikutnya, sehingga setiap latihan selalu dimulai dari keadaan bersih.
Referensi #
- Aggregate Function Descriptions — MySQL 8.4 Reference Manual
- SELECT Statement — MySQL 8.4 Reference Manual
Kita sekarang bisa menjawab “berapa banyak” dengan tiga varian COUNT dan memilih varian yang tepat sesuai makna NULL pada data. Pertanyaan berikutnya pada laporan biasanya bukan lagi soal jumlah, melainkan total: berapa unit terjual dan berapa omzet keseluruhan. Chapter berikutnya membahas SUM, termasuk satu kejutan penting ketika tidak ada baris yang cocok.