Perbandingan = menuntut teks yang persis sama — ia tidak bisa menjawab “produk mana yang namanya diawali kata Peng?” atau “promo mana yang mengandung angka 50%?”. Untuk pertanyaan berpola, SQL menyediakan operator LIKE dengan dua wildcard: % untuk segala jumlah karakter dan _ untuk tepat satu karakter. Varian ILIKE melakukan hal yang sama tanpa memedulikan besar kecil huruf. Pada chapter ini kita membedah kedua wildcard itu, menguji sensitivitas huruf, lalu mempelajari karakter escape — satu-satunya cara mencari teks yang benar-benar mengandung tanda % itu sendiri, seperti label promo Diskon 50% di tabel latihan kita.

Menyiapkan Tabel Latihan #

Tabel produk Toko Maju Jaya yang sama dipakai untuk terakhir kalinya di rangkaian chapter filtering dasar ini. Kolom nama menyediakan variasi huruf besar-kecil yang dibutuhkan demo ILIKE, dan kolom promo dengan nilai seperti Diskon 50% menjadi bahan utama demo escape:

sql buat-tabel.sql
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%');

Output yang Dihasilkan:

text
CREATE TABLE
INSERT 0 8

Dua Wildcard: % dan _ #

Pola LIKE dibangun dari teks biasa plus dua karakter istimewa. Tabel berikut merangkum keduanya:

WildcardArtiContoh polaCocok dengan
%nol atau lebih karakter apa pun'Peng%'Penghapus, Penggaris 30cm
% di tengahsegala teks di antaranya'%30cm%'Penggaris 30cm
_tepat satu karakter apa pun'_enghapus%'Penghapus
_ di tengahtepat satu karakter di posisinya'Penggaris 30_m'Penggaris 30cm

Satu aturan penting sebelum melihat contoh: pola LIKE harus cocok dengan seluruh nilai kolom, bukan sebagian — perilakunya seperti pola yang dijangkar di dua ujung. Mencari nama yang “mengandung” kata tertentu karena itu selalu ditulis dengan % di kedua sisi:

sql like-dasar.sql
SELECT id, nama FROM produk
WHERE nama LIKE 'Peng%'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama LIKE '%Hitam'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama LIKE '%30cm%'
ORDER BY id;

Output yang Dihasilkan:

text
 id |      nama      
----+----------------
  6 | Penghapus
  8 | Penggaris 30cm
(2 rows)

 id |     nama     
----+--------------
  2 | Pulpen Hitam
(1 row)

 id |      nama      
----+----------------
  8 | Penggaris 30cm
(1 row)

Mari kita bedah tiga pola itu:

  1. nama LIKE 'Peng%' menjaring dua produk yang namanya dimulai dengan Peng: Penghapus dan Penggaris 30cm. Wildcard % di ujung menyerap sisa nama sepanjang apa pun.
  2. nama LIKE '%Hitam' menjaring satu produk yang namanya berakhir dengan Hitam. Tanpa % di awal, pola ini menuntut nama dimulai persis dengan Hitam — Pulpen Hitam hanya lolos karena %-nya menjelma menjadi Pulpen .
  3. nama LIKE '%30cm%' menjaring nama yang mengandung 30cm di mana pun posisinya — pola “mengandung” klasik dengan % mengapit di dua sisi.

Wildcard _ Mewakili Tepat Satu Karakter #

Wildcard _ lebih ketat dari %: satu garis bawah mewakili tepat satu karakter — bukan nol, bukan dua. Perbandingan berikut memperlihatkan bedanya pada data yang sama:

sql underscore.sql
SELECT id, nama FROM produk
WHERE nama LIKE '_enghapus%'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama LIKE 'Penggaris 30_m'
ORDER BY id;

Output yang Dihasilkan:

text
 id |   nama    
----+-----------
  6 | Penghapus
(1 row)

 id |      nama      
----+----------------
  8 | Penggaris 30cm
(1 row)

Pola '_enghapus%' menjaring Penghapus — karakter P diambil alih oleh _, sisanya harus cocok huruf demi huruf. Bandingkan dengan 'Peng%' di bagian sebelumnya yang menjaring dua produk: _ menolak Penggaris 30cm karena huruf kedua Penggaris adalah e, bukan n. Pola kedua, 'Penggaris 30_m', memperlihatkan _ di tengah pola: satu karakter apa pun boleh duduk di posisi itu — pada Penggaris 30cm, posisi itu diisi huruf c. Karena _ selalu tepat satu karakter, pola seperti '_ng%' akan menolak nama yang hanya satu huruf pendeknya tidak pas — ketelitian inilah yang membuat _ berguna untuk pola dengan panjang tetap, misalnya kode voucher 'DISC_2026_%'.

LIKE versus ILIKE: Sensitivitas Huruf #

LIKE membandingkan huruf besar-kecil secara sensitif — di server dengan locale C, 'hvs' dan 'HVS' adalah byte yang berbeda. ILIKE adalah varian case-insensitive dari LIKE yang dimiliki PostgreSQL (bukan standar SQL):

sql ilike.sql
SELECT id, nama FROM produk
WHERE nama LIKE '%hvs%'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama ILIKE '%hvs%'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama ILIKE 'p%'
ORDER BY id;

Output yang Dihasilkan:

text
 id | nama 
----+------
(0 rows)

 id |     nama      
----+---------------
  3 | Kertas HVS A4
(1 row)

 id |      nama      
----+----------------
  2 | Pulpen Hitam
  6 | Penghapus
  8 | Penggaris 30cm
(3 rows)

Tiga hasil itu menceritakan perbedaannya dengan lengkap:

  1. LIKE '%hvs%' mengembalikan nol baris — nama Kertas HVS A4 menyimpan HVS dengan huruf besar, dan LIKE menolak menyamakannya dengan hvs.
  2. ILIKE '%hvs%' menjaring Kertas HVS A4 — huruf besar-kecil diabaikan sepenuhnya, pola dan data dicocokkan tanpa memedulikan casing.
  3. ILIKE 'p%' menjaring semua nama berawalan huruf p dalam casing apa pun: Pulpen Hitam, Penghapus, dan Penggaris 30cm.

Untuk data yang namanya dicampur-campur casingnya (hasil impor, input pengguna tanpa normalisasi), ILIKE sering menjadi penyelamat pencarian. Alternatifnya adalah menormalkan kedua sisi dengan lower(nama) LIKE 'peng%' — pola yang portabel ke database lain yang tidak punya ILIKE, dengan catatan fungsi lower() pada kolom membuat index biasa tidak terpakai kecuali dibuat index ekspresi.

Karakter Escape untuk % Literal #

Bagaimana mencari promo yang mengandung tanda persen itu sendiri? Pola '%50%%' tidak menjawabnya — dua % bersebelahan tetap dibaca sebagai wildcard. Solusinya adalah karakter escape: satu karakter yang dinaikkan derajatnya untuk membatalkan makna istimewa karakter sesudahnya. Secara default PostgreSQL memakai garis miring terbalik (\) sebagai escape, dan klausa ESCAPE membuatnya eksplisit:

sql escape.sql
SELECT id, nama, promo FROM produk
WHERE promo LIKE '%50\%%' ESCAPE '\'
ORDER BY id;

SELECT id, nama, promo FROM produk
WHERE promo LIKE '%25\%%'
ORDER BY id;

SELECT 'Diskon 50%' LIKE '%\%%' AS mengandung_persen,
       'Buku Tulis 58' LIKE '%\%%' AS tanpa_persen;

Output yang Dihasilkan:

text
 id |     nama      |   promo    
----+---------------+------------
  3 | Kertas HVS A4 | Diskon 50%
(1 row)

 id |       nama       |   promo    
----+------------------+------------
  7 | Kalkulator Solar | Diskon 25%
(1 row)

 mengandung_persen | tanpa_persen 
-------------------+--------------
 t                 | f
(1 row)

Pola '%50\%%' terlihat seperti sandi, tetapi dibaca dari kiri ke kanan menjadi masuk akal:

  1. % — nol atau lebih karakter apa pun (penyerap awal).
  2. 50 — teks biasa yang harus ada.
  3. \% — tanda persen literal, karena \ membatalkan peran % sebagai wildcard.
  4. % — wildcard penutup, menyerap sisa teks apa pun setelah persen.

Hasilnya: satu baris — Kertas HVS A4 dengan promo Diskon 50%. Query kedua memakai pola yang sama tanpa klausa ESCAPE dan tetap bekerja, karena \ memang escape default LIKE di PostgreSQL; klausa ESCAPE '\' hanya membuatnya eksplisit. Query ketiga menguji pola minimal '%\%%' (mengandung satu persen literal): cocok untuk 'Diskon 50%' dan menolak 'Buku Tulis 58' yang tidak punya tanda persen. Mencari teks yang mengandung backslash literal mengikuti logika yang sama — pola backslash di-escape dengan backslash lain, misalnya '%\\%'.

Sekilas Operator Regex #

LIKE dengan dua wildcardnya kuat untuk pola sederhana, tetapi pola seperti “nama yang mengandung angka” tetap canggung — karakter angka harus disebut satu-satu. PostgreSQL punya senjata yang jauh lebih ekspresif: operator ~ untuk regular expression. Dua contoh singkat berikut hanya sepintas — pembahasan penuhnya menempati chapter Regular Expressions di section ini:

SELECT id, nama FROM produk
WHERE nama ~ '^Peng'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama ~ '[0-9]+'
ORDER BY id;

Output yang Dihasilkan:

text
 id |      nama      
----+----------------
  6 | Penghapus
  8 | Penggaris 30cm
(2 rows)

 id |      nama      
----+----------------
  1 | Buku Tulis 58
  3 | Kertas HVS A4
  8 | Penggaris 30cm
(3 rows)

Pola '^Peng' berarti “diawali Peng” — hasilnya sama dengan LIKE 'Peng%', dan tabel perbandingannya pun lengkap: ^ dan $ di regex berperan seperti jangkar, menggantikan posisi % di LIKE. Pola '[0-9]+' — “mengandung satu atau lebih digit” — menjaring tiga nama: Buku Tulis 58, Kertas HVS A4, dan Penggaris 30cm. Pola semacam ini mustahil ditulis dengan LIKE tanpa merangkai puluhan variasi wildcard. Ketika kebutuhan pola melampaui % dan _, regex adalah jawabannya.

Dari WHERE sederhana sampai pencocokan pola, perangkat filtering teks kita kini lengkap: perbandingan persis, rentang, daftar, dan pola dengan escape. Satu topik penyaringan masih tersisa dan menjadi semakin penting justru karena semua operator di section ini “gagal diam-diam” terhadapnya: NULL. Operator IS NULL, IS NOT NULL, dan IS DISTINCT FROM — topik chapter berikutnya — adalah alat yang menutup celah itu.

Referensi #

Berkas Sumber

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

buat-tabel.sql

Unduh berkas
sql
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%');

escape.sql

Unduh berkas
sql
SELECT id, nama, promo FROM produk
WHERE promo LIKE '%50\%%' ESCAPE '\'
ORDER BY id;

SELECT id, nama, promo FROM produk
WHERE promo LIKE '%25\%%'
ORDER BY id;

SELECT 'Diskon 50%' LIKE '%\%%' AS mengandung_persen,
       'Buku Tulis 58' LIKE '%\%%' AS tanpa_persen;

ilike.sql

Unduh berkas
sql
SELECT id, nama FROM produk
WHERE nama LIKE '%hvs%'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama ILIKE '%hvs%'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama ILIKE 'p%'
ORDER BY id;

like-dasar.sql

Unduh berkas
sql
SELECT id, nama FROM produk
WHERE nama LIKE 'Peng%'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama LIKE '%Hitam'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama LIKE '%30cm%'
ORDER BY id;

regex-preview.sql

Unduh berkas
sql
SELECT id, nama FROM produk
WHERE nama ~ '^Peng'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama ~ '[0-9]+'
ORDER BY id;

underscore.sql

Unduh berkas
sql
SELECT id, nama FROM produk
WHERE nama LIKE '_enghapus%'
ORDER BY id;

SELECT id, nama FROM produk
WHERE nama LIKE 'Penggaris 30_m'
ORDER BY id;