Chapter sebelumnya memperkenalkan AND, OR, dan NOT satu per satu. Kondisi bisnis nyata jarang sesederhana itu: “produk Kertas atau Perekat yang harganya paling banyak dua belas ribu” sudah menggabungkan tiga pembandingan. Yang sering luput dari perhatian adalah urutan pengerjaan operator — AND lebih tinggi prioritasnya daripada OR, sehingga query tanpa tanda kurung bisa dimaknai sama sekali berbeda dari niat kita. Pada chapter ini kita akan membuktikan perbedaan itu dengan dua query nyata yang hasilnya berbeda, lalu melatih kombinasi dan NOT pada kondisi majemuk, dan menutup dengan jebakan klasik NOT IN yang berisi NULL.
Menyiapkan Tabel Latihan #
Kita pakai kembali tabel produk dan pelanggan dengan data yang sama seperti chapter-chapter sebelumnya:
DROP DATABASE IF EXISTS belajar_filter;
CREATE DATABASE belajar_filter;
USE belajar_filter;Output yang Dihasilkan:
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 1 row affected (0.00 sec)
Database changedCREATE 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:
Query OK, 0 rows affected (0.00 sec)
Query OK, 10 rows affected (0.00 sec)
Records: 10 Duplicates: 0 Warnings: 0CREATE TABLE pelanggan (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(100) NOT NULL,
kota VARCHAR(50) NOT NULL,
telepon VARCHAR(20) NULL
);
INSERT INTO pelanggan (nama, kota, telepon) VALUES
('Budi Santoso', 'Bandung', '0812-5000-1001'),
('Siti Rahayu', 'Jakarta', '0813-5000-1002'),
('Andi Wijaya', 'Surabaya', NULL),
('Dewi Lestari', 'Bandung', '0815-5000-1004'),
('Rian Hidayat', 'Yogyakarta', NULL),
('Maya Putri', 'Medan', '0817-5000-1006'),
('Eko Prasetyo', 'Semarang', NULL),
('Fitri Handayani', 'Bandung', '0819-5000-1008');Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 8 rows affected (0.00 sec)
Records: 8 Duplicates: 0 Warnings: 0Menggabungkan Lebih dari Dua Kondisi #
Kombinasi paling sehat dimulai dari tanda kurung: kelompokkan kondisi yang semakna, lalu hubungkan antarkelompok. Query berikut mencari produk Kertas atau Perekat — kemasan ringkas, harga terjangkau — dengan pola (kondisi OR kondisi) AND kondisi:
SELECT nama, kategori, harga
FROM produk
WHERE (kategori = 'Kertas' OR kategori = 'Perekat') AND harga <= 12000
ORDER BY id;Output yang Dihasilkan:
+----------------+----------+----------+
| nama | kategori | harga |
+----------------+----------+----------+
| Kertas Origami | Kertas | 12000.00 |
| Amplop Coklat | Kertas | 800.00 |
| Stipo 12 Gram | Perekat | 6000.00 |
| Selotip Bening | Perekat | 8000.00 |
+----------------+----------+----------+
4 rows in set (0.00 sec)Empat produk lolos: dua produk Kertas yang murah dan dua produk Perekat. Tanda kurung memastikan OR di nilai lebih dulu sebagai satu kelompok “kategori yang diizinkan”, baru hasilnya di-AND-kan dengan batas harga. Mari kita bedah:
(kategori = 'Kertas' OR kategori = 'Perekat')— kelompok pertama: lima produk berkategori Kertas atau Perekat lolos tahap ini.AND harga <= 12000— kelompok kedua memangkas lagi:Kertas HVS A4(27500) gugur, empat sisanya bertahan.
Prioritas Operator: AND Lebih Tinggi dari OR #
Sekarang eksperimen kunci chapter ini. Bayangkan kita ingin mencari “produk Kertas, ditambah produk Alat Tulis yang mahal” dan menulisnya tanpa tanda kurung:
SELECT nama, kategori, harga
FROM produk
WHERE kategori = 'Kertas' OR kategori = 'Alat Tulis' AND harga > 9000
ORDER BY id;Output yang Dihasilkan:
+-----------------+------------+----------+
| nama | kategori | harga |
+-----------------+------------+----------+
| Spidol Permanen | Alat Tulis | 10000.00 |
| Kertas HVS A4 | Kertas | 27500.00 |
| Kertas Origami | Kertas | 12000.00 |
| Amplop Coklat | Kertas | 800.00 |
+-----------------+------------+----------+
4 rows in set (0.00 sec)Empat baris tampil — termasuk Amplop Coklat yang harganya cuma 800. Mengapa produk murah itu lolos padahal niat kita menambah batas harga? Jawabannya ada pada prioritas operator: MySQL mengerjakan AND lebih dulu daripada OR, sehingga query di atas sebenarnya dimaknai:
SELECT nama, kategori, harga
FROM produk
WHERE kategori = 'Kertas' OR (kategori = 'Alat Tulis' AND harga > 9000)
ORDER BY id;Output yang Dihasilkan:
+-----------------+------------+----------+
| nama | kategori | harga |
+-----------------+------------+----------+
| Spidol Permanen | Alat Tulis | 10000.00 |
| Kertas HVS A4 | Kertas | 27500.00 |
| Kertas Origami | Kertas | 12000.00 |
| Amplop Coklat | Kertas | 800.00 |
+-----------------+------------+----------+
4 rows in set (0.00 sec)Bacaannya berubah total: “semua produk Kertas (tanpa syarat harga) ATAU produk Alat Tulis yang harganya di atas 9000”. Tiga produk Kertas masuk apa adanya, dan hanya Spidol Permanen yang lolos dari kelompok kedua. Bila niat kita semula adalah “produk Kertas atau Alat Tulis, yang harganya di atas 9000”, tanda kurung harus dipindah ke kelompok kategori:
SELECT nama, kategori, harga
FROM produk
WHERE (kategori = 'Kertas' OR kategori = 'Alat Tulis') AND harga > 9000
ORDER BY id;Output yang Dihasilkan:
+-----------------+------------+----------+
| nama | kategori | harga |
+-----------------+------------+----------+
| Spidol Permanen | Alat Tulis | 10000.00 |
| Kertas HVS A4 | Kertas | 27500.00 |
| Kertas Origami | Kertas | 12000.00 |
+-----------------+------------+----------+
3 rows in set (0.00 sec)Hasilnya menyusut menjadi tiga baris — Amplop Coklat yang murah tersingkir karena kini batas harga berlaku untuk semua kategori. Dua query terakhir hanya berbeda penempatan tanda kurung, tetapi hasilnya berbeda satu baris — bukti nyata bahwa prioritas operator bukan teori kosong.
NOT pada Kondisi Majemuk #
NOT menjadi senjata yang bersih ketika membalik kondisi berkelompok. Query berikut mengambil pelanggan di luar Bandung dan Semarang:
SELECT nama, kota
FROM pelanggan
WHERE NOT (kota = 'Bandung' OR kota = 'Semarang')
ORDER BY id;Output yang Dihasilkan:
+--------------+------------+
| nama | kota |
+--------------+------------+
| Siti Rahayu | Jakarta |
| Andi Wijaya | Surabaya |
| Rian Hidayat | Yogyakarta |
| Maya Putri | Medan |
+--------------+------------+
4 rows in set (0.00 sec)Empat pelanggan lolos. Tanda kurung wajib dalam pola ini: tanpa tanda kurung, NOT hanya membalik kondisi pertama kota = 'Bandung', sehingga query dimaknai “(bukan Bandung) ATAU Semarang” — pelanggan Semarang lolos ganda dan pelanggan Bandung yang… tetap tersaring lewat pintu belakang OR. Aturan praktisnya: NOT membalik satu kondisi yang paling dekat, kecuali tanda kurung memperluas cakupannya.
NOT Bersama IN dan Jebakan NULL #
Cara lain menyatakan “di luar Bandung dan Semarang” adalah NOT IN — operator yang akan kita bahas tuntas di chapter berikutnya. Namun ada satu perilaku yang perlu kita catat sejak sekarang. Perhatikan daftar nilai berikut yang diam-diam memuat NULL:
SELECT nama, kota
FROM pelanggan
WHERE kota NOT IN ('Bandung', NULL)
ORDER BY id;Output yang Dihasilkan:
Empty set (0.00 sec)Hasilnya kosong total — padahal jelas ada pelanggan dari Jakarta, Surabaya, Yogyakarta, dan Medan yang seharusnya lolos. Penyebabnya mengikuti logika NULL dari chapter Operator Logika: MySQL mengevaluasi kota <> 'Bandung' AND kota <> NULL, dan perbandingan apa pun terhadap NULL menghasilkan NULL, bukan benar. Karena hanya baris dengan kondisi bernilai benar yang lolos, seluruh baris gugur. Solusinya sederhana: pastikan daftar IN tidak pernah memuat NULL, atau saring nilai NULL lebih dulu dengan IS NOT NULL.
Membersihkan Database Latihan #
Latihan kombinasi selesai. Kita jatuhkan kembali database latihan:
DROP DATABASE belajar_filter;Output yang Dihasilkan:
Query OK, 2 rows affected (0.00 sec)Referensi #
- Logical Operators — MySQL 8.4 Reference Manual
- Comparison Functions and Operators — MySQL 8.4 Reference Manual
- SELECT Statement — MySQL 8.4 Reference Manual
Kita kini percaya diri merangkai kondisi dan mengendalikan prioritasnya. Kondisi seperti “kategori di antara Kertas, Perekat, atau Alat Tulis” masih bisa ditulis dengan OR berantai, tetapi akan memanjang dan rentan salah ketik. Chapter berikutnya memperkenalkan operator IN yang meringkas daftar nilai menjadi satu baris yang ringkas dibaca.