Topik ini membahas NULL secara menyeluruh, yaitu apa artinya, bagaimana logika tiga nilai bekerja, dan alat apa yang dipakai untuk menanganinya. Dataset utama sengaja memuat satu anggota tanpa email dan beberapa peminjaman tanpa tanggal kembali, sehingga setiap pernyataan pada topik ini dapat diuji langsung.
Blok penyiapan dataset#
# siapkan ulang tabel dan data contoh untuk topik ini
PGOPTIONS='-c client_min_messages=warning' psql -q -U postgres -d perpustakaan <<'SQL'
DROP TABLE IF EXISTS peminjaman, buku, anggota, kategori CASCADE;
CREATE TABLE kategori (id SERIAL PRIMARY KEY, nama TEXT NOT NULL UNIQUE);
CREATE TABLE anggota (id SERIAL PRIMARY KEY, nama TEXT NOT NULL, email TEXT UNIQUE, bergabung DATE NOT NULL, aktif BOOLEAN NOT NULL DEFAULT TRUE);
CREATE TABLE buku (id SERIAL PRIMARY KEY, judul TEXT NOT NULL, penulis TEXT NOT NULL, tahun INTEGER NOT NULL, kategori_id INTEGER REFERENCES kategori(id));
CREATE TABLE peminjaman (id SERIAL PRIMARY KEY, anggota_id INTEGER NOT NULL REFERENCES anggota(id), buku_id INTEGER NOT NULL REFERENCES buku(id), tanggal_pinjam DATE NOT NULL, tanggal_kembali DATE);
INSERT INTO kategori (nama) VALUES ('Pemrograman'), ('Sains'), ('Sejarah'), ('Fiksi'), ('Statistika');
INSERT INTO anggota (nama, email, bergabung, aktif) VALUES ('Ali Rahman', '[email protected]', '2024-01-15', TRUE), ('Budi Santoso', '[email protected]', '2024-03-02', TRUE), ('Citra Kirana', '[email protected]', '2024-05-20', FALSE), ('Dewi Lestari', '[email protected]', '2024-08-11', TRUE), ('Eka Pratama', NULL, '2025-01-30', TRUE);
INSERT INTO buku (judul, penulis, tahun, kategori_id) VALUES ('Dasar Basis Data', 'Sari Wulandari', 2021, 1), ('Jaringan Komputer', 'Ahmad Fauzi', 2019, 1), ('Fisika untuk Pemula', 'Rina Marlina', 2020, 2), ('Kimia Organik', 'Rina Marlina', 2022, 2), ('Sejarah Nusantara', 'Bambang Wijaya', 2018, 3), ('Cerita Kota Lama', 'Nur Aisyah', 2023, 4), ('Statistika Terapan', 'Sari Wulandari', 2022, 5), ('Algoritma dan Struktur Data', 'Ahmad Fauzi', 2021, 1);
INSERT INTO peminjaman (anggota_id, buku_id, tanggal_pinjam, tanggal_kembali) VALUES (1, 1, '2025-03-01', '2025-03-15'), (1, 7, '2025-03-05', '2025-03-20'), (2, 3, '2025-03-10', NULL), (3, 5, '2025-02-20', '2025-03-01'), (2, 1, '2025-04-02', NULL), (4, 6, '2025-04-07', NULL), (5, 8, '2025-04-09', '2025-04-25'), (4, 2, '2025-05-01', NULL);
SQLNULL bukan nol dan bukan teks kosong#
NULL menandai nilai yang tidak diketahui atau tidak berlaku, dan ketiga kolom berikut memakainya dengan makna berbeda pada data yang sama. Email Eka Pratama tidak diketahui, sedangkan tanggal_kembali pada peminjaman yang masih berjalan berarti belum terjadi, dan keduanya bukan nol ataupun teks kosong.
Perbandingan biasa dengan NULL tidak pernah menghasilkan benar atau salah, melainkan ketahuan, karena membandingkan sesuatu yang tak diketahui tidak memberi jawaban. Karena itu NULL = NULL bernilai NULL, dan predikat khusus IS NULL menjadi satu-satunya cara menyaringnya.
# hitung seluruh baris versus baris dengan email diketahui
psql -U postgres -d perpustakaan -c "SELECT COUNT(*) AS total, COUNT(email) AS beremail FROM anggota;" total | beremail
-------+----------
5 | 4
(1 row)COUNT(*) menghitung baris, sedangkan COUNT(email) melewati baris yang emailnya NULL, dan selisih keduanya berlima lawan empat. Fungsi agregasi lain berperilaku sama dengan mengabaikan NULL, perilaku yang dijabarkan lagi pada modul agregasi.
Logika tiga nilai#
Logika SQL beroperasi pada tiga nilai, yaitu TRUE, FALSE, dan NULL yang dibaca sebagai tidak diketahui. Aturan AND dan OR mengikuti naluri kehati-hatian, yaitu satu nilai salah membuat AND pasti salah seketika, satu nilai benar membuat OR pasti benar seketika, dan sisanya mewarisi ketidakpastian.
# tabel kebenaran AND dan OR dengan nilai tidak diketahui
psql -U postgres -d perpustakaan -c "SELECT TRUE AND NULL AS dan_dengan_null, FALSE AND NULL AS dan_dengan_salah, TRUE OR NULL AS atau_dengan_null, FALSE OR NULL AS atau_dengan_salah;" dan_dengan_null | dan_dengan_salah | atau_dengan_null | atau_dengan_salah
-----------------+------------------+------------------+-------------------
| f | t |
(1 row)Klausa WHERE hanya meloloskan baris yang syaratnya bernilai TRUE, sehingga baris dengan syarat NULL dikeluarkan tanpa error. Perilaku senyap inilah sumber bug yang paling sering ditemui, dan tabel kebenaran di atas layak diingat sebagai satu kesatuan.
IS NULL dan jebakan perbandingan#
Predikat IS NULL dan IS NOT NULL menyaring ketidaktahuan secara langsung, sedangkan perbandingan biasa diam-diam mengeluarkan baris NULL dari hasil. Contoh paling berbahaya adalah mengira negasi perbandingan mencakup semuanya.
# anggota dengan email selain milik Ali
psql -U postgres -d perpustakaan -c "SELECT nama FROM anggota WHERE email <> '[email protected]';" nama
--------------
Budi Santoso
Citra Kirana
Dewi Lestari
(3 rows)Keluarannya menampilkan empat nama, bukan lima dikurangi satu, karena baris Eka yang emailnya NULL tidak bernilai benar maupun salah pada perbandingan tersebut. Bentuk yang benar untuk meliputi keduanya adalah WHERE email <> '[email protected]' OR email IS NULL, dan menuliskannya tanpa sadar adalah keterampilan yang dilatih topik ini.
COALESCE dan NULLIF#
Fungsi COALESCE mengembalikan argumen pertama yang bukan NULL, sehingga menjadi cara baku memberi nilai pengganti pada tampilan. Fungsi NULLIF bekerja sebaliknya, yaitu mengembalikan NULL ketika dua argumennya sama, dan lazim dipakai mengubah nilai penanda menjadi NULL.
# nilai pengganti untuk email yang tak diketahui
psql -U postgres -d perpustakaan -c "SELECT nama, COALESCE(email, 'tanpa email') AS kontak FROM anggota ORDER BY nama;" nama | kontak
--------------+-------------------
Ali Rahman | [email protected]
Budi Santoso | [email protected]
Citra Kirana | [email protected]
Dewi Lestari | [email protected]
Eka Pratama | tanpa email
(5 rows)Pasangan ini berpadu dalam pola yang sama, yaitu COALESCE menormalkan keluaran untuk pembaca, sedangkan NULLIF menormalkan masukan sebelum dihitung. Keduanya tidak mengubah data yang tersimpan, sehingga makna aslinya tetap terjaga bagi query lain.
NOT IN dan racun NULL#
Operator NOT IN membandingkan dengan seluruh anggota daftarnya, dan satu NULL di daftar itu membuat hasilnya tidak pernah benar. Perilaku ini menghasilkan query yang sah dan tetap mengembalikan nol baris tanpa peringatan apa pun.
# NOT IN bertemu satu nilai tidak diketahui
psql -U postgres -d perpustakaan -c "SELECT 4 NOT IN (1, 2, NULL) AS hasil;" hasil
-------
(1 row)Pada data nyata, daftar itu biasanya hasil subquery dengan kolom yang boleh NULL, sehingga bug-nya muncul jauh dari penyebabnya. Penggantinya adalah NOT EXISTS, yang tidak mewarisi masalah ini dan dibahas pada modul subquery dan CTE.
Kesalahan umum#
Kesalahan pertama adalah menulis WHERE email = NULL, yang mengembalikan nol baris tanpa error, padahal bentuk yang benar adalah WHERE email IS NULL. Kesalahan kedua adalah mengisi kolom teks dengan string kosong untuk melambangkan ketidaktahuan, karena string kosong adalah nilai yang diketahui dan seluruh semantik NULL menjadi tidak konsisten di tabel itu. Kesalahan ketiga adalah mengira COALESCE memperbaiki data, padahal ia hanya memperbaiki tampilan satu query, dan penyebab NULL yang keliru tetap harus diperbaiki pada datanya.
Kesalahan keempat adalah NOT IN terhadap subquery yang kolomnya boleh NULL, yang diam-diam mengosongkan hasil. Kebiasaan penangkalnya sederhana, yaitu menandai kolom rujukan sebagai NOT NULL atau memakai NOT EXISTS sejak awal.
Ringkasan#
- NULL menandai nilai yang tidak diketahui atau tidak berlaku, dan
NULL = NULLsendiri bernilai NULL. - Logika SQL berjalan pada tiga nilai, dan WHERE hanya meloloskan baris yang syaratnya benar sungguhan.
- IS NULL dan IS NOT NULL menjadi satu-satunya penyaring ketidaktahuan, sedangkan perbandingan biasa diam-diam mengeluarkannya.
- COALESCE memberi nilai pengganti pada tampilan, NULLIF mengubah penanda menjadi NULL, dan NOT EXISTS menggantikan NOT IN pada daftar yang boleh NULL.
Referensi#
- Comparison Functions and Operators — PostgreSQL Documentation — Predikat IS NULL dan perilaku perbandingan dengan NULL.
- Conditional Expressions — PostgreSQL Documentation — Dokumentasi COALESCE dan NULLIF.
- Comparison Operators — PostgreSQL Tutorial — Tabel operator perbandingan pada dokumentasi resmi.