Klausa WHERE dari chapter sebelumnya menyaring baris lewat kondisi, dan hampir semua kondisi dibangun dari satu bata yang sama: operator perbandingan. harga > 20000, kategori = 'kertas', tanggal_masuk >= DATE '2026-01-01' — semuanya memakai operator yang mengembalikan nilai boolean dari dua nilai yang dibandingkan. Pada chapter ini kita membahas ketujuh operator itu satu per satu, lalu melihat bagaimana perilakunya berbeda untuk angka, tanggal, timestamp, dan teks — termasuk satu aturan emas yang membingkai semuanya: perbandingan dengan NULL tidak pernah menghasilkan true ataupun false.
Tujuh Operator Perbandingan #
PostgreSQL menyediakan tujuh operator perbandingan dasar. Tabel berikut merangkum semuanya beserta contoh kondisi yang bernilai true untuk baris Kertas HVS A4 (harga 55000, kategori kertas):
| Operator | Arti | Contoh |
|---|---|---|
= | sama dengan | kategori = 'kertas' |
<> | tidak sama dengan (bentuk standar SQL) | kategori <> 'alat tulis' |
!= | tidak sama dengan (bentuk lain dari <>) | kategori != 'alat tulis' |
< | kurang dari | harga < 100000 |
<= | kurang dari atau sama dengan | harga <= 55000 |
> | lebih dari | harga > 50000 |
>= | lebih dari atau sama dengan | harga >= 55000 |
Dua operator “tidak sama dengan” itu identik sepenuhnya — <> adalah bentuk yang dianjurkan standar SQL, sedangkan != adalah bentuk populer yang juga diterima PostgreSQL. Keduanya boleh dipakai bergantian, tetapi konsistensi dalam satu tim lebih penting daripada pilihan bentuknya. Tabel latihan kita masih sama — produk milik Toko Maju Jaya — ditambah satu tabel kecil penyesuaian_stok yang mencatat koreksi stok beserta waktu kejadiannya:
CREATE TABLE produk (
id integer PRIMARY KEY,
nama text NOT NULL,
kategori text NOT NULL,
harga numeric(10, 2) NOT NULL,
stok integer NOT NULL,
aktif boolean NOT NULL,
tanggal_masuk date,
promo text
);
INSERT INTO produk (id, nama, kategori, harga, stok, aktif, tanggal_masuk, promo) VALUES
(1, 'Buku Tulis 58', 'alat tulis', 4500, 120, true, DATE '2025-11-10', NULL),
(2, 'Pulpen Hitam', 'alat tulis', 3000, 200, true, DATE '2025-12-01', 'Diskon 10%'),
(3, 'Kertas HVS A4', 'kertas', 55000, 40, true, DATE '2026-01-05', 'Diskon 50%'),
(4, 'Stapler Besar', 'alat tulis', 24000, 15, false, DATE '2026-01-20', NULL),
(5, 'Amplop Coklat', 'kertas', 1500, 500, true, DATE '2026-02-14', NULL),
(6, 'Penghapus', 'alat tulis', 2000, 0, false, DATE '2026-02-14', NULL),
(7, 'Kalkulator Solar', 'elektronik', 185000, 8, true, DATE '2026-03-02', 'Diskon 25%'),
(8, 'Penggaris 30cm', 'alat tulis', 3500, 85, true, DATE '2026-03-15', 'Diskon 5%');
CREATE TABLE penyesuaian_stok (
id integer PRIMARY KEY,
produk_id integer NOT NULL,
perubahan integer NOT NULL,
waktu timestamp NOT NULL
);
INSERT INTO penyesuaian_stok (id, produk_id, perubahan, waktu) VALUES
(1, 3, -10, TIMESTAMP '2026-01-15 08:30:00'),
(2, 3, 5, TIMESTAMP '2026-01-15 15:45:00'),
(3, 7, -2, TIMESTAMP '2026-02-02 09:10:00'),
(4, 1, 50, TIMESTAMP '2026-03-20 16:00:00');Output yang Dihasilkan:
CREATE TABLE
INSERT 0 8
CREATE TABLE
INSERT 0 4Sama Dengan dan Tidak Sama Dengan #
Operator = meloloskan baris yang nilainya persis sama; <> dan != kebalikannya. Tiga perintah berikut memakai ketiganya pada kolom kategori:
SELECT id, nama, kategori FROM produk
WHERE kategori = 'elektronik'
ORDER BY id;
SELECT id, nama, kategori FROM produk
WHERE kategori <> 'alat tulis'
ORDER BY id;
SELECT id, nama, kategori FROM produk
WHERE kategori != 'alat tulis'
ORDER BY id;Output yang Dihasilkan:
id | nama | kategori
----+------------------+------------
7 | Kalkulator Solar | elektronik
(1 row)
id | nama | kategori
----+------------------+------------
3 | Kertas HVS A4 | kertas
5 | Amplop Coklat | kertas
7 | Kalkulator Solar | elektronik
(3 rows)
id | nama | kategori
----+------------------+------------
3 | Kertas HVS A4 | kertas
5 | Amplop Coklat | kertas
7 | Kalkulator Solar | elektronik
(3 rows)Perintah pertama hanya menjaring Kalkulator Solar — satu-satunya produk elektronik. Perintah kedua dan ketiga mengembalikan hasil yang persis sama: tiga produk yang kategorinya bukan alat tulis (Kertas HVS A4, Amplop Coklat, Kalkulator Solar). Identitas hasil itu bukan kebetulan; <> dan != adalah operator yang sama persis, cukup pilih satu sebagai kebiasaan.
Perhatikan juga perbandingan teks bersifat case-sensitive: kategori = 'Kertas' tidak akan cocok dengan 'kertas' karena huruf besar-kecilnya ikut dibandingkan. Perilaku ini dan cara menyiasatinya dibahas di chapter LIKE dan ILIKE.
Membandingkan Angka #
Empat operator urutan (<, <=, >, >=) bekerja seperti matematika sekolah. Satu hal yang perlu diperhatikan: hasil ORDER BY di bawah sengaja memakai kolom yang dibandingkan, sehingga kita bisa melihat posisi batas dengan jelas:
SELECT id, nama, harga FROM produk
WHERE harga >= 24000
ORDER BY harga, id;
SELECT id, nama, harga FROM produk
WHERE harga > 100000
ORDER BY harga, id;
SELECT id, nama, stok FROM produk
WHERE stok <= 15
ORDER BY stok, id;
SELECT id, nama, stok FROM produk
WHERE stok < 10
ORDER BY stok, id;Output yang Dihasilkan:
id | nama | harga
----+------------------+-----------
4 | Stapler Besar | 24000.00
3 | Kertas HVS A4 | 55000.00
7 | Kalkulator Solar | 185000.00
(3 rows)
id | nama | harga
----+------------------+-----------
7 | Kalkulator Solar | 185000.00
(1 row)
id | nama | stok
----+------------------+------
6 | Penghapus | 0
7 | Kalkulator Solar | 8
4 | Stapler Besar | 15
(3 rows)
id | nama | stok
----+------------------+------
6 | Penghapus | 0
7 | Kalkulator Solar | 8
(2 rows)Bedah empat hasil tersebut:
harga >= 24000menjaring tiga produk, termasukStapler Besaryang harganya tepat 24000 — operator>=meloloskan nilai yang sama dengan batas.harga > 100000hanya menjaringKalkulator Solar;Kertas HVS A4(55000) tidak lolos karena 55000 tidak lebih dari 100000.stok <= 15menjaring tiga produk dengan stok paling tipis, termasukStapler Besaryang tepat 15.stok < 10menjaring dua produk —Stapler Besar(15) kini gugur karena 15 tidak kurang dari 10. Selisih satu karakter (<=vs<) mengubah hasil dua menjadi tiga baris; itulah alasan membaca operator dengan teliti.
Membandingkan Tanggal dan Timestamp #
Tanggal dan timestamp dibandingkan secara kronologis — tanggal yang lebih awal selalu “kurang dari” tanggal yang lebih baru. Literalnya ditulis dengan awalan DATE atau TIMESTAMP dan nilai tetap dalam format ISO, sehingga hasilnya tidak bergantung pada setting regional server:
SELECT id, nama, tanggal_masuk FROM produk
WHERE tanggal_masuk > DATE '2026-02-01'
ORDER BY tanggal_masuk, id;
SELECT id, produk_id, perubahan, waktu FROM penyesuaian_stok
WHERE waktu >= TIMESTAMP '2026-01-15 09:00:00'
ORDER BY waktu, id;
SELECT id, produk_id, perubahan, waktu FROM penyesuaian_stok
WHERE waktu < TIMESTAMP '2026-02-01'
ORDER BY waktu, id;Output yang Dihasilkan:
id | nama | tanggal_masuk
----+------------------+---------------
5 | Amplop Coklat | 2026-02-14
6 | Penghapus | 2026-02-14
7 | Kalkulator Solar | 2026-03-02
8 | Penggaris 30cm | 2026-03-15
(4 rows)
id | produk_id | perubahan | waktu
----+-----------+-----------+---------------------
2 | 3 | 5 | 2026-01-15 15:45:00
3 | 7 | -2 | 2026-02-02 09:10:00
4 | 1 | 50 | 2026-03-20 16:00:00
(3 rows)
id | produk_id | perubahan | waktu
----+-----------+-----------+---------------------
1 | 3 | -10 | 2026-01-15 08:30:00
2 | 3 | 5 | 2026-01-15 15:45:00
(2 rows)Perintah pertama menjaring empat produk yang masuk setelah 1 Februari 2026. Dua perintah berikutnya bekerja pada kolom timestamp: perbandingan waktu >= TIMESTAMP '2026-01-15 09:00:00' menjaring tiga penyesuaian, dan yang menarik adalah penyesuaian pertama (pukul 08:30) yang tersaring keluar — timestamp membandingkan sampai level detik, bahkan mikrodetik, sehingga pukul 08:30 jelas lebih kecil daripada 09:00. Perintah ketiga memperlihatkan sisi sebaliknya: dua penyesuaian bulan Januari lolos karena terjadi sebelum 1 Februari.
Membandingkan Teks: Urutan Kamus #
Operator < dan > pada teks memakai urutan kamus (lexicographic) — perbandingan karakter demi karakter dari kiri. Kata yang lebih pendek yang menjadi awalan kata lain selalu lebih kecil, sama seperti di kamus: Stapler muncul sebelum Stapler Besar. Namun ada detail yang sering mengejutkan: di server ini (locale C), huruf besar dibandingkan sebagai byte yang lebih kecil daripada huruf kecil:
SELECT id, nama FROM produk
WHERE nama < 'Penghapus'
ORDER BY nama;
SELECT id, nama FROM produk
WHERE nama >= 'P'
ORDER BY nama;
SELECT 'Makanan' < 'minuman' AS huruf_besar_dulu,
'a' < 'A' AS a_vs_A,
'Stapler' < 'Stapler Besar' AS prefiks_lebih_pendek;Output yang Dihasilkan:
id | nama
----+------------------
5 | Amplop Coklat
1 | Buku Tulis 58
7 | Kalkulator Solar
3 | Kertas HVS A4
8 | Penggaris 30cm
(5 rows)
id | nama
----+----------------
8 | Penggaris 30cm
6 | Penghapus
2 | Pulpen Hitam
4 | Stapler Besar
(4 rows)
huruf_besar_dulu | a_vs_a | prefiks_lebih_pendek
------------------+--------+----------------------
t | f | t
(1 row)Mari kita bedah tiga hasil itu:
nama < 'Penghapus'menjaring lima produk yang urut kamusnya sebelum kata “Penghapus” — termasukPenggaris 30cm, karenaPengg...lebih kecil daripadaPengh...(hurufgsebelumh). Bandingkan kamus sungguhan: “penggaris” memang tercantum sebelum “penghapus”.nama >= 'P'menjaring empat produk: tiga yang berawalan P (Pulpen Hitam,Penghapus,Penggaris 30cm) plusStapler Besaryang lolos karena awalanSmemang lebih besar daripadaPdi urutan kamus. Perhatikan juga bahwa setiap kata berawalan P dinilai lebih besar daripada satu hurufP— kata yang lebih panjang dengan awalan sama selalu lebih besar.- Baris kebenaran terakhir membuktikan tiga aturan sekaligus:
'Makanan' < 'minuman'karenaM(byte lebih kecil) mengalah sebelumavsidibandingkan;'a' < 'A'bernilaifalsekarena huruf kecil punya byte lebih besar; dan'Stapler' < 'Stapler Besar'karena prefiks yang lebih pendek selalu lebih dulu.
Perbandingan dengan NULL Selalu NULL #
Aturan terpenting sebelum melangkah lebih jauh: NULL bukan nilai, melainkan penanda “tidak ada nilai”. Operator perbandingan apa pun yang menyentuh NULL menghasilkan NULL, bukan true atau false. Ekspresi 5000 > NULL ibarat ditanya “apakah lima ribu lebih besar dari sesuatu yang tidak diketahui nilainya?” — jawaban yang jujur memang “tidak bisa dipastikan”:
SELECT 5000 > NULL AS angka_dibanding_null,
'kertas' = NULL AS teks_dibanding_null;
SELECT count(*) AS baris_yang_lolos
FROM produk
WHERE harga > NULL;Output yang Dihasilkan:
angka_dibanding_null | teks_dibanding_null
----------------------+---------------------
|
(1 row)
baris_yang_lolos
------------------
0
(1 row)Dua kolom pada baris pertama tampil kosong — itulah psql menampilkan NULL; bukan false, bukan true. Konsekuensinya di WHERE sangat nyata: WHERE harga > NULL mengembalikan nol baris tanpa pesan error apa pun, meski harga delapan baris semuanya terisi. WHERE hanya meloloskan baris yang kondisinya true; NULL tidak pernah true, jadi barisnya dibuang — perilaku yang sama dengan jebakan promo != 'Diskon 50%' di chapter WHERE.
Ketujuh operator perbandingan kini lengkap di tangan kita: sama dengan, tidak sama dengan, dan empat operator urutan untuk angka, tanggal, timestamp, maupun teks. Kondisi nyata di aplikasi jarang sesederhana itu — “produk aktif dan harga di bawah lima ribu”, “kategori kertas atau elektronik” — dan untuk menggabungkan kondisi itulah PostgreSQL menyediakan operator logika AND, OR, dan NOT, materi chapter berikutnya.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
banding-tanggal.sql
Unduh berkasSELECT id, nama, tanggal_masuk FROM produk
WHERE tanggal_masuk > DATE '2026-02-01'
ORDER BY tanggal_masuk, id;
SELECT id, produk_id, perubahan, waktu FROM penyesuaian_stok
WHERE waktu >= TIMESTAMP '2026-01-15 09:00:00'
ORDER BY waktu, id;
SELECT id, produk_id, perubahan, waktu FROM penyesuaian_stok
WHERE waktu < TIMESTAMP '2026-02-01'
ORDER BY waktu, id;
banding-teks.sql
Unduh berkasSELECT id, nama FROM produk
WHERE nama < 'Penghapus'
ORDER BY nama;
SELECT id, nama FROM produk
WHERE nama >= 'P'
ORDER BY nama;
SELECT 'Makanan' < 'minuman' AS huruf_besar_dulu,
'a' < 'A' AS a_vs_A,
'Stapler' < 'Stapler Besar' AS prefiks_lebih_pendek;
buat-tabel.sql
Unduh berkasCREATE TABLE produk (
id integer PRIMARY KEY,
nama text NOT NULL,
kategori text NOT NULL,
harga numeric(10, 2) NOT NULL,
stok integer NOT NULL,
aktif boolean NOT NULL,
tanggal_masuk date,
promo text
);
INSERT INTO produk (id, nama, kategori, harga, stok, aktif, tanggal_masuk, promo) VALUES
(1, 'Buku Tulis 58', 'alat tulis', 4500, 120, true, DATE '2025-11-10', NULL),
(2, 'Pulpen Hitam', 'alat tulis', 3000, 200, true, DATE '2025-12-01', 'Diskon 10%'),
(3, 'Kertas HVS A4', 'kertas', 55000, 40, true, DATE '2026-01-05', 'Diskon 50%'),
(4, 'Stapler Besar', 'alat tulis', 24000, 15, false, DATE '2026-01-20', NULL),
(5, 'Amplop Coklat', 'kertas', 1500, 500, true, DATE '2026-02-14', NULL),
(6, 'Penghapus', 'alat tulis', 2000, 0, false, DATE '2026-02-14', NULL),
(7, 'Kalkulator Solar', 'elektronik', 185000, 8, true, DATE '2026-03-02', 'Diskon 25%'),
(8, 'Penggaris 30cm', 'alat tulis', 3500, 85, true, DATE '2026-03-15', 'Diskon 5%');
CREATE TABLE penyesuaian_stok (
id integer PRIMARY KEY,
produk_id integer NOT NULL,
perubahan integer NOT NULL,
waktu timestamp NOT NULL
);
INSERT INTO penyesuaian_stok (id, produk_id, perubahan, waktu) VALUES
(1, 3, -10, TIMESTAMP '2026-01-15 08:30:00'),
(2, 3, 5, TIMESTAMP '2026-01-15 15:45:00'),
(3, 7, -2, TIMESTAMP '2026-02-02 09:10:00'),
(4, 1, 50, TIMESTAMP '2026-03-20 16:00:00');
null-perbandingan.sql
Unduh berkasSELECT 5000 > NULL AS angka_dibanding_null,
'kertas' = NULL AS teks_dibanding_null;
SELECT count(*) AS baris_yang_lolos
FROM produk
WHERE harga > NULL;
operator-sama.sql
Unduh berkasSELECT id, nama, kategori FROM produk
WHERE kategori = 'elektronik'
ORDER BY id;
SELECT id, nama, kategori FROM produk
WHERE kategori <> 'alat tulis'
ORDER BY id;
SELECT id, nama, kategori FROM produk
WHERE kategori != 'alat tulis'
ORDER BY id;
urutan-angka.sql
Unduh berkasSELECT id, nama, harga FROM produk
WHERE harga >= 24000
ORDER BY harga, id;
SELECT id, nama, harga FROM produk
WHERE harga > 100000
ORDER BY harga, id;
SELECT id, nama, stok FROM produk
WHERE stok <= 15
ORDER BY stok, id;
SELECT id, nama, stok FROM produk
WHERE stok < 10
ORDER BY stok, id;