Total penjualan sebesar 1280000.00 terdengar mengesankan — sampai kita tahu bahwa angka itu berasal dari dua belas transaksi yang masing-masing kecil. Rata-rata adalah angka yang membuat total bisa dibandingkan: nilai transaksi tipikal, harga jual rata-rata, diskon rata-rata per pelanggan. Fungsi agregasi AVG menghitungnya dengan membagi jumlah nilai dengan banyaknya nilai. Pada chapter ini kita akan bedah perilaku AVG yang paling sering membingungkan pemula: format desimalnya yang lebih panjang dari kolom aslinya, dan kebiasaannya mengabaikan NULL — bukan memperlakukannya sebagai nol. Kita juga akan membuktikan bahwa AVG memang setara dengan SUM dibagi COUNT versi MySQL.
Menyiapkan Tabel Latihan #
Kita pakai tabel penjualan yang sama seperti dua chapter sebelumnya, ditambah satu kolom baru: diskon bertipe DECIMAL(7,2) yang boleh NULL. Hanya delapan dari dua belas transaksi yang mendapat diskon — empat baris bernilai NULL — sehingga efek pengabaian NULL bisa kita amati dengan jelas:
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 changedCREATE 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,
diskon DECIMAL(7,2) NULL
);
INSERT INTO penjualan (tanggal, kota, produk, jumlah, harga, diskon) VALUES
('2026-01-05', 'Jakarta', 'Kopi Gayo', 2, 55000.00, 2000.00),
('2026-01-05', 'Bandung', 'Teh Melati', 3, 25000.00, 1000.00),
('2026-01-06', 'Jakarta', 'Teh Melati', 1, 25000.00, NULL),
('2026-01-07', 'Surabaya', 'Kopi Toraja', 5, 62000.00, 2000.00),
('2026-01-08', 'Bandung', 'Gula Aren', 4, 15000.00, 1000.00),
('2026-01-09', 'Jakarta', 'Gula Aren', 2, 15000.00, NULL),
('2026-01-10', 'Yogyakarta', 'Kopi Gayo', 3, 55000.00, 2000.00),
('2026-01-11', 'Surabaya', 'Teh Melati', 2, 25000.00, 1000.00),
('2026-01-12', 'Yogyakarta', 'Kopi Toraja', 1, 62000.00, NULL),
('2026-01-13', 'Jakarta', 'Kopi Toraja', 4, 62000.00, 2000.00),
('2026-01-14', 'Bandung', 'Kopi Gayo', 1, 55000.00, 1000.00),
('2026-01-15', 'Surabaya', 'Gula Aren', 6, 15000.00, NULL);Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 12 rows affected (0.00 sec)
Records: 12 Duplicates: 0 Warnings: 0Total seluruh diskon adalah 12000.00 dari delapan transaksi berdiskon: empat transaksi berdiskon 2000.00 dan empat lainnya 1000.00. Angka-angka ini sengaja dibuat mudah dihitung manual, sehingga setiap hasil AVG pada chapter ini bisa kita verifikasi dengan kepala sendiri — kebiasaan yang sebaiknya dipertahankan saat belajar fungsi agregasi.
Menghitung Rata-rata Sederhana #
Bentuk dasarnya menyebutkan satu kolom angka:
SELECT AVG(jumlah) AS rata_jumlah
FROM penjualan;Output yang Dihasilkan:
+-------------+
| rata_jumlah |
+-------------+
| 2.8333 |
+-------------+
1 row in set (0.00 sec)Hasilnya 2.8333 — total 34 unit dibagi dua belas baris. Perhatikan formatnya: kolom jumlah bertipe INT tanpa desimal, tetapi hasil AVG-nya tampil dengan empat angka desimal. Ini bukan bug melainkan aturan tipe: untuk argumen bilangan bulat, AVG menghasilkan DECIMAL dengan skala empat digit (nilai 34/12 = 2.83333... dibulatkan ke 2.8333). Bagaimana dengan kolom yang memang berdesimal? Mari kita uji:
SELECT AVG(harga) AS rata_harga
FROM penjualan;Output yang Dihasilkan:
+--------------+
| rata_harga |
+--------------+
| 39250.000000 |
+--------------+
1 row in set (0.00 sec)Hasilnya 39250.000000 — enam angka desimal, padahal kolom harga hanya punya dua. Aturannya konsisten: skala hasil AVG adalah skala kolom ditambah empat digit, sehingga DECIMAL(10,2) menghasilkan DECIMAL(...,6) dan INT (skala nol) menghasilkan empat digit. Nilai rata-rata sebenarnya tetap presisi di dalam hasil tersebut; hanya tampilannya yang membawa lebih banyak digit daripada yang kita biasakan lihat pada kolom uang.
NULL Diabaikan, Bukan Dihitung Nol #
Sekarang uji kolom diskon yang mengandung NULL pada empat baris:
SELECT COUNT(*) AS semua_baris,
COUNT(diskon) AS baris_berdiskon,
SUM(diskon) AS total_diskon,
AVG(diskon) AS rata_diskon
FROM penjualan;Output yang Dihasilkan:
+-------------+-----------------+--------------+-------------+
| semua_baris | baris_berdiskon | total_diskon | rata_diskon |
+-------------+-----------------+--------------+-------------+
| 12 | 8 | 12000.00 | 1500.000000 |
+-------------+-----------------+--------------+-------------+
1 row in set (0.00 sec)Empat kolom hasil menceritakan kisah yang lengkap: dua belas baris, delapan baris berdiskon, total 12000.00, dan rata-rata 1500.000000. Angka rata-rata tersebut berasal dari 12000.00 / 8, bukan 12000.00 / 12 — AVG mengabaikan baris yang kolomnya NULL sepenuhnya, sebagaimana SUM dan COUNT(kolom) melakukannya. Rata-rata yang dihitung adalah “rata-rata dari transaksi yang benar-benar memiliki diskon”.
Untuk membuktikannya, kita hitung dua versi rata-rata manual dengan SUM dan COUNT:
SELECT SUM(diskon) / COUNT(diskon) AS rata_manual_non_null,
SUM(diskon) / COUNT(*) AS rata_manual_semua_baris
FROM penjualan;Output yang Dihasilkan:
+----------------------+-------------------------+
| rata_manual_non_null | rata_manual_semua_baris |
+----------------------+-------------------------+
| 1500.000000 | 1000.000000 |
+----------------------+-------------------------+
1 row in set (0.00 sec)Versi pertama menghasilkan 1500.000000 — persis sama dengan AVG(diskon) — sedangkan versi kedua menghasilkan 1000.000000. Pembuktian ini penting karena menjelaskan apa yang sebenarnya dijanjikan AVG: fungsi ini adalah singkatan dari SUM(kolom) / COUNT(kolom), keduanya mengabaikan NULL. Bila kebutuhan bisnis kita justru “rata-rata diskon jika setiap transaksi tanpa diskon dianggap nol”, angka yang benar adalah 1000.000000, dan cara mendapatkannya adalah AVG(IFNULL(diskon, 0)):
SELECT AVG(IFNULL(diskon, 0)) AS rata_diskon_nol
FROM penjualan;Output yang Dihasilkan:
+-----------------+
| rata_diskon_nol |
+-----------------+
| 1000.000000 |
+-----------------+
1 row in set (0.00 sec)Fungsi IFNULL(diskon, 0) mengganti setiap NULL menjadi 0 sebelum nilai masuk ke AVG, sehingga pembaginya kembali menjadi dua belas baris. Hasilnya 1000.000000 — sama dengan versi SUM / COUNT(*). Dua angka yang berbeda ini sama-sama “benar”; yang menentukan pilihan adalah makna yang kita inginkan.
Merapikan Tampilan dengan ROUND #
Untuk laporan yang dibaca manusia, enam digit desimal lebih sering mengganggu daripada membantu. Fungsi ROUND membulatkan hasil ke jumlah desimal yang kita tentukan:
SELECT ROUND(AVG(harga), 2) AS rata_harga_2desimal,
ROUND(AVG(diskon), 0) AS rata_diskon_bulat
FROM penjualan;Output yang Dihasilkan:
+---------------------+-------------------+
| rata_harga_2desimal | rata_diskon_bulat |
+---------------------+-------------------+
| 39250.00 | 1500 |
+---------------------+-------------------+
1 row in set (0.00 sec)Rata-rata harga tampil sebagai 39250.00 dan rata-rata diskon menjadi 1500 tanpa desimal. Perhatikan urutan kerjanya: AVG menghitung dengan presisi penuh terlebih dahulu, baru ROUND membulatkan hasil akhirnya — menulis AVG(ROUND(harga, 2)) pada kolom yang memang sudah dua desimal tidak mengubah apa pun. ROUND di sini murni urusan tampilan hasil query; nilai yang tersimpan di tabel tidak pernah tersentuh.
Membersihkan Database Latihan #
Latihan rata-rata selesai; database latihan kita hapuskan kembali:
DROP DATABASE belajar_agregasi;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)Referensi #
- Aggregate Function Descriptions — MySQL 8.4 Reference Manual
- Mathematical Functions — MySQL 8.4 Reference Manual
Kini kita menguasai tiga agregat penghitung angka: COUNT untuk jumlah, SUM untuk total, dan AVG untuk rata-rata — termasuk jebakan NULL dan format desimalnya. Satu jenis pertanyaan belum terjawab: bukan “berapa banyak” atau “berapa rata-ratanya”, melainkan “yang paling”. Berapa transaksi terbesar, harga termahal, tanggal penjualan pertama? Chapter berikutnya membahas MIN dan MAX, dua fungsi yang juga punya kebiasaan khas saat bertemu teks dan tanggal.