WHERE — فیلتر کردن ردیفها بر اساس شرط
تا اینجا هر پرسوجویی که نوشتیم، همهی ردیفهای جدول را برمیگرداند. اما در دنیای واقعی، تقریباً هیچوقت به همهی دادهها نیاز نداریم — میخواهیم فقط دانشآموزان یک شهر خاص را ببینیم، یا فقط سفارشهای یک روز مشخص را. این دقیقاً کاری است که WHERE انجام میدهد: از میان همهی ردیفها، فقط آنهایی را نگه میدارد که یک شرط مشخص را برآورده کنند.
ساختار پایه
SELECT full_name, city FROM students WHERE city = N'تهران';
این پرسوجو فقط دانشآموزانی را برمیگرداند که مقدار ستون cityشان دقیقاً برابر 'تهران' باشد. توجه کن که در SQL Server، برای مقادیر متنی، پیشوند N قبل از رشته گذاشته میشود تا مطمئن شویم متن فارسی بهدرستی مقایسه میشود — دقیقاً همان نکتهای که در درس انواع داده دیدیم.
عملگرهای مقایسهای
| عملگر | معنا |
|---|---|
| = | برابر است با |
| <> یا != | برابر نیست با |
| > | بزرگتر از |
| < | کوچکتر از |
| >= | بزرگتر یا مساوی |
| <= | کوچکتر یا مساوی |
SELECT full_name, grade FROM students WHERE grade >= 10;
ترکیب چند شرط با AND و OR
میتوان چند شرط را با هم ترکیب کرد:
- AND: ردیف فقط زمانی نگه داشته میشود که همهی شرطها درست باشند.
- OR: ردیف نگه داشته میشود اگر حداقل یکی از شرطها درست باشد.
-- دانشآموزان تهرانی با پایهی ۱۰ یا بالاتر SELECT full_name, city, grade FROM students WHERE city = N'تهران' AND grade >= 10; -- دانشآموزان تهرانی یا شیرازی، فارغ از پایه SELECT full_name, city FROM students WHERE city = N'تهران' OR city = N'شیراز';
بیا این دو ایده را روی دادهی واقعی امتحان کنیم:
مراقب اولویت AND و OR باش
یکی از رایجترین اشتباهات مبتدیان همینجاست: AND همیشه قبل از OR محاسبه میشود — دقیقاً مثل ضرب که در ریاضی قبل از جمع محاسبه میشود. این پرسوجو را ببین:
SELECT full_name, city, grade FROM students WHERE city = N'تهران' OR city = N'شیراز' AND grade = 11;
در نگاه اول ممکن است فکر کنی این پرسوجو یعنی «شهر تهران یا شیراز، با پایهی ۱۱». اما SQL Server اول AND را محاسبه میکند، پس این پرسوجو در واقع اینطور خوانده میشود:
WHERE city = N'تهران' OR (city = N'شیراز' AND grade = 11)
یعنی: «هر دانشآموز تهرانی (با هر پایهای)، یا هر دانشآموز شیرازی که پایهاش ۱۱ باشد» — چیزی کاملاً متفاوت از آنچه شاید در ذهن داشتی. راهحل ساده است: هروقت AND و OR را با هم ترکیب میکنی، منظور واقعیات را با پرانتز صریح بنویس:
SELECT full_name, city, grade FROM students WHERE (city = N'تهران' OR city = N'شیراز') AND grade = 11;
AND و OR) در یک شرط دارید، حتماً با پرانتز مشخص کنید کدام قسمت اول محاسبه شود — حتی اگر مطمئنید اولویت پیشفرض همان چیزی است که میخواهید. این کار، کد را هم برای خودتان بعداً و هم برای همتیمیها خیلی خواناتر میکند.منفی کردن یک شرط با NOT
SELECT full_name, city FROM students WHERE NOT city = N'تهران'; -- دقیقاً معادل: WHERE city <> N'تهران'
فیلتر کردن یک بازه با BETWEEN
برای اینکه مقداری بین دو عدد (یا دو تاریخ) باشد، بهجای نوشتن دو شرط با AND، میتوان از BETWEEN استفاده کرد:
SELECT full_name, grade FROM students WHERE grade BETWEEN 10 AND 11; -- دقیقاً معادل: WHERE grade >= 10 AND grade <= 11
BETWEEN هر دو سر بازه را هم شامل میشود (inclusive)؛ یعنی خود ۱۰ و خود ۱۱ هم در نتیجه هستند.بررسی عضویت در یک لیست با IN
وقتی میخواهی چند مقدار مشخص را چک کنی، بهجای زنجیرهای طولانی از OR، از IN استفاده کن:
SELECT full_name, city FROM students WHERE city IN (N'تهران', N'شیراز', N'مشهد'); -- دقیقاً معادل: WHERE city = N'تهران' OR city = N'شیراز' OR city = N'مشهد'
برعکسش هم با NOT IN ممکن است: WHERE city NOT IN (N'تهران', N'شیراز') یعنی هر شهری غیر از این دو.
بیا BETWEEN و IN را هم امتحان کنیم:
جستجوی الگو در متن با LIKE
وقتی مقدار دقیق را نمیدانی و فقط یک الگو در ذهن داری (مثلاً «نامی که با علی شروع میشود»)، از LIKE همراه با دو نویسهی خاص استفاده میشود:
| نویسه | معنا |
|---|---|
| % | هر تعداد نویسه (حتی صفر نویسه) |
| _ | دقیقاً یک نویسه |
-- نامهایی که با «علی» شروع میشوند SELECT full_name FROM students WHERE full_name LIKE N'علی%'; -- نامهایی که به «محمدی» ختم میشوند SELECT full_name FROM students WHERE full_name LIKE N'%محمدی'; -- نامهایی که در هر جایی «حسین» دارند SELECT full_name FROM students WHERE full_name LIKE N'%حسین%';
% شروع میشوند (مثل '%حسین%') نمیتوانند از ایندکس معمولی استفاده کنند و روی جدولهای بزرگ میتوانند کند باشند. در فصل ۱۰ (ایندکسگذاری) بیشتر دربارهی این موضوع صحبت میکنیم.حالا نوبت توست — یکی از این سه الگو را امتحان کن:
یک نکتهی مهم دربارهی NULL
ممکن است وسوسه شوی برای پیدا کردن ردیفهای خالی بنویسی WHERE city = NULL. این کار هیچوقت جواب درست نمیدهد؛ چون NULL بهمعنای «نامشخص» است، نه یک مقدار قابلمقایسه. برای این کار باید از IS NULL استفاده کرد — که با جزئیات کامل، موضوع درس بعدی است.
چرا WHERE معمولاً نمیتواند نام مستعار SELECT را ببیند؟
در درس قبل با AS نام مستعار ساختیم. در بسیاری از پایگاهدادههای رابطهای — از جمله SQL Server — یک قانون سختگیرانه وجود دارد: نمیتوان همان نام مستعار را داخل WHERE همان پرسوجو استفاده کرد. علتش به «ترتیب پردازش منطقی» SQL برمیگردد که در درس SELECT اشاره کردیم: WHERE پیش از SELECT پردازش میشود، پس وقتی نوبت به بررسی شرط WHERE میرسد، نام مستعاری که قرار است در SELECT ساخته شود، هنوز اصلاً وجود ندارد. در SQL Server، پرسوجوی زیر با خطا متوقف میشود:
SELECT grade + 1 AS NextYearGrade FROM Students WHERE NextYearGrade > 10; -- خطا: نام ستون «NextYearGrade» شناختهشده نیست
حالا بیا همین پرسوجو را در Playground این سایت (که روی SQLite اجرا میشود) امتحان کنیم — نتیجهاش شاید تعجبآور باشد:
SELECT در WHERE همان پرسوجو هم استفاده شود. این دقیقاً یکی از همان تفاوتهای بین موتورهاست که باید به آنها عادت کنی: کدی که اینجا کار میکند، ممکن است روی SQL Server واقعی با خطا متوقف شود. برای اینکه کدت همهجا کار کند، امنترین راه این است که عبارت را در WHERE تکرار کنی: WHERE grade + 1 > 10.جمعبندی این درس
WHEREفقط ردیفهایی را نگه میدارد که شرط دادهشده برایشان درست باشد.- عملگرهای مقایسهای (
=,<>,>, ...) و عملگرهای منطقی (AND,OR,NOT) پایهی هر شرط هستند. ANDهمیشه قبل ازORمحاسبه میشود — برای وضوح، همیشه از پرانتز استفاده کن.BETWEENبرای بازه،INبرای لیستی از مقادیر، وLIKEبرای الگوی متنی بهکار میروند.city = NULLهرگز کار نمیکند؛ بهجایش باید ازIS NULLاستفاده کرد.- در SQL Server، نام مستعار ساختهشده در
SELECTداخلWHEREهمان پرسوجو در دسترس نیست (SQLite در این مورد استثنا و مسامحهکارتر عمل میکند).
در درس بعدی، کامل با مفهوم NULL آشنا میشویم: چرا یک مقدار «نامشخص» با هیچ مقداری — حتی خودش — برابر نیست، و چطور درست با آن کار کنیم.