شرطها دقیقتر از آناند که به نظر میرسند
عملگرهای مقایسه (= <> < > <= >=)، منطقی (AND OR NOT) و مجموعهای (IN، BETWEEN) را همه میشناسند. دامها در جزئیات است.
SELECT sku FROM carpets
WHERE city IN ('کاشان', 'قم')
AND price BETWEEN 50000000 AND 500000000 -- شامل هر دو سر
AND (reeds >= 50 OR reeds IS NULL);
اولویت AND از OR بیشتر است؛ a OR b AND c یعنی a OR (b AND c). هر وقت هر دو را دارید پرانتز بگذارید.
BETWEEN و تاریخ
created_at BETWEEN '2025-03-01' AND '2025-03-31' سفارشهای ساعت 10 صبح روز 31 را جا میاندازد، چون '2025-03-31' یعنی نیمهشب ابتدای آن روز. الگوی درست بازهی نیمهباز است:
WHERE created_at >= '2025-03-01' AND created_at < '2025-04-01'
NULL یعنی «نامعلوم»، نه صفر و نه خالی
هر مقایسه با NULL نتیجهی UNKNOWN میدهد و WHERE فقط ردیفهایی را برمیگرداند که شرطشان TRUE باشد. این منطق سهارزشی است:
| عبارت | نتیجه |
|---|---|
NULL = NULL | NULL (نه TRUE) |
NULL <> 5 | NULL |
TRUE AND NULL | NULL |
FALSE AND NULL | FALSE |
TRUE OR NULL | TRUE |
NULL IS NULL | TRUE |
NULL <=> NULL | TRUE (مقایسهی NULL-امن) |
-- فرش نائین (reeds = NULL) در هیچکدام از این دو نیست!
SELECT COUNT(*) FROM carpets WHERE reeds >= 60;
SELECT COUNT(*) FROM carpets WHERE NOT (reeds >= 60);
SELECT sku, COALESCE(reeds, 0) AS reeds_or_zero FROM carpets;
SELECT COUNT(*), COUNT(reeds) FROM carpets; -- COUNT(ستون) NULLها را نمیشمارد
LIKE و ایندکس
% یعنی هر تعداد کاراکتر و _ یعنی دقیقاً یک کاراکتر. حساس بودن به بزرگی حروف به collation ستون بستگی دارد، نه به LIKE.
SELECT sku FROM carpets WHERE sku LIKE 'KSH-%'; -- میتواند از ایندکس sku استفاده کند
SELECT sku FROM carpets WHERE title LIKE '%ابریشم%'; -- اسکن کامل جدول
SELECT sku FROM carpets WHERE sku LIKE 'KSH\_%'; -- خود کاراکتر _ را جستوجو کن
SELECT title FROM carpets WHERE title REGEXP '^فرش (دستباف|ماشینی)';
LIKE با پیشوند ثابت ('KSH-%') مثل یک بازه عمل میکند و ایندکس را به کار میگیرد؛ % در ابتدا یعنی بررسی تکتک ردیفها. برای جستوجوی واقعی متن فارسی در فصل پنجم سراغ FULLTEXT میرویم. REGEXP در MySQL 8 بر پایهی کتابخانهی ICU است و یونیکد را درست میفهمد.
نکتههایی که کمتر کسی میداند
WHERE id NOT IN (SELECT customer_id FROM orders)اگر حتی یک customer_id برابر NULL باشد، هیچ ردیفی برنمیگرداند؛ بهجایش NOT EXISTS بنویسید (فصل چهارم).- ستون UNIQUE میتواند چند NULL داشته باشد، چون NULLها با هم «برابر» نیستند؛ اگر یکتایی واقعی میخواهید ستون را NOT NULL کنید.
- در مرتبسازی صعودی NULLها اول میآیند. برای آخر بردنشان:
ORDER BY reeds IS NULL, reeds. '12abc' = 12در MySQL TRUE است (با یک warning)، چون رشته به عدد تبدیل میشود؛ مقایسهی ستون متنی با عدد هم نتیجهی غلط میدهد و هم ایندکس را از کار میاندازد.SHOW WARNINGS;را بلافاصله بعد از هر دستوری که «n warnings» گزارش کرد اجرا کنید؛ MySQL بسیاری از خطاهای داده را بیصدا به warning تبدیل میکند.