Pertanyaan penyaringan sering berbentuk rentang: “harga antara lima ribu sampai sepuluh ribu”, “pesanan sepanjang Februari”, “stok di bawah sepuluh”. Rentang selalu bisa ditulis dengan kombinasi >= dan <= yang dihubungkan AND, tetapi MySQL menyediakan operator khusus BETWEEN yang membacanya jauh lebih dekat ke bahasa manusia. Pada chapter ini kita akan menguji BETWEEN pada angka dan tanggal, membuktikan dengan data nyata bahwa kedua nilai batasnya ikut di dalam hasil, membandingkannya dengan padanan >= AND <=, lalu mencatat perilaku yang mengejutkan ketika kita menulis rentang terbalik.

Menyiapkan Tabel Latihan #

Kita pakai tabel produk untuk rentang angka dan tabel pesanan untuk rentang tanggal, mengikuti pola data section ini:

sql
DROP DATABASE IF EXISTS belajar_filter;
CREATE DATABASE belajar_filter;
USE belajar_filter;

Output yang Dihasilkan:

text
Query OK, 0 rows affected, 1 warning (0.00 sec)

Query OK, 1 row affected (0.00 sec)

Database changed
sql
CREATE TABLE produk (
  id INT AUTO_INCREMENT PRIMARY KEY,
  nama VARCHAR(100) NOT NULL,
  kategori VARCHAR(50) NOT NULL,
  harga DECIMAL(10,2) NOT NULL,
  stok INT NOT NULL DEFAULT 0
);

INSERT INTO produk (nama, kategori, harga, stok) VALUES
  ('Buku Tulis Sidu 38', 'Alat Tulis', 4500.00, 120),
  ('Pensil 2B', 'Alat Tulis', 3000.00, 200),
  ('Penghapus Putih', 'Alat Tulis', 2500.00, 150),
  ('Pulpen Gel Hitam', 'Alat Tulis', 5000.00, 80),
  ('Spidol Permanen', 'Alat Tulis', 10000.00, 45),
  ('Kertas HVS A4', 'Kertas', 27500.00, 20),
  ('Kertas Origami', 'Kertas', 12000.00, 60),
  ('Amplop Coklat', 'Kertas', 800.00, 300),
  ('Stipo 12 Gram', 'Perekat', 6000.00, 0),
  ('Selotip Bening', 'Perekat', 8000.00, 55);

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Query OK, 10 rows affected (0.00 sec)
Records: 10  Duplicates: 0  Warnings: 0
sql
CREATE TABLE pesanan (
  id INT AUTO_INCREMENT PRIMARY KEY,
  nama_pelanggan VARCHAR(100) NOT NULL,
  nama_produk VARCHAR(100) NOT NULL,
  jumlah INT NOT NULL,
  total DECIMAL(10,2) NOT NULL,
  tanggal DATE NOT NULL
);

INSERT INTO pesanan (nama_pelanggan, nama_produk, jumlah, total, tanggal) VALUES
  ('Budi Santoso', 'Pensil 2B', 10, 30000.00, '2026-01-05'),
  ('Siti Rahayu', 'Kertas HVS A4', 2, 55000.00, '2026-01-18'),
  ('Dewi Lestari', 'Spidol Permanen', 3, 30000.00, '2026-02-01'),
  ('Budi Santoso', 'Kertas Origami', 5, 60000.00, '2026-02-14'),
  ('Maya Putri', 'Buku Tulis Sidu 38', 20, 90000.00, '2026-02-28'),
  ('Eko Prasetyo', 'Pulpen Gel Hitam', 4, 20000.00, '2026-03-05'),
  ('Fitri Handayani', 'Selotip Bening', 6, 48000.00, '2026-03-12'),
  ('Budi Santoso', 'Penghapus Putih', 12, 30000.00, '2026-03-25'),
  ('Budi Santoso', 'Pulpen Gel Hitam', 2, 10000.00, '2026-03-25');

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Query OK, 9 rows affected (0.00 sec)
Records: 9  Duplicates: 0  Warnings: 0

Sintaks BETWEEN #

Operator BETWEEN diikuti dua nilai — batas bawah dan batas atas — yang dipisahkan keyword AND. Query berikut mengambil produk dengan harga 5000 hingga 10000:

sql
SELECT nama, harga
FROM produk
WHERE harga BETWEEN 5000 AND 10000
ORDER BY id;

Output yang Dihasilkan:

text
+------------------+----------+
| nama             | harga    |
+------------------+----------+
| Pulpen Gel Hitam |  5000.00 |
| Spidol Permanen  | 10000.00 |
| Stipo 12 Gram    |  6000.00 |
| Selotip Bening   |  8000.00 |
+------------------+----------+
4 rows in set (0.00 sec)

Empat produk lolos: Pulpen Gel Hitam, Spidol Permanen, Stipo 12 Gram, dan Selotip Bening. Cara bacanya persis seperti kalimat: nilai kolom harus berada di antara kedua batas. Kondisi ini setara dengan harga >= 5000 AND harga <= 10000 — dan ekuivalensi itu akan kita buktikan, bukan sekadar dipercaya.

Nilai Batas Bersifat Inklusif #

Perhatikan kembali hasil di atas: Pulpen Gel Hitam berharga tepat 5000 dan Spidol Permanen berharga tepat 10000 — keduanya ikut di dalam hasil. Inilah sifat paling penting BETWEEN: kedua nilai batas dianggap bagian dari rentang. Kita pastikan dengan query terpisah yang hanya mencari nilai di batas:

sql
SELECT nama, harga
FROM produk
WHERE harga = 5000 OR harga = 10000
ORDER BY id;

Output yang Dihasilkan:

text
+------------------+----------+
| nama             | harga    |
+------------------+----------+
| Pulpen Gel Hitam |  5000.00 |
| Spidol Permanen  | 10000.00 |
+------------------+----------+
2 rows in set (0.00 sec)

Kedua produk batas ditemukan — produk yang sama dengan yang muncul di hasil BETWEEN kita. Konsekuensi praktisnya: bila kebutuhan bisnis menyatakan rentang “di atas 5000 hingga 10000”, tulis harga > 5000 AND harga <= 10000 karena BETWEEN akan mengikutkan 5000.

Ekuivalensi dengan kombinasi pembanding sekarang kita uji berdampingan:

sql
SELECT nama, harga FROM produk WHERE harga BETWEEN 5000 AND 10000 ORDER BY id;

SELECT nama, harga FROM produk WHERE harga >= 5000 AND harga <= 10000 ORDER BY id;

Output yang Dihasilkan:

text
+------------------+----------+
| nama             | harga    |
+------------------+----------+
| Pulpen Gel Hitam |  5000.00 |
| Spidol Permanen  | 10000.00 |
| Stipo 12 Gram    |  6000.00 |
| Selotip Bening   |  8000.00 |
+------------------+----------+
4 rows in set (0.00 sec)

+------------------+----------+
| nama             | harga    |
+------------------+----------+
| Pulpen Gel Hitam |  5000.00 |
| Spidol Permanen  | 10000.00 |
| Stipo 12 Gram    |  6000.00 |
| Selotip Bening   |  8000.00 |
+------------------+----------+
4 rows in set (0.00 sec)

Kedua query menghasilkan tabel yang persis sama: empat baris, kolom yang sama, urutan yang sama. BETWEEN adalah gula sintaksis — cara menulis yang lebih manis untuk kondisi yang sama. Pilih BETWEEN saat kedua batas benar-benar inklusif karena maksudnya terbaca langsung; pilih kombinasi >=/> dan <=/< ketika salah satu batas harus eksklusif.

NOT BETWEEN untuk Di Luar Rentang #

Menambahkan NOT membalik makna: baris lolos bila nilainya berada di luar kedua batas:

sql
SELECT nama, harga
FROM produk
WHERE harga NOT BETWEEN 5000 AND 10000
ORDER BY id;

Output yang Dihasilkan:

text
+--------------------+----------+
| nama               | harga    |
+--------------------+----------+
| Buku Tulis Sidu 38 |  4500.00 |
| Pensil 2B          |  3000.00 |
| Penghapus Putih    |  2500.00 |
| Kertas HVS A4      | 27500.00 |
| Kertas Origami     | 12000.00 |
| Amplop Coklat      |   800.00 |
+--------------------+----------+
6 rows in set (0.00 sec)

Enam produk lolos — kebalikan persis dari empat produk di dalam rentang. Pola NOT BETWEEN cocok untuk kasus seperti menampilkan baris anomali: nilai di luar rentang wajar hasil validasi.

BETWEEN pada Tanggal #

Rentang tanggal adalah penggunaan BETWEEN yang paling sering muncul di laporan bulanan. Query berikut mengambil seluruh pesanan sepanjang Februari 2026:

sql
SELECT id, nama_pelanggan, tanggal
FROM pesanan
WHERE tanggal BETWEEN '2026-02-01' AND '2026-02-28'
ORDER BY id;

Output yang Dihasilkan:

text
+----+----------------+------------+
| id | nama_pelanggan | tanggal    |
+----+----------------+------------+
|  3 | Dewi Lestari   | 2026-02-01 |
|  4 | Budi Santoso   | 2026-02-14 |
|  5 | Maya Putri     | 2026-02-28 |
+----+----------------+------------+
3 rows in set (0.00 sec)

Tiga pesanan Februari lolos — dan perhatikan dua detail batasnya: pesanan pada '2026-02-01' (tanggal awal) serta pesanan pada '2026-02-28' (tanggal akhir) keduanya ikut, membuktikan inklusifitas bekerja sama persis pada tipe DATE. Karena perbandingan tanggal bersifat kronologis, tidak ada konversi aneh: batas bawah berarti “tanggal itu atau sesudahnya”, batas atas berarti “tanggal itu atau sebelumnya”.

sql
SELECT id, nama_pelanggan, tanggal
FROM pesanan
WHERE tanggal NOT BETWEEN '2026-02-01' AND '2026-02-28'
ORDER BY id;

Output yang Dihasilkan:

text
+----+-----------------+------------+
| id | nama_pelanggan  | tanggal    |
+----+-----------------+------------+
|  1 | Budi Santoso    | 2026-01-05 |
|  2 | Siti Rahayu     | 2026-01-18 |
|  6 | Eko Prasetyo    | 2026-03-05 |
|  7 | Fitri Handayani | 2026-03-12 |
|  8 | Budi Santoso    | 2026-03-25 |
|  9 | Budi Santoso    | 2026-03-25 |
+----+-----------------+------------+
6 rows in set (0.00 sec)

NOT BETWEEN mengembalikan enam pesanan sisanya: dua pesanan Januari dan empat pesanan Maret.

Jebakan: Rentang Terbalik #

Apa yang terjadi bila batas atas tak sengaja ditulis lebih dulu? Kita uji langsung:

sql
SELECT nama, harga
FROM produk
WHERE harga BETWEEN 10000 AND 5000
ORDER BY id;

Output yang Dihasilkan:

text
Empty set (0.00 sec)

Tidak ada error dan tidak ada baris — hasil kosong. Syarat BETWEEN 10000 AND 5000 dibaca harga >= 10000 AND harga <= 5000, dan tidak ada angka yang bisa sekaligus lebih besar dari 10000 sekaligus lebih kecil dari 5000. Lebih berbahayanya lagi: NOT BETWEEN dengan rentang terbalik justru meloloskan semua baris, sehingga bug ini bisa tampak seperti query sehat. MySQL tidak memperingatkan rentang terbalik karena kondisi tersebut sah secara sintaks.

Membersihkan Database Latihan #

Latihan rentang selesai. Kita jatuhkan database latihan bersama tabel produk dan pesanan:

sql
DROP DATABASE belajar_filter;

Output yang Dihasilkan:

text
Query OK, 2 rows affected (0.00 sec)

Referensi #

Rentang nilai diskrit seperti harga dan tanggal kini tertangani. Penyaringan berikutnya bergerak ke pola teks: “nama produk yang mengandung kata Kertas”, “kota yang berawalan huruf S”. Operator LIKE dengan dua karakter wildcardnya menangani pencocokan pola semacam itu — topik chapter selanjutnya.