TL;DR
Operator logika SQL ada tiga: AND (dua syarat harus benar), OR (salah satu benar cukup), dan NOT (membalik hasil). Urutan evaluasinya NOT dulu, lalu AND, terakhir OR. Karena AND dieksekusi sebelum OR, query tanpa tanda kurung bisa ngasih hasil yang salah tanpa munculin pesan error sama sekali.
Operator logika SQL ada tiga: AND, OR, dan NOT. Ketiganya nentuin baris mana yang lolos filter WHERE.
Yang bikin repot bukan cara kerjanya. Itu gampang. Yang bikin repot urutan evaluasinya. SQL ngerjain NOT duluan, terus AND, baru OR. Lupa satu tanda kurung, dan query kamu ngasih hasil salah tanpa satu pun pesan error.
Aku pernah ngirim laporan penjualan Jakarta ke klien, dan ternyata di dalamnya nyelip transaksi Bandung. Penyebabnya cuma itu: kurung yang lupa dipasang.
Operator logika SQL adalah kata kunci yang nggabungin atau ngebalik kondisi di klausa WHERE, HAVING, dan CASE. Hasilnya selalu TRUE, FALSE, atau UNKNOWN. Cuma baris yang menghasilkan TRUE yang bakal muncul di output.
Tiga operatornya:
| Operator | Artinya | Baris lolos kalau |
|---|---|---|
| AND | Dan | Semua kondisi TRUE |
| OR | Atau | Minimal satu kondisi TRUE |
| NOT | Bukan | Kondisi di belakangnya FALSE |
Semua contoh di artikel ini pakai tabel transaksi dari dataset Toko Berkah, toko kelontong online yang jadi bahan latihan di NgulikSQL. Kamu bisa bikin sendiri dengan query di bawah.
CREATE TABLE transaksi (
id INT PRIMARY KEY,
nama_produk VARCHAR(60),
kategori VARCHAR(30),
kota VARCHAR(30),
jumlah INT,
total_harga INT,
status VARCHAR(20)
);
INSERT INTO transaksi VALUES
(1, 'Beras Pandan Wangi 5kg', 'Sembako', 'Jakarta', 2, 130000, 'lunas'),
(2, 'Minyak Goreng 2L', 'Sembako', 'Bandung', 3, 54000, 'lunas'),
(3, 'Kopi Sachet Box', 'Minuman', 'Jakarta', 1, 25000, 'pending'),
(4, 'Gula Pasir 1kg', 'Sembako', 'Surabaya', 5, 75000, 'lunas'),
(5, 'Teh Celup Box', 'Minuman', 'Bandung', 2, 18000, 'batal'),
(6, 'Sabun Cuci Piring', 'Kebersihan','Jakarta', 4, 40000, 'lunas'),
(7, 'Beras Setra Ramos 10kg', 'Sembako', 'Jakarta', 1, 120000, 'pending'),
(8, 'Susu UHT 1L', 'Minuman', 'Surabaya', 6, 96000, 'lunas'),
(9, 'Deterjen 800g', 'Kebersihan','Bandung', 2, 36000, 'lunas'),
(10, 'Kecap Manis 600ml', 'Sembako', 'Jakarta', 3, 45000, 'batal');
AND cuma ngeloloskan baris kalau semua kondisi di sekitarnya bernilai TRUE. Satu kondisi gagal, baris itu langsung dibuang.
SELECT nama_produk, kota, total_harga
FROM transaksi
WHERE kota = 'Jakarta' AND total_harga > 50000;
Hasilnya cuma 2 baris: Beras Pandan Wangi (Rp130.000) dan Beras Setra Ramos (Rp120.000). Sabun Cuci Piring di Jakarta kena buang soalnya harganya cuma Rp40.000.
Makin banyak AND yang kamu tambah, makin sedikit baris yang keluar. AND itu penyaring.
OR ngeloloskan baris kalau minimal satu kondisi TRUE. Kebalikannya AND, makin banyak OR, makin banyak baris yang keluar.
SELECT nama_produk, kategori
FROM transaksi
WHERE kategori = 'Sembako' OR kategori = 'Minuman';
Hasilnya 8 baris. Cuma 2 transaksi kategori Kebersihan yang nggak ikut.
Kalau kamu nulis 3 OR atau lebih di satu kolom yang sama, ganti pakai operator IN. Lebih pendek, hasilnya sama.
-- Tiga OR beruntun
WHERE kota = 'Jakarta' OR kota = 'Bandung' OR kota = 'Surabaya'
-- Versi ringkas
WHERE kota IN ('Jakarta', 'Bandung', 'Surabaya')
NOT ngebalik hasil dari kondisi di belakangnya. TRUE jadi FALSE, FALSE jadi TRUE.
SELECT nama_produk, status
FROM transaksi
WHERE NOT status = 'batal';
Hasilnya 8 baris, semua transaksi kecuali Teh Celup dan Kecap Manis yang statusnya batal.
Buat perbandingan sederhana kayak gini, status <> 'batal' lebih pendek dan artinya sama. NOT baru kerasa gunanya waktu digabung sama operator lain:
WHERE kota NOT IN ('Jakarta', 'Bandung')
WHERE nama_produk NOT LIKE '%Beras%'
WHERE NOT EXISTS (SELECT 1 FROM retur WHERE retur.transaksi_id = transaksi.id)
Ini bagian yang paling sering bikin bug diam-diam. SQL punya urutan tetap:
Artinya, AND selalu "nempel" lebih kuat ke tetangganya dibanding OR. Lihat query ini:
SELECT nama_produk, kota, kategori
FROM transaksi
WHERE kota = 'Jakarta' OR kota = 'Bandung' AND kategori = 'Sembako';
Niat kamu mungkin: ambil transaksi Sembako dari Jakarta atau Bandung. Yang dikerjain database beda.
Database baca query itu kayak gini:
WHERE kota = 'Jakarta' OR (kota = 'Bandung' AND kategori = 'Sembako')
Hasilnya: semua 5 transaksi Jakarta ikut, termasuk Kopi Sachet (Minuman) dan Sabun Cuci Piring (Kebersihan). Total 6 baris, padahal yang kamu mau cuma 4.
Nggak ada error. Nggak ada peringatan. Query jalan mulus dan angkanya salah.
Pakai tanda kurung. Selalu.
SELECT nama_produk, kota, kategori
FROM transaksi
WHERE (kota = 'Jakarta' OR kota = 'Bandung') AND kategori = 'Sembako';
Sekarang hasilnya 4 baris, semuanya Sembako dari Jakarta atau Bandung. Persis yang kamu mau.
Aturan praktis: setiap kali kamu campur AND dan OR dalam satu WHERE, pasang kurung. Nggak ada pengecualian.
Kurung nggak bikin query lebih lambat. Database tetap nyusun rencana eksekusi yang sama. Yang kamu dapat cuma satu: query yang jelas maksudnya, buat kamu dan buat orang yang baca 6 bulan kemudian.
Pemilik Toko Berkah minta daftar transaksi yang perlu ditagih. Kriterianya:
Tiga kriteria, tiga operator berbeda. Ini querynya:
SELECT nama_produk, kota, total_harga, status
FROM transaksi
WHERE (kota = 'Jakarta' OR kota = 'Surabaya')
AND total_harga >= 40000
AND NOT status = 'batal';
Hasilnya 5 baris dengan total nilai Rp461.000. Coba hapus kurungnya, dan hasilnya berubah jadi 6 baris dengan total Rp486.000, selisih Rp25.000 dari transaksi Kopi Sachet yang seharusnya nggak masuk.
Selisih Rp25.000 di dataset 10 baris kelihatan sepele. Di tabel 500.000 baris, selisih kayak gini yang bikin laporan kamu ditolak finance.
Versi yang lebih enak dibaca, pakai IN dan operator perbandingan:
SELECT nama_produk, kota, total_harga, status
FROM transaksi
WHERE kota IN ('Jakarta', 'Surabaya')
AND total_harga >= 40000
AND status <> 'batal';
Udah dibahas di atas, tapi diulang soalnya ini penyebab bug nomor satu. Campur? Kurung.
WHERE NOT kota = NULL selalu ngasih hasil kosong. Perbandingan apa pun sama NULL hasilnya UNKNOWN, dan UNKNOWN yang dibalik NOT tetap UNKNOWN, bukan TRUE.
Pakai IS NULL dan IS NOT NULL. Detail lengkapnya ada di artikel NULL di SQL.
Kalau daftar di dalam NOT IN mengandung NULL, hasilnya selalu kosong. Contoh: WHERE kota NOT IN (SELECT kota FROM cabang) bakal balik kosong kalau ada satu baris di tabel cabang yang kotanya NULL. Filter dulu NULL-nya, atau ganti pakai NOT EXISTS.
Lima OR di kolom yang sama itu susah dibaca dan gampang salah ketik. Pakai IN.
Sebagian orang nulis kondisi paling selektif di depan, mikir database bakal ngecek dari kiri ke kanan. Query planner nggak kerja gitu, dia nyusun ulang urutannya sendiri berdasarkan statistik tabel. Tulis kondisi dengan urutan yang paling gampang dibaca manusia.
Aturan prioritas ini standar di semua database besar. Kamu bisa cek daftar lengkapnya di dokumentasi operator precedence PostgreSQL.
Urutannya NOT dulu, lalu AND, terakhir OR. Jadi di query WHERE a OR b AND c, database bakal ngerjain b AND c dulu, baru hasilnya di-OR sama a. Urutan ini standar di semua database besar: PostgreSQL, MySQL, SQL Server, dan Oracle. Kalau kamu mau urutan lain, bungkus pakai tanda kurung.
Karena AND dievaluasi duluan, kondisi OR kamu jadi berdiri sendiri. Query WHERE kota = 'Jakarta' OR kota = 'Bandung' AND kategori = 'Sembako' bakal narik semua transaksi Jakarta apa pun kategorinya, plus transaksi Bandung yang Sembako. Solusinya bungkus bagian OR pakai kurung.
NOT membalik hasil dari satu ekspresi logika apa pun, sementara <> cuma buat bandingin dua nilai supaya nggak sama. Buat perbandingan sederhana, status <> 'batal' sama artinya dengan NOT status = 'batal', tapi lebih pendek. NOT lebih berguna waktu digabung sama IN, LIKE, atau EXISTS.
Nggak bisa dengan cara biasa. NOT kolom = NULL selalu ngasih hasil kosong, karena perbandingan apa pun dengan NULL hasilnya UNKNOWN, bukan TRUE atau FALSE. Buat nyari baris yang isinya NULL, pakai IS NULL. Buat yang bukan NULL, pakai IS NOT NULL.
Buat perbandingan nilai di satu kolom yang sama, IN dan rangkaian OR biasanya dieksekusi dengan rencana yang sama, jadi kecepatannya mirip. Bedanya di keterbacaan. Pakai IN kalau nilainya di satu kolom, pakai OR kalau kondisinya beda-beda kolom.
Yang perlu nempel di kepala:
Coba sendiri: jalanin query jebakan di atas tanpa kurung, hitung barisnya, terus tambahin kurung dan hitung lagi. Sekali ngerasain selisihnya, kamu nggak bakal lupa.
Mau latihan langsung di browser tanpa install database? Buka halaman fungsi WHERE di NgulikData, ada editor SQL yang udah berisi dataset Toko Berkah.
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.