فصل ۲: SQL پایه — خواندن و نوشتن داده، درست و امن

عملگرها، NULL و منطق سه‌ارزشی، LIKE و REGEXP

شرط‌ها دقیق‌تر از آن‌اند که به نظر می‌رسند

عملگرهای مقایسه (= <> < > <= >=)، منطقی (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 = NULLNULL (نه TRUE)
NULL <> 5NULL
TRUE AND NULLNULL
FALSE AND NULLFALSE
TRUE OR NULLTRUE
NULL IS NULLTRUE
NULL <=> NULLTRUE (مقایسه‌ی 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 تبدیل می‌کند.

برای ذخیره‌ی پیشرفت و شرکت در آزمون، وارد شوید — رایگان است.