TL;DR
WHERE adalah klausa SQL yang menyaring baris supaya cuma data yang memenuhi syarat yang masuk ke hasil query. Kamu tulis WHERE setelah FROM, lalu isi kondisinya pakai operator seperti sama dengan, lebih besar, LIKE, IN, atau BETWEEN. Satu hal yang sering bikin salah: nilai NULL nggak bisa dicek pakai tanda sama dengan, harus pakai IS NULL.
WHERE adalah klausa SQL yang nyaring baris mana yang boleh masuk ke hasil query. Kamu kasih syarat, database buang baris yang nggak memenuhi.
Tanpa WHERE, tiap query narik seluruh isi tabel. Di tabel transaksi e-commerce dengan 4 juta baris, itu bedanya antara jawaban dalam 0,2 detik dan laptop kamu yang ngehang.
Di bawah ada semua operatornya, urutan prioritas AND dan OR yang sering bikin hasil salah diam-diam, plus perilaku NULL yang jadi jebakan paling licik di SQL.
WHERE adalah klausa yang menentukan kondisi mana yang harus dipenuhi sebuah baris supaya ikut ke hasil query. Database ngecek kondisinya baris per baris. Kalau hasilnya benar, baris itu lolos. Kalau salah, dibuang.
SELECT kolom
FROM tabel
WHERE kondisi;
Posisinya selalu setelah FROM, dan sebelum GROUP BY atau ORDER BY.
Semua contoh di bawah pakai tabel ini. Perhatiin kolom kode_promo, sengaja ada yang kosong, buat bahas NULL nanti.
CREATE TABLE transaksi (
id INT PRIMARY KEY,
tanggal DATE NOT NULL,
kota VARCHAR(50),
kategori VARCHAR(50),
produk VARCHAR(100),
kasir VARCHAR(50),
total DECIMAL(12,2),
kode_promo VARCHAR(20)
);
INSERT INTO transaksi (id, tanggal, kota, kategori, produk, kasir, total, kode_promo) VALUES
(1, '2026-01-03', 'Surabaya', 'Minuman', 'Kopi Sachet Gula Aren', 'Rina', 25000.00, NULL),
(2, '2026-01-03', 'Bandung', 'Snack', 'Keripik Singkong', 'Doni', 60000.00, 'HEMAT10'),
(3, '2026-01-04', 'Surabaya', 'Minuman', 'Teh Kotak', 'Rina', 96000.00, NULL),
(4, '2026-01-05', 'Jakarta', 'Sembako', 'Beras Premium 5kg', 'Sari', 225000.00, 'GRATISONGKIR'),
(5, '2026-01-06', 'Bandung', 'Minuman', 'Kopi Susu Botol', 'Doni', 108000.00, NULL),
(6, '2026-01-07', 'Jakarta', 'Snack', 'Biskuit Kaleng', 'Sari', 110000.00, 'HEMAT10'),
(7, '2026-01-08', 'Surabaya', 'Sembako', 'Minyak Goreng 2L', 'Rina', 228000.00, NULL),
(8, '2026-01-09', 'Bandung', 'Minuman', 'Kopi Sachet Gula Aren', 'Doni', 50000.00, 'HEMAT10');
| Operator | Artinya | Contoh |
|---|---|---|
= | sama dengan | kota = 'Surabaya' |
<> atau != | nggak sama dengan | kategori <> 'Snack' |
> < | lebih besar / kecil | total > 100000 |
>= <= | lebih besar / kecil atau sama | total >= 50000 |
BETWEEN | rentang, batasnya ikut | total BETWEEN 50000 AND 150000 |
IN | salah satu dari daftar | kota IN ('Surabaya','Bandung') |
LIKE | cocok pola teks | produk LIKE '%Kopi%' |
IS NULL | nilainya kosong | kode_promo IS NULL |
Teks dibungkus tanda kutip satu. Angka nggak pakai kutip. Salah satu kesalahan paling sering: nulis total > '100000'. Di sebagian database itu jalan tapi lambat, di sebagian lain langsung error.
Pakai AND kalau semua syarat harus kena:
SELECT produk, total FROM transaksi
WHERE kota = 'Bandung' AND kategori = 'Minuman';
Hasilnya 2 baris: Kopi Susu Botol dan Kopi Sachet Gula Aren.
Pakai OR kalau salah satu aja cukup. Tapi di sinilah jebakannya.
SQL ngerjain AND duluan, baru OR, sama kayak perkalian sebelum penjumlahan. Jadi query ini:
WHERE kota = 'Surabaya' OR kota = 'Bandung' AND total > 50000
dibaca database sebagai:
WHERE kota = 'Surabaya' OR (kota = 'Bandung' AND total > 50000)
Artinya semua transaksi Surabaya ikut, berapa pun nilainya. Kalau maksud kamu "kota Surabaya atau Bandung, dan nilainya di atas 50 ribu", kamu harus nulis kurungnya sendiri:
SELECT produk, total FROM transaksi
WHERE (kota = 'Surabaya' OR kota = 'Bandung')
AND total > 50000;
Ini bug yang nggak pernah kasih error. Query-nya jalan, angkanya keluar, dan angkanya salah. Kebiasaan yang aku pakai: begitu AND dan OR nyampur dalam satu WHERE, langsung kasih kurung, walau secara teknis nggak wajib.
-- Panjang
WHERE kota = 'Surabaya' OR kota = 'Bandung' OR kota = 'Jakarta'
-- Pendek, sama hasilnya
WHERE kota IN ('Surabaya', 'Bandung', 'Jakarta')
BETWEEN buat rentang angka atau tanggal, dan batasnya ikut:
WHERE total BETWEEN 50000 AND 150000
Itu sama persis dengan total >= 50000 AND total <= 150000. Hati-hati waktu dipakai buat tanggal dengan jam, BETWEEN '2026-01-01' AND '2026-01-31' bakal misahin transaksi tanggal 31 pukul 14:00, soalnya batas atasnya dianggap jam 00:00.
Dua wildcard-nya:
%: karakter apa aja, sebanyak apa aja (termasuk nol)_: tepat satu karakterSELECT produk FROM transaksi
WHERE produk LIKE '%Kopi%';
Nemu "Kopi Sachet Gula Aren" dan "Kopi Susu Botol": 3 baris dari 8.
Soal huruf besar-kecil: PostgreSQL peka, MySQL biasanya nggak. Kalau kamu mau aman di mana pun, samain dulu:
WHERE LOWER(produk) LIKE '%kopi%'
Detail wildcard lengkapnya ada di artikel operator LIKE.
Ini jebakan paling licik di SQL. Query ini nggak pernah ngasih hasil:
-- SALAH: selalu kosong
SELECT * FROM transaksi WHERE kode_promo = NULL;
Alasannya: NULL artinya "nggak diketahui". Dan sesuatu yang nggak diketahui nggak bisa dibilang sama dengan apa pun, bahkan sama NULL lain. Hasil perbandingannya bukan benar, bukan salah, tapi unknown. Dan WHERE cuma ngeloloskan yang hasilnya benar.
-- BENAR
SELECT id, produk FROM transaksi WHERE kode_promo IS NULL;
Hasilnya 4 baris, setengah dari transaksi toko_berkah ternyata nggak pakai kode promo sama sekali.
Efek sampingnya juga bikin kaget. WHERE kategori <> 'Snack' nggak akan ngeloloskan baris yang kategorinya NULL, walau NULL jelas bukan 'Snack'. Kamu harus nulis eksplisit:
WHERE kategori <> 'Snack' OR kategori IS NULL
Bahasan lengkap perilaku NULL ada di artikel NULL di SQL dan glosarium NULL.
| WHERE | HAVING | |
|---|---|---|
| Kapan jalan | Sebelum GROUP BY | Sesudah GROUP BY |
| Nyaring apa | Baris mentah | Hasil agregasi |
| Boleh pakai SUM/COUNT? | Nggak | Boleh |
Kalau kamu mau filter "kota yang total penjualannya di atas 1 juta", itu HAVING. Kalau kamu mau filter "transaksi di atas 100 ribu", itu WHERE. Referensi klausanya ada di halaman fungsi WHERE.
"Surabaya" artinya nama kolom, bukan teks. Pakai kutip satu.WHERE YEAR(tanggal) = 2026 bikin database nggak bisa pakai index, dan query-nya lambat. Tulis WHERE tanggal >= '2026-01-01' AND tanggal < '2027-01-01'.=. Selalu kosong hasilnya.Sintaks resminya ada di dokumentasi PostgreSQL soal WHERE.
WHERE nyaring baris mana yang boleh ikut ke hasil query. Database ngecek kondisi yang kamu tulis buat tiap baris, dan cuma baris yang kondisinya bernilai benar yang lolos. Tanpa WHERE, semua baris di tabel ikut ketarik. Klausa ini ditulis setelah FROM dan sebelum GROUP BY.
WHERE nyaring baris sebelum data dikelompokkan, HAVING nyaring setelahnya. Jadi WHERE nggak bisa dipakai buat kondisi yang melibatkan SUM atau COUNT, karena waktu WHERE jalan, hasil agregasinya belum ada. Kalau kamu mau filter kota dengan total penjualan di atas 1 juta, itu tugas HAVING.
Karena NULL artinya nilai yang nggak diketahui, dan sesuatu yang nggak diketahui nggak bisa dibandingkan sama apa pun, termasuk sama NULL lain. Hasil perbandingannya bukan benar atau salah, tapi unknown, dan baris dengan hasil unknown nggak pernah lolos WHERE. Pakai IS NULL sebagai gantinya.
AND dievaluasi lebih dulu dari OR, sama seperti perkalian sebelum penjumlahan. Jadi A OR B AND C dibaca sebagai A OR (B AND C). Kalau maksudmu (A OR B) AND C, kasih tanda kurung sendiri. Kebiasaan aman: selalu pakai kurung waktu AND dan OR nyampur.
Tergantung databasenya. PostgreSQL peka, jadi pola '%kopi%' nggak nemu "Kopi". Pakai ILIKE kalau mau abaikan kapitalisasi. MySQL dengan collation default justru nggak peka. Cara paling aman yang jalan di mana-mana: samain dulu pakai LOWER di kedua sisi.
WHERE nyaring baris sebelum apa pun yang lain terjadi. Teks pakai kutip satu, angka nggak pakai kutip.
AND jalan sebelum OR, kasih kurung sendiri kalau keduanya nyampur. Dan NULL cuma bisa dicek pakai IS NULL.
Copy tabel transaksi di atas, terus tulis 5 query WHERE sendiri. Coba juga WHERE kode_promo = NULL biar kamu lihat sendiri hasilnya kosong.
Lanjut ke ORDER BY SQL buat ngurutin hasil query yang udah kamu saring.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Analisa per kuartal, hari kerja, atau musim jadi ribet kalau tiap query ngitung ulang atribut tanggal. Tabel kalender nyimpen semua atribut itu sekali, biar tinggal di-JOIN.
Laporan penjualan harian sering bolong di hari tanpa transaksi. Ini cara bikin deret tanggal lengkap di SQL biar tiap hari muncul, walau nilainya nol.
Struktur organisasi tersimpan sebagai kolom id_atasan yang saling nunjuk. Ini cara narik rantai jabatan, hitung total bawahan, dan span of control cuma pakai SQL.