Setiap aplikasi hidup dari pertanyaan ya/tidak: apakah pelanggan ini masih aktif, apakah tagihan sudah lunas, apakah pesanan terverifikasi. PostgreSQL menyimpan jawaban pertanyaan seperti itu dalam tipe boolean — hanya satu byte per nilai, dengan tiga kemungkinan isi: true, false, atau NULL. Justru karena tampak sederhana, boolean sering disalahpahami: bentuk literal yang diterimanya lebih banyak dari yang dikira orang, NULL-nya bermain dengan aturan logika tiga nilai, dan penulisan WHERE yang salah membuat baris hilang tanpa pesan error. Chapter ini membedah semuanya dengan tabel pelanggan yang statusnya beragam.

Membuat Tabel dengan Kolom boolean #

Tabel pelanggan berikut memakai dua kolom boolean: aktif (boleh NULL, untuk pelanggan yang statusnya belum dipastikan) dan premium (wajib diisi, default false). Lima barisnya sengaja diisi dengan bentuk literal yang berbeda-beda:

sql buat-tabel.sql
CREATE TABLE pelanggan (
    id      integer PRIMARY KEY,
    nama    text NOT NULL,
    aktif   boolean DEFAULT true,
    premium boolean NOT NULL DEFAULT false
);

INSERT INTO pelanggan (id, nama, aktif, premium) VALUES
    (1, 'Budi', true, 'f'),
    (2, 'Siti', 't', '1'),
    (3, 'Toko Maju Jaya', '1', false),
    (4, 'Rina', 'no', true),
    (5, 'Agus', NULL, 'off');

SELECT id, nama, aktif, premium
FROM pelanggan
ORDER BY id;

Output yang Dihasilkan:

text
CREATE TABLE
INSERT 0 5
 id |      nama      | aktif | premium 
----+----------------+-------+---------
  1 | Budi           | t     | f
  2 | Siti           | t     | t
  3 | Toko Maju Jaya | t     | f
  4 | Rina           | f     | t
  5 | Agus           |       | f
(5 rows)

Lima baris masuk dengan lima kombinasi penulisan berbeda, dan hasilnya seragam: kolom aktif berisi t untuk Budi, Siti, dan Toko Maju Jaya; f untuk Rina; serta kosong untuk Agus yang NULL. PostgreSQL menampilkan boolean sebagai t dan f — singkatan satu huruf, bukan kata penuh — dan NULL tampil sebagai kolom kosong. Baris Agus juga memperlihatkan fungsi DEFAULT true: kolom aktif sengaja tidak diberi NOT NULL sehingga NULL diperbolehkan, dan itu keputusan desain yang akan kita bahas pada bagian logika tiga nilai.

Bentuk Literal yang Diterima #

Kata kunci true dan false adalah bentuk utama, tetapi PostgreSQL menerima enam bentuk string untuk masing-masing nilai — berguna saat data datang dari form, file CSV, atau sistem lain:

NilaiBentuk yang diterima
truetrue, 't', 'yes', 'y', 'on', '1'
falsefalse, 'f', 'no', 'n', 'off', '0'

Semua bentuk string tidak peka huruf besar-kecil ('TRUE', 'tRuE' sama sahnya), spasi di awal dan akhir diabaikan, dan awalan unik seperti 'tru' atau 'fal' pun diterima. Kita periksa sebagian bentuk itu langsung di server:

SELECT true AS kata_kunci,
       'true'::boolean AS string_true,
       'TRUE'::boolean AS huruf_besar,
       't'::boolean AS singkat_t;

SELECT false AS kata_kunci,
       'f'::boolean AS singkat_f,
       '1'::boolean AS angka_satu,
       '0'::boolean AS angka_nol;

SELECT 'yes'::boolean AS ya,
       'no'::boolean AS tidak,
       'on'::boolean AS nyala,
       'off'::boolean AS mati;

Output yang Dihasilkan:

text
 kata_kunci | string_true | huruf_besar | singkat_t 
------------+-------------+-------------+-----------
 t          | t           | t           | t
(1 row)

 kata_kunci | singkat_f | angka_satu | angka_nol 
------------+-----------+------------+-----------
 f          | f         | t          | f
(1 row)

 ya | tidak | nyala | mati 
----+-------+-------+------
 t  | f     | t     | f
(1 row)

Dua belas ekspresi, dua hasil: semuanya berkurang menjadi t atau f. Perhatikan bahwa bentuk angka '1' dan '0' berupa string berkutip — menulis 1 tanpa kutip bukan literal boolean melainkan integer, dan PostgreSQL tidak mengonversinya secara diam-diam.

Menyaring Baris dengan Kolom boolean #

Kekuatan khas boolean di PostgreSQL: kolomnya bisa dipakai langsung sebagai syarat WHERE tanpa perbandingan apa pun. Tiga query berikut menyaring pelanggan dengan cara yang berbeda:

SELECT id, nama
FROM pelanggan
WHERE aktif
ORDER BY id;

SELECT id, nama
FROM pelanggan
WHERE aktif = true
ORDER BY id;

SELECT id, nama
FROM pelanggan
WHERE NOT premium
ORDER BY id;

Output yang Dihasilkan:

text
 id |      nama      
----+----------------
  1 | Budi
  2 | Siti
  3 | Toko Maju Jaya
(3 rows)

 id |      nama      
----+----------------
  1 | Budi
  2 | Siti
  3 | Toko Maju Jaya
(3 rows)

 id |      nama      
----+----------------
  1 | Budi
  3 | Toko Maju Jaya
  5 | Agus
(3 rows)

Mari kita bedah hasil ketiganya:

  1. WHERE aktif: bentuk paling idiomatik — kolom boolean langsung menjadi syarat. Baris Budi, Siti, dan Toko Maju Jaya lolos; Rina (false) dan Agus (NULL) tersaring keluar.
  2. WHERE aktif = true: hasilnya identik dengan bentuk pertama. Perbandingan ini sah tetapi berlebihan — komunitas PostgreSQL umumnya menganggapnya noise.
  3. WHERE NOT premium: membalik syarat untuk mencari pelanggan non-premium. Budi, Toko Maju Jaya, dan Agus muncul — perhatikan bahwa Agus yang aktif-nya NULL tetap lolos, karena NULL-nya ada di kolom lain yang tidak diperiksa.

Perhatikan pola penting dari query pertama dan ketiga: baris Agus muncul di WHERE NOT premium tetapi tidak di WHERE aktif. Syarat WHERE aktif menuntut nilai true; baris dengan NULL tidak memenuhi tuntutan itu — dan WHERE NOT aktif pun tidak akan menampungnya, seperti berikutnya kita buktikan.

NULL dan Logika Tiga Nilai #

NULL pada kolom boolean tidak berarti “salah” — NULL berarti “tidak diketahui”, dan PostgreSQL memperlakukannya dengan logika tiga nilai SQL. Predikat IS TRUE, IS FALSE, dan IS UNKNOWN adalah satu-satunya cara menguji ketiga keadaan itu secara eksplisit:

SELECT id, nama, aktif
FROM pelanggan
WHERE aktif IS NOT TRUE
ORDER BY id;

SELECT id, nama
FROM pelanggan
WHERE aktif IS UNKNOWN
ORDER BY id;

SELECT (NULL::boolean AND true) IS NULL AS nol_dan_benar,
       (NULL::boolean OR false) IS NULL AS nol_atau_salah,
       (NOT NULL::boolean) IS NULL AS bukan_nol;

Output yang Dihasilkan:

text
 id | nama | aktif 
----+------+-------
  4 | Rina | f
  5 | Agus | 
(2 rows)

 id | nama 
----+------
  5 | Agus
(1 row)

 nol_dan_benar | nol_atau_salah | bukan_nol 
---------------+----------------+-----------
 t             | t              | t
(1 row)

Hasilnya memperlihatkan aturan mainnya:

  1. IS NOT TRUE mengambil Rina (nilainya false) sekaligus Agus (nilainya NULL) — kebalikan dari WHERE aktif yang hanya mengambil nilai true. Bandingkan dengan WHERE NOT aktif: bentuk itu hanya menghasilkan Rina, karena NOT NULL tetap NULL dan NULL tidak lolos WHERE.
  2. IS UNKNOWN secara khusus menangkap baris yang nilainya NULL — hanya Agus.
  3. Query ketiga membuktikan tabel kebenaran tiga nilai: NULL AND true menghasilkan NULL (bukan false, karena lawan operand belum tahu nilai sejatinya), NULL OR false juga NULL, dan NOT NULL tetap NULL. Ketiga hasilnya diuji dengan IS NULL dan semuanya t.

Literal yang Tidak Dikenal #

Kelenturan bentuk literal punya batas tegas: string di luar daftar yang diakui ditolak mentah. Kata Bahasa Indonesia yang paling natural justru jadi contoh kegagalannya:

INSERT INTO pelanggan (id, nama, aktif, premium)
VALUES (6, 'Dewi', 'benar', false);

Output yang Dihasilkan:

text
psql:literal-invalid.sql:2: ERROR:  invalid input syntax for type boolean: "benar"
LINE 2: VALUES (6, 'Dewi', 'benar', false);
                           ^

Error invalid input syntax for type boolean: "benar" muncul begitu string 'benar' dibaca — PostgreSQL tidak menebak makna kata, ia hanya menerima daftar bentuk resmi yang kita lihat di tabel sebelumnya. Serupa dengan ini: SELECT 'ya'::boolean; gagal dengan error yang sama meskipun 'yes' dan 'y' sah. Kalau aplikasi Anda menerima input bebas (misalnya dropdown berbahasa Indonesia), terjemahkan dulu di sisi aplikasi menjadi true/false sebelum mengirimnya ke database.

Dengan ya/tidak beres, sisa katalog tipe data yang belum kita jelajahi adalah yang paling menuntut perhatian detail: tanggal dan waktu — tipe yang formatnya, zona waktunya, dan jebakan kalendernya (termasuk 30 Februari) akan kita bedah di chapter berikutnya.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

boolean-null.sql

Unduh berkas
sql
SELECT id, nama, aktif
FROM pelanggan
WHERE aktif IS NOT TRUE
ORDER BY id;

SELECT id, nama
FROM pelanggan
WHERE aktif IS UNKNOWN
ORDER BY id;

SELECT (NULL::boolean AND true) IS NULL AS nol_dan_benar,
       (NULL::boolean OR false) IS NULL AS nol_atau_salah,
       (NOT NULL::boolean) IS NULL AS bukan_nol;

buat-tabel.sql

Unduh berkas
sql
CREATE TABLE pelanggan (
    id      integer PRIMARY KEY,
    nama    text NOT NULL,
    aktif   boolean DEFAULT true,
    premium boolean NOT NULL DEFAULT false
);

INSERT INTO pelanggan (id, nama, aktif, premium) VALUES
    (1, 'Budi', true, 'f'),
    (2, 'Siti', 't', '1'),
    (3, 'Toko Maju Jaya', '1', false),
    (4, 'Rina', 'no', true),
    (5, 'Agus', NULL, 'off');

SELECT id, nama, aktif, premium
FROM pelanggan
ORDER BY id;

literal-boolean.sql

Unduh berkas
sql
SELECT true AS kata_kunci,
       'true'::boolean AS string_true,
       'TRUE'::boolean AS huruf_besar,
       't'::boolean AS singkat_t;

SELECT false AS kata_kunci,
       'f'::boolean AS singkat_f,
       '1'::boolean AS angka_satu,
       '0'::boolean AS angka_nol;

SELECT 'yes'::boolean AS ya,
       'no'::boolean AS tidak,
       'on'::boolean AS nyala,
       'off'::boolean AS mati;

literal-invalid.sql

Unduh berkas
sql
INSERT INTO pelanggan (id, nama, aktif, premium)
VALUES (6, 'Dewi', 'benar', false);

where-boolean.sql

Unduh berkas
sql
SELECT id, nama
FROM pelanggan
WHERE aktif
ORDER BY id;

SELECT id, nama
FROM pelanggan
WHERE aktif = true
ORDER BY id;

SELECT id, nama
FROM pelanggan
WHERE NOT premium
ORDER BY id;