Filtering dengan daftar nilai (IN) menangani pilihan diskrit, tetapi banyak pertanyaan berbentuk rentang: produk dengan harga dua sampai lima ribu rupiah, transaksi kuartal pertama, stok di bawah ambang aman. Kondisi harga >= 2000 AND harga <= 4500 menjawabnya, tetapi operator BETWEEN membuat maksud itu terbaca seperti bahasa manusia: harga BETWEEN 2000 AND 4500. Kedua bentuk itu identik sepenuhnya — termasuk satu detail yang membedakan BETWEEN dari intuisi sebagian orang: rentangnya inklusif di kedua ujung. Pada chapter ini kita menerapkan BETWEEN pada angka, tanggal, dan teks, membedah ekuivalensinya dengan >= AND <=, dan menutup dengan satu kejutan urutan kamus yang membuat BETWEEN pada teks berperilaku tak terduga.

Menyiapkan Tabel Latihan #

Tabel produk Toko Maju Jaya yang sama kembali dipakai — kolom harga (angka), tanggal_masuk (tanggal), nama dan promo (teks) semuanya akan menjadi bahan demo rentang:

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

BETWEEN pada Angka: Inklusif di Kedua Ujung #

Bentuk dasarnya: ekspresi BETWEEN batas_bawah AND batas_atas. Baris lolos bila nilainya berada di rentang itu — termasuk nilainya yang tepat sama dengan batas bawah maupun batas atas. Tiga query berikut memperlihatkan ketiganya sekaligus, lengkap dengan satu kasus batas yang terbalik:

SELECT id, nama, harga FROM produk
WHERE harga BETWEEN 2000 AND 4500
ORDER BY harga, id;

SELECT id, nama, harga FROM produk
WHERE harga BETWEEN 2000 AND 2000
ORDER BY id;

SELECT id, nama, harga FROM produk
WHERE harga BETWEEN 4500 AND 2000
ORDER BY id;

Output yang Dihasilkan:

text
 id |      nama      |  harga  
----+----------------+---------
  6 | Penghapus      | 2000.00
  2 | Pulpen Hitam   | 3000.00
  8 | Penggaris 30cm | 3500.00
  1 | Buku Tulis 58  | 4500.00
(4 rows)

 id |   nama    |  harga  
----+-----------+---------
  6 | Penghapus | 2000.00
(1 row)

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

Mari kita bedah tiga hasil itu:

  1. harga BETWEEN 2000 AND 4500 menjaring empat produk — dan perhatikan dua baris di ujung: Penghapus (tepat 2000) dan Buku Tulis 58 (tepat 4500) ikut lolos. Batas bukan “sampai sebelum”, melainkan termasuk.
  2. harga BETWEEN 2000 AND 2000 adalah uji ekstrem inklusivitas: rentang menyusut menjadi satu titik, dan Penghapus tetap lolos — bukti bahwa kedua ujung benar-benar dimasukkan.
  3. harga BETWEEN 4500 AND 2000 (batas terbalik) tidak error, hanya mengembalikan nol baris. BETWEEN tidak menukar batas secara otomatis: kondisinya tetap harga >= 4500 AND harga <= 2000, yang mustahil dipenuhi nilai mana pun. Kesalahan urutan batas seperti ini hanya terlihat dari hasil kosongnya.

NOT BETWEEN #

Kebalikan rentang ditulis NOT BETWEEN — baris di luar rentang (di bawah batas bawah atau di atas batas atas) yang lolos. Bentuk NOT (harga BETWEEN ...) menghasilkan hal yang sama, mengikuti aturan NOT dari chapter AND OR NOT:

sql not-between.sql
SELECT id, nama, harga FROM produk
WHERE harga NOT BETWEEN 2000 AND 4500
ORDER BY harga, id;

SELECT id, nama, harga FROM produk
WHERE NOT (harga BETWEEN 2000 AND 4500)
ORDER BY harga, id;

Output yang Dihasilkan:

text
 id |       nama       |   harga   
----+------------------+-----------
  5 | Amplop Coklat    |   1500.00
  4 | Stapler Besar    |  24000.00
  3 | Kertas HVS A4    |  55000.00
  7 | Kalkulator Solar | 185000.00
(4 rows)

 id |       nama       |   harga   
----+------------------+-----------
  5 | Amplop Coklat    |   1500.00
  4 | Stapler Besar    |  24000.00
  3 | Kertas HVS A4    |  55000.00
  7 | Kalkulator Solar | 185000.00
(4 rows)

Kedua query mengembalikan empat baris yang sama persis: Amplop Coklat (1500, di bawah rentang) serta Stapler Besar, Kertas HVS A4, dan Kalkulator Solar (di atas rentang). Empat produk yang tadi lolos di BETWEEN kini tersaring keluar — hasil kedua bentuk saling melengkapi seperti isi dan kulitnya. Perlu diingat juga perilaku NULL-nya mengikuti logika tiga nilai: bila kolomnya NULL, BETWEEN bernilai NULL dan NOT BETWEEN pun demikian — barisnya hilang dari kedua hasil secara diam-diam, seperti biasa.

BETWEEN pada Tanggal #

Rentang tanggal adalah penggunaan BETWEEN yang paling sering muncul di laporan: kuartal, bulan berjalan, atau periode promosi. Literalnya ditulis dengan awalan DATE dan format ISO tetap. Dua query berikut memakai rentang kuartal pertama 2026 — satu dengan BETWEEN, satu dengan bentuk ekuivalennya:

SELECT id, nama, tanggal_masuk FROM produk
WHERE tanggal_masuk BETWEEN DATE '2026-01-01' AND DATE '2026-03-31'
ORDER BY tanggal_masuk, id;

SELECT id, nama, tanggal_masuk FROM produk
WHERE tanggal_masuk >= DATE '2026-01-01' AND tanggal_masuk <= DATE '2026-03-31'
ORDER BY tanggal_masuk, id;

Output yang Dihasilkan:

text
 id |       nama       | tanggal_masuk 
----+------------------+---------------
  3 | Kertas HVS A4    | 2026-01-05
  4 | Stapler Besar    | 2026-01-20
  5 | Amplop Coklat    | 2026-02-14
  6 | Penghapus        | 2026-02-14
  7 | Kalkulator Solar | 2026-03-02
  8 | Penggaris 30cm   | 2026-03-15
(6 rows)

 id |       nama       | tanggal_masuk 
----+------------------+---------------
  3 | Kertas HVS A4    | 2026-01-05
  4 | Stapler Besar    | 2026-01-20
  5 | Amplop Coklat    | 2026-02-14
  6 | Penghapus        | 2026-02-14
  7 | Kalkulator Solar | 2026-03-02
  8 | Penggaris 30cm   | 2026-03-15
(6 rows)

Enam produk masuk di kuartal pertama 2026 — kedua query mengembalikan baris dan urutan yang persis sama, membuktikan ekuivalensi BETWEEN dengan >= AND <= secara langsung. Dua produk dari akhir 2025 (Buku Tulis 58 dan Pulpen Hitam) tersaring keluar di kedua versi. Satu detail layak dicatat untuk kolom bertipe timestamp: batas TIMESTAMP '2026-03-31' berarti tepat pukul 00:00:00 di awal hari itu, sehingga transaksi pukul 10:00 pagi 31 Maret tidak lolos ke dalam rentang. Batas atas untuk kolom timestamp sebaiknya ditulis TIMESTAMP '2026-03-31 23:59:59' atau, lebih bersih lagi, memakai ujung eksklusif: waktu < DATE '2026-04-01'.

BETWEEN pada Teks: Ikut Urutan Kamus #

BETWEEN pada teks memakai perbandingan urutan kamus yang sudah dibahas di chapter Operator Perbandingan — dan di sinilah intuisi sering tersesat. Dua contoh berikut, satu pada nama dan satu pada promo:

SELECT id, nama FROM produk
WHERE nama BETWEEN 'A' AND 'D'
ORDER BY nama;

SELECT id, nama, promo FROM produk
WHERE promo BETWEEN 'Diskon 10%' AND 'Diskon 50%'
ORDER BY promo;

Output yang Dihasilkan:

text
 id |     nama      
----+---------------
  5 | Amplop Coklat
  1 | Buku Tulis 58
(2 rows)

 id |       nama       |   promo    
----+------------------+------------
  2 | Pulpen Hitam     | Diskon 10%
  7 | Kalkulator Solar | Diskon 25%
  8 | Penggaris 30cm   | Diskon 5%
  3 | Kertas HVS A4    | Diskon 50%
(4 rows)

Hasil pertama terlihat wajar: hanya Amplop Coklat dan Buku Tulis 58 yang lolos — nama-nama berawalan A dan B memang berada di antara 'A' dan 'D' menurut kamus, sementara nama berawalan K, P, dan S berada di luar rentang. Hasil kedua adalah kejutannya: rentang 'Diskon 10%' sampai 'Diskon 50%' menjaring empat promo, termasuk… Diskon 5%. Angka 5 yang secara numerik lebih kecil dari 10 ternyata berada di dalam rentang, karena teks dibandingkan karakter demi karakter: '5' punya byte lebih besar daripada '1', sehingga 'Diskon 5%' berada setelah 'Diskon 10%' dan 'Diskon 25%' di urutan kamus. Urutan tampilnya pun memperlihatkan hal yang sama — Diskon 5% muncul di antara Diskon 25% dan Diskon 50%.

Rentang dan daftar kini lengkap di tangan kita: IN untuk nilai diskrit, BETWEEN untuk rentang kontinu. Dua bentuk penyaringan itu punya satu batas yang sama — keduanya mencocokkan nilai secara persis. Untuk pertanyaan seperti “nama produk yang mengandung kata Penggaris” atau “semua promo yang diakhiri tanda persen”, kita butuh pencocokan pola: wildcard % dan _ milik LIKE, materi chapter berikutnya.

Referensi #

Berkas Sumber

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

between-angka.sql

Unduh berkas
sql
SELECT id, nama, harga FROM produk
WHERE harga BETWEEN 2000 AND 4500
ORDER BY harga, id;

SELECT id, nama, harga FROM produk
WHERE harga BETWEEN 2000 AND 2000
ORDER BY id;

SELECT id, nama, harga FROM produk
WHERE harga BETWEEN 4500 AND 2000
ORDER BY id;

between-tanggal.sql

Unduh berkas
sql
SELECT id, nama, tanggal_masuk FROM produk
WHERE tanggal_masuk BETWEEN DATE '2026-01-01' AND DATE '2026-03-31'
ORDER BY tanggal_masuk, id;

SELECT id, nama, tanggal_masuk FROM produk
WHERE tanggal_masuk >= DATE '2026-01-01' AND tanggal_masuk <= DATE '2026-03-31'
ORDER BY tanggal_masuk, id;

between-teks.sql

Unduh berkas
sql
SELECT id, nama FROM produk
WHERE nama BETWEEN 'A' AND 'D'
ORDER BY nama;

SELECT id, nama, promo FROM produk
WHERE promo BETWEEN 'Diskon 10%' AND 'Diskon 50%'
ORDER BY promo;

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

not-between.sql

Unduh berkas
sql
SELECT id, nama, harga FROM produk
WHERE harga NOT BETWEEN 2000 AND 4500
ORDER BY harga, id;

SELECT id, nama, harga FROM produk
WHERE NOT (harga BETWEEN 2000 AND 4500)
ORDER BY harga, id;