I16๐SELECT, Filter & NULLโ
โโDasarTebak Output
COUNT(*) vs COUNT(kolom) vs COUNT(DISTINCT)
#count#null#distinct
Pertanyaan
"Tanpa menjalankan query, coba tebak: berapa angka di ketiga kolom hasil query ini?"
Tabel pelanggan:
| pelanggan_id | nama | kota |
|---|---|---|
| 1 | Budi | Jakarta |
| 2 | Siti | Bandung |
| 3 | Andi | Jakarta |
| 4 | Dewi | NULL |
| 5 | Rina | Surabaya |
| 6 | Joko | NULL |
| 7 | Putri | Bandung |
SELECT COUNT(*) AS semua_baris, COUNT(kota) AS ada_kota, COUNT(DISTINCT kota) AS kota_unik FROM pelanggan;
Jawaban Singkat
Hasilnya 7, 5, 3. COUNT(*) menghitung semua baris tanpa peduli isinya. COUNT(kota) hanya menghitung baris yang kotanya tidak NULL, jadi Dewi dan Joko tidak terhitung. COUNT(DISTINCT kota) menghitung nilai unik yang tidak NULL: Jakarta, Bandung, Surabaya, jadi 3. NULL tidak dihitung sebagai satu nilai unik.
Pembahasan
COUNT(*): jumlah baris. Ada 7 baris di tabel, jadi 7. Isi kolom tidak dilihat sama sekali, baris yang semua kolomnya NULL pun tetap terhitung.COUNT(kolom): jumlah nilai yang tidak NULL. Dari 7 baris, 2 punyakotaNULL. Hasilnya 5. Ini berlaku untuk semua fungsi agregat selainCOUNT(*): NULL diabaikan.COUNT(DISTINCT kolom): jumlah nilai unik yang tidak NULL. Nilai yang ada: Jakarta (2x), Bandung (2x), Surabaya (1x). Unik: 3. NULL dibuang dulu sebelum dihitung uniknya.- Cara mengingat. Bintang berarti "baris". Nama kolom berarti "nilai".
DISTINCTberarti "nilai berbeda". NULL bukan nilai, jadi tidak pernah ikut dihitung kecuali diCOUNT(*).
Query
SELECT COUNT(*) AS semua_baris, COUNT(kota) AS ada_kota, COUNT(DISTINCT kota) AS kota_unik FROM pelanggan;
Contoh Output
| semua_baris | ada_kota | kota_unik |
|---|---|---|
| 7 | 5 | 3 |
Jebakan Umum
- Menjawab
kota_unik= 4 karena menganggap NULL sebagai satu "kota" tersendiri.SELECT DISTINCT kotamemang menampilkan baris NULL, tapiCOUNT(DISTINCT kota)tidak menghitungnya. - Mengira
COUNT(kota)sama denganCOUNT(*). Keduanya hanya sama kalau kolomnya tidak pernah NULL. - Mengira
COUNT(1)berbeda dariCOUNT(*). Hasilnya sama persis, karena1tidak pernah NULL. Soal performa, optimizer modern memperlakukannya sama. - Memakai
COUNT(kolom)untuk menghitung jumlah baris tanpa sadar kolomnya punya NULL. Laporan jadi kurang hitung.
Follow-up dari Interviewer
- "Bagaimana supaya NULL ikut dihitung sebagai satu kategori unik?"
COUNT(DISTINCT COALESCE(kota, '(kosong)')). Di data sampel hasilnya 4. - "Berapa hasil
SELECT COUNT(*) FROM pelanggan WHERE kota <> 'Jakarta'?" 3 (Siti, Rina, Putri). Dewi dan Joko tidak ikut karenaNULL <> 'Jakarta'bernilai UNKNOWN. - "Bagaimana menghitung persentase pelanggan yang belum isi kota?"
100.0 * (COUNT(*) - COUNT(kota)) / COUNT(*), hasilnya sekitar 28,6%.
Yang Sebenarnya Diuji
Pemahaman bagaimana fungsi agregat memperlakukan NULL. Ini dasar dari banyak bug laporan, misalnya jumlah user aktif yang kurang hitung karena kolom yang dipakai di COUNT ternyata punya NULL.
Catatan Dialect
- Perilaku
COUNT(*),COUNT(kolom), danCOUNT(DISTINCT kolom)sama di DuckDB, PostgreSQL, MySQL, BigQuery, dan Snowflake. - Untuk menghitung kombinasi unik beberapa kolom, MySQL menerima
COUNT(DISTINCT a, b), sedangkan dialect lain biasanya lewat subquery:SELECT COUNT(*) FROM (SELECT DISTINCT a, b FROM t) x. Perhatikan bahwa cara subquery ini ikut menghitung kombinasi yang mengandung NULL.