Ada satu kelas kesalahan SQL yang tidak pernah memunculkan pesan error: kuerinya jalan, angkanya keluar rapi, dan angkanya salah. Hampir selalu penyebabnya sama, yaitu NULL. Berikut aturannya, dengan perilaku yang tertulis di dokumentasi resmi mesin basis datanya, bukan dari kebiasaan.
NULL bukan string kosong, dan tidak sama dengan apa pun
Kolom telepon berisi NULL berarti nomornya tidak diketahui. Kolom telepon berisi string kosong berarti orangnya diketahui tidak punya nomor. Dua hal berbeda, dan keduanya sah disimpan.
Konsekuensinya keras: dalam SQL, NULL tidak pernah bernilai benar ketika dibandingkan dengan nilai apa pun, termasuk dengan NULL lain. Jadi WHERE telepon = NULL mengembalikan nol baris, selalu, tanpa peringatan. Yang benar IS NULL atau IS NOT NULL.
Aturan turunannya: ekspresi apa pun yang memuat NULL menghasilkan NULL, kecuali dinyatakan lain. 1 + NULL menghasilkan NULL. CONCAT('Invisible', NULL) juga NULL, bukan kata "Invisible".
COUNT(*) dan COUNT(kolom) menjawab pertanyaan berbeda
Fungsi agregat seperti COUNT(), MIN(), dan SUM() mengabaikan NULL. Pengecualiannya COUNT(*), yang menghitung baris, bukan nilai kolom.
Artinya SELECT COUNT(*), COUNT(umur) FROM orang bisa mengembalikan 1.000 dan 840 dari tabel yang sama. Keduanya benar; yang salah adalah menyebut keduanya "jumlah data".
Ingin mendalaminya lebih terstruktur? Taalenta punya kelas SQL & Python Untuk Data Analisis.
Efek paling licik ada di rata-rata. AVG membagi total dengan jumlah nilai yang bukan NULL, bukan dengan jumlah baris. Kalau 160 baris kosong, rata-rata Anda dihitung dari 840 baris, dan biasanya hasilnya lebih tinggi daripada yang Anda kira sedang dilaporkan.
NOT IN dengan satu NULL akan mengosongkan hasil
Ini jebakan yang paling sering menghilangkan baris. Kalau daftar di kanan memuat setidaknya satu NULL dan tidak ada nilai yang cocok, hasil konstruksi NOT IN adalah NULL, bukan TRUE. Baris yang hasilnya NULL tidak lolos WHERE, jadi laporan Anda kehilangan seluruh baris yang seharusnya muncul.
Alasannya ada di definisinya: NOT IN setara dengan <> ALL, dan perbandingan dengan NULL tidak pernah menghasilkan FALSE, hanya "tidak diketahui". Dua penggantinya yang aman: pakai NOT EXISTS, atau saring dulu NULL di subkueri dengan WHERE kolom IS NOT NULL.
DISTINCT, GROUP BY, dan ORDER BY justru menganggap NULL sama
Di sinilah aturannya berbalik arah, dan itu membingungkan. Untuk perbandingan, dua NULL tidak pernah sama. Tetapi untuk DISTINCT, GROUP BY, dan ORDER BY, semua NULL diperlakukan setara. Maka GROUP BY menghasilkan satu kelompok NULL, bukan satu kelompok per baris kosong.
Urutannya juga punya aturan tetap: pada ORDER BY menaik, NULL muncul lebih dulu; pada ORDER BY menurun, NULL muncul terakhir. Berguna saat memeriksa data, menyesatkan saat mengambil sepuluh teratas.
Aturannya tidak seragam antar mesin
Jangan memindahkan kebiasaan dari satu mesin ke mesin lain tanpa memeriksa. SQLite, misalnya, masih mengizinkan kolom PRIMARY KEY berisi NULL karena kelalaian historis yang sengaja dipertahankan demi kompatibilitas, kecuali pada tabel WITHOUT ROWID dan STRICT. SQLite juga membolehkan kueri agregat memuat kolom yang tidak ada di GROUP BY, sesuatu yang ditolak hampir semua mesin lain. Kueri yang "benar" di laptop Anda bisa berubah arti di server produksi.
Dua alat untuk memeriksanya
PostgreSQL menyediakan IS DISTINCT FROM dan IS NOT DISTINCT FROM, yang memperlakukan NULL seperti nilai biasa: NULL IS DISTINCT FROM NULL menghasilkan false, bukan NULL. Untuk pemeriksaan cepat, ada juga num_nulls() dan num_nonnulls().
Kebiasaan yang murah dan berdampak besar: sebelum melaporkan angka apa pun, hitung dulu berapa NULL per kolom yang ikut dihitung. Satu kueri tambahan biasanya cukup untuk mengetahui apakah selisih yang muncul berasal dari data atau dari aturan bahasa.
Sumber
- MySQL 8.4 Reference Manual, B.3.4.3 Problems with NULL Values, https://dev.mysql.com/doc/refman/8.4/en/problems-with-null.html
- PostgreSQL 18 Documentation, 9.24 Subquery Expressions, https://www.postgresql.org/docs/current/functions-subquery.html
- PostgreSQL 18 Documentation, 9.2 Comparison Functions and Operators, https://www.postgresql.org/docs/current/functions-comparison.html
- SQLite, Quirks, Caveats, and Gotchas In SQLite, https://sqlite.org/quirks.html