SELECT و فیلتر
داده را دقیق بخوان: انتخاب ستون و اسم مستعار با AS، فیلتر با WHERE و عملگرهای = و <> و BETWEEN و IN و LIKE و ILIKE، ترکیب با AND و OR و پرانتز، NULL و IS NULL و COALESCE، مرتبسازی با ORDER BY، صفحهبندی با LIMIT و OFFSET، DISTINCT و ستونهای محاسبهای.
- حدود ۱۷ دقیقه مطالعه
- ۹ مثال اجراشده
- ۳ تمرین با جواب
- مقدماتی تا متوسط
- بهروزرسانی: ۲۹ مهر ۱۴۰۵
توی این درس یاد میگیری از یک جدول دقیقاً همان چیزی را بیرون بکشی که لازم داری. با SELECT ستونها را انتخاب میکنی و با AS اسم خوانا میدهی، با WHERE سطرها را فیلتر میکنی (برابری، بازه با BETWEEN، فهرست با IN، الگوی متن با LIKE)، شرطها را با AND و OR ترکیب میکنی، با مقدار مرموز NULL درست کار میکنی، نتیجه را با ORDER BY مرتب و با LIMIT محدود میکنی، و ستونهای جدید حساب میکنی (ارزش موجودی، قیمت بعد از تخفیف). این درس پایهی همهی درسهای بعدی است.
مسئله: جدول هزار سطری و یک سؤال ساده
Section titled “مسئله: جدول هزار سطری و یک سؤال ساده”SELECT * FROM products برای ۱۲ محصول خوب است، ولی فروشگاه واقعی ده هزار محصول دارد و سؤالها مشخصاند: «کالاهای شبکهی تمامشده»، «۱۰ کالای گرانتر از یک میلیون که تخفیف دارند»، «محصولهایی که از اول مهر اضافه شدهاند». کشیدن کل جدول به برنامه و فیلتر کردن با پایتون هم کند است و هم بیدلیل؛ دیتابیس دقیقاً برای جواب دادن به همین سؤالها بهینه شده.
تشبیه: صافی و سینی
Section titled “تشبیه: صافی و سینی”SELECT مثل کار کردن با یک سینی میوه است: FROM میگوید کدام سینی، WHERE صافی است که فقط میوههای مورد نظر (سیبهای قرمز بزرگتر از فلان) رد میشوند، SELECT میگوید از هر میوه چه چیزی را نشان بده (اسم و وزن، نه همهچیز)، ORDER BY آنها را ردیف میکند و LIMIT میگوید «فقط سه تای اول را بیاور».
آماده کردن داده
Section titled “آماده کردن داده”یک جدول محصول کاملتر لازم داریم. این را در فایل ~/products.sql (با nano) بنویس:
DROP TABLE IF EXISTS products;CREATE TABLE products ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, category TEXT NOT NULL, price INTEGER NOT NULL CHECK (price >= 0), stock INTEGER NOT NULL DEFAULT 0, discount INTEGER, added_on DATE NOT NULL DEFAULT CURRENT_DATE);INSERT INTO products (name, category, price, stock, discount, added_on) VALUES ('کتاب پایتون', 'کتاب', 320000, 12, 10, '2026-03-10'), ('کتاب لینوکس', 'کتاب', 280000, 0, NULL, '2026-01-22'), ('کتاب داکر', 'کتاب', 350000, 5, NULL, '2026-08-01'), ('ماوس بیسیم', 'لوازم جانبی', 450000, 30, 5, '2026-02-14'), ('کیبورد مکانیکی', 'لوازم جانبی', 1890000, 8, NULL, '2026-05-03'), ('هدفون', 'لوازم جانبی', 1250000, 0, 15, '2026-06-18'), ('هارد اکسترنال', 'ذخیرهسازی', 3200000, 4, NULL, '2026-04-09'), ('فلش 64 گیگ', 'ذخیرهسازی', 290000, 50, NULL, '2026-07-30'), ('SSD 512 گیگ', 'ذخیرهسازی', 2750000, 7, 10, '2026-09-12'), ('کابل شبکه', 'شبکه', 95000, 120, NULL, '2026-01-05'), ('روتر وایفای', 'شبکه', 2400000, 3, NULL, '2026-08-25'), ('سوئیچ 8 پورت', 'شبکه', 1650000, 0, 20, '2026-10-02');و اجرایش کن:
psql shop -f ~/products.sqlDROP TABLECREATE TABLEINSERT 0 12-f یک فایل SQL را اجرا میکند (داخل psql: \i ~/products.sql). DROP TABLE IF EXISTS جدول قبلی درس اول را پاک میکند تا از نو بسازیم؛ روی دادهی واقعی با این دستور بسیار محتاط باش. ستون discount (درصد تخفیف) عمداً برای بعضی کالاها خالی (NULL) است.
مثالهای عملی
Section titled “مثالهای عملی”از اینجا همهچیز داخل psql shop.
مثال ۱: کل جدول
Section titled “مثال ۱: کل جدول”SELECT * FROM products; id | name | category | price | stock | discount | added_on----+----------------+-------------+---------+-------+----------+------------ 1 | کتاب پایتون | کتاب | 320000 | 12 | 10 | 2026-03-10 2 | کتاب لینوکس | کتاب | 280000 | 0 | | 2026-01-22 3 | کتاب داکر | کتاب | 350000 | 5 | | 2026-08-01 4 | ماوس بیسیم | لوازم جانبی | 450000 | 30 | 5 | 2026-02-14 5 | کیبورد مکانیکی | لوازم جانبی | 1890000 | 8 | | 2026-05-03 6 | هدفون | لوازم جانبی | 1250000 | 0 | 15 | 2026-06-18 7 | هارد اکسترنال | ذخیرهسازی | 3200000 | 4 | | 2026-04-09 8 | فلش 64 گیگ | ذخیرهسازی | 290000 | 50 | | 2026-07-30 9 | SSD 512 گیگ | ذخیرهسازی | 2750000 | 7 | 10 | 2026-09-12 10 | کابل شبکه | شبکه | 95000 | 120 | | 2026-01-05 11 | روتر وایفای | شبکه | 2400000 | 3 | | 2026-08-25 12 | سوئیچ 8 پورت | شبکه | 1650000 | 0 | 20 | 2026-10-02(12 rows)خانههای خالی ستون discount همان NULLاند. (کج شدن یکی دو ستون در اسمهایی که نیمفاصله دارند، فقط به نمایش psql برمیگردد.) در برنامهها SELECT * را کم استفاده کن: ستونهایی را بخواه که لازم داری (مثال بعد).
مثال ۲: فیلتر برابری و مرتبسازی
Section titled “مثال ۲: فیلتر برابری و مرتبسازی”SELECT name, price FROM products WHERE category = 'کتاب' ORDER BY price DESC; name | price-------------+-------- کتاب داکر | 350000 کتاب پایتون | 320000 کتاب لینوکس | 280000(3 rows)WHERE category = 'کتاب': فقط سطرهایی که این شرط برایشان درست است. در SQL مقایسه با یک=است (برخلاف==پایتون) و نابرابری<>(یا!=).ORDER BY price DESC: از گران به ارزان (DESC)؛ پیشفرضASC(صعودی) است. بدونORDER BY، ترتیب سطرها تضمینشده نیست؛ اگر ترتیب برایت مهم است، همیشه بنویسش.
مثال ۳: بازه و فهرست، BETWEEN و IN
Section titled “مثال ۳: بازه و فهرست، BETWEEN و IN”SELECT name, price FROM products WHERE price BETWEEN 300000 AND 1500000 ORDER BY price;SELECT name, category FROM products WHERE category IN ('کتاب', 'شبکه') AND stock = 0; name | price-------------+--------- کتاب پایتون | 320000 کتاب داکر | 350000 ماوس بیسیم | 450000 هدفون | 1250000(4 rows)
name | category--------------+---------- کتاب لینوکس | کتاب سوئیچ 8 پورت | شبکه(2 rows)BETWEEN a AND b هر دو سر را شامل میشود (یعنی price >= a AND price <= b). IN (...) کوتاهشدهی چند OR است: category = 'کتاب' OR category = 'شبکه'. سؤال دوم همان سؤال مدیر فروش است: کتابها و کالاهای شبکهی تمامشده.
مثال ۴: الگوی متن، LIKE و ILIKE
Section titled “مثال ۴: الگوی متن، LIKE و ILIKE”SELECT name FROM products WHERE name LIKE 'کتاب%';SELECT name FROM products WHERE name ILIKE '%ssd%'; name------------- کتاب پایتون کتاب لینوکس کتاب داکر(3 rows)
name------------- SSD 512 گیگ(1 row)در LIKE، % یعنی «هر تعداد حرف (حتی صفر)» و _ یعنی «دقیقاً یک حرف». 'کتاب%' یعنی «با کتاب شروع شود» و '%ssd%' یعنی «جایی ssd داشته باشد». ILIKE (مخصوص PostgreSQL) به بزرگی و کوچکی حروف حساس نیست؛ برای همین ssd کوچک، SSD را پیدا کرد. (شبیه wildcardهای * و ? در shell، با علامتهای دیگر.)
کدام الگو اسمهایی را پیدا میکند که به «گیگ» ختم میشوند؟
جواب درست: LIKE '%گیگ'
% قبل از کلمه یعنی هر چیزی قبلش بیاید و بعدش چیزی نباشد.
مثال ۵: AND، OR و پرانتز
Section titled “مثال ۵: AND، OR و پرانتز”میخواهی «کتابها یا کالاهای شبکه، که گرانتر از یک میلیون باشند». بدون پرانتز:
SELECT name FROM products WHERE category = 'کتاب' OR category = 'شبکه' AND price > 1000000; name-------------- کتاب پایتون کتاب لینوکس کتاب داکر روتر وایفای سوئیچ 8 پورت(5 rows)کتابهای ارزان هم آمدند! چون AND قبل از OR حساب میشود (مثل ضرب قبل از جمع)، و شرط اینطور خوانده شد: «کتاب باشد، یا (شبکه باشد و گران)». با پرانتز:
SELECT name FROM products WHERE (category = 'کتاب' OR category = 'شبکه') AND price > 1000000; name-------------- روتر وایفای سوئیچ 8 پورت(2 rows)قاعده: هر وقت AND و OR در یک شرط هستند، پرانتز بگذار، حتی اگر فکر میکنی لازم نیست.
مثال ۶: NULL، مقدار نامعلوم
Section titled “مثال ۶: NULL، مقدار نامعلوم”SELECT name, discount FROM products WHERE discount = NULL;SELECT name, discount FROM products WHERE discount IS NULL LIMIT 3; name | discount------+----------(0 rows)
name | discount----------------+---------- کتاب لینوکس | کتاب داکر | کیبورد مکانیکی |(3 rows)اولی هیچ سطری نداد، با اینکه هفت کالا تخفیف ندارند. NULL یعنی «نامعلوم»، و «آیا نامعلوم برابر نامعلوم است؟» جوابش هم نامعلوم است، نه «درست». برای همین هر مقایسهای با NULL (=، <>، <) هرگز درست نمیشود. همیشه IS NULL و IS NOT NULL. برای جایگزین کردن NULL با یک مقدار پیشفرض، COALESCE (مثال ۸).
مثال ۷: ستون محاسبهای و AS
Section titled “مثال ۷: ستون محاسبهای و AS”SELECT name, price, stock, price * stock AS stock_valueFROM productsORDER BY stock_value DESCLIMIT 3; name | price | stock | stock_value----------------+---------+-------+------------- SSD 512 گیگ | 2750000 | 7 | 19250000 کیبورد مکانیکی | 1890000 | 8 | 15120000 فلش 64 گیگ | 290000 | 50 | 14500000(3 rows)SELECT میتواند حساب کند: price * stock ارزش موجودی هر کالاست. AS به نتیجه اسم میدهد (اسم مستعار یا alias) که در سرستون میآید و در ORDER BY هم قابلاستفاده است. LIMIT 3 فقط سه سطر اول را میدهد: «سه کالایی که بیشترین پول در انبار خواباندهاند».
مثال ۸: COALESCE و قیمت نهایی
Section titled “مثال ۸: COALESCE و قیمت نهایی”SELECT name, price, COALESCE(discount, 0) AS discount, price * (100 - COALESCE(discount, 0)) / 100 AS final_priceFROM productsWHERE category = 'لوازم جانبی'; name | price | discount | final_price----------------+---------+----------+------------- ماوس بیسیم | 450000 | 5 | 427500 کیبورد مکانیکی | 1890000 | 0 | 1890000 هدفون | 1250000 | 15 | 1062500(3 rows)COALESCE(a, b) اولین مقدار غیر NULL را برمیگرداند؛ اینجا یعنی «اگر تخفیف نیست، صفر». بدون آن، هر حسابی با NULL (مثل 100 - NULL) خودش NULL میشد و قیمت نهایی کیبورد خالی میماند.
مثال ۹: تاریخ، DISTINCT و صفحهبندی
Section titled “مثال ۹: تاریخ، DISTINCT و صفحهبندی”SELECT name, added_on FROM products WHERE added_on >= '2026-08-01' ORDER BY added_on;SELECT DISTINCT category FROM products ORDER BY category;SELECT name, price FROM products ORDER BY price DESC LIMIT 3 OFFSET 3; name | added_on--------------+------------ کتاب داکر | 2026-08-01 روتر وایفای | 2026-08-25 SSD 512 گیگ | 2026-09-12 سوئیچ 8 پورت | 2026-10-02(4 rows)
category------------- ذخیرهسازی شبکه لوازم جانبی کتاب(4 rows)
name | price----------------+--------- کیبورد مکانیکی | 1890000 سوئیچ 8 پورت | 1650000 هدفون | 1250000(3 rows)- تاریخها با قالب
'YYYY-MM-DD'و با همان عملگرهای مقایسه کار میکنند. DISTINCTتکراریها را حذف میکند: فهرست دستههای متفاوت.LIMIT 3 OFFSET 3یعنی «سه سطر اول را رد کن و سه تای بعدی را بده»؛ همان «صفحهی دوم» یک فهرست در سایت. (برای صفحهبندی همیشهORDER BYلازم است، وگرنه صفحهها ممکن است همپوشانی داشته باشند.)
پشت پرده: SQL «چه» میگوید، نه «چطور»
Section titled “پشت پرده: SQL «چه» میگوید، نه «چطور»”در پایتون حلقه مینوشتی: «برای هر سطر، اگر شرط درست بود، به لیست اضافه کن». در SQL فقط میگویی چه میخواهی («کتابهای گرانتر از …، مرتبشده بر اساس قیمت») و دیتابیس خودش تصمیم میگیرد چطور پیدایشان کند: کل جدول را بخواند، از یک ایندکس استفاده کند، یا اول مرتب کند و بعد فیلتر. به این زبان اعلانی (declarative) میگویند. بخشی از PostgreSQL به اسم برنامهریز (planner) بهترین راه را انتخاب میکند؛ در درس ایندکس با EXPLAIN نقشهای را که کشیده میبینی.
ترتیب منطقی اجرا هم با ترتیب نوشتن فرق دارد (شکل بالای درس): اول FROM و WHERE، بعد SELECT، بعد ORDER BY و LIMIT. برای همین اسم مستعاری که در SELECT ساختهای (stock_value) در ORDER BY قابلاستفاده است ولی در WHERE نه (اشتباهات رایج ۵).
جدولهای مرجع
Section titled “جدولهای مرجع”| عملگر | معنی | مثال |
|---|---|---|
= / <> |
برابر / نابرابر | category = 'کتاب' |
< > <= >= |
مقایسه | price > 1000000 |
BETWEEN a AND b |
در بازه (با دو سر) | price BETWEEN 1 AND 9 |
IN (...) |
یکی از فهرست | id IN (1, 3, 5) |
LIKE / ILIKE |
الگو (% هر چیز، _ یک حرف) / بدون حساسیت به حروف |
name ILIKE '%ssd%' |
IS NULL / IS NOT NULL |
خالی بودن | discount IS NULL |
AND / OR / NOT |
ترکیب (AND اول؛ پرانتز بگذار) | (a OR b) AND c |
| بخش | کار |
|---|---|
SELECT a, b AS x |
ستونها و اسم مستعار |
DISTINCT |
حذف تکراری |
ORDER BY a DESC, b |
مرتبسازی (چند ستونه) |
LIMIT n OFFSET m |
فقط n سطر بعد از m سطر |
COALESCE(x, 0) |
جایگزین NULL |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) = NULL بهجای IS NULL
Section titled “۱) = NULL بهجای IS NULL”مثال ۶: صفر سطر، بدون هیچ خطایی. خطرناک است چون ساکت است. راهحل: IS NULL.
۲) فراموش کردن پرانتز بین AND و OR
Section titled “۲) فراموش کردن پرانتز بین AND و OR”مثال ۵. راهحل: همیشه پرانتز.
۳) جا انداختن ویرگول بین ستونها
Section titled “۳) جا انداختن ویرگول بین ستونها”SELECT name price FROM products LIMIT 2; price------------- کتاب پایتون کتاب لینوکس(2 rows)هیچ خطایی نیامد؛ ولی سرستون میگوید price و داخلش اسمهاست! بدون ویرگول، price اسم مستعار ستون name شد (AS اختیاری است). راهحل: SELECT name, price.
۴) نگه داشتن عدد به شکل متن
Section titled “۴) نگه داشتن عدد به شکل متن”SELECT '9' > '10' AS text_compare, 9 > 10 AS number_compare; text_compare | number_compare--------------+---------------- t | f(1 row)متنها حرف به حرف مقایسه میشوند و «۹» از «۱» بزرگتر است، پس '9' > '10' درست است (t). اگر قیمت را در ستون TEXT نگه داری، مرتبسازی و مقایسهات خراب میشود. راهحل: نوع درست برای هر ستون (INTEGER، NUMERIC، DATE).
۵) استفاده از اسم مستعار در WHERE
Section titled “۵) استفاده از اسم مستعار در WHERE”SELECT price * stock AS v FROM products WHERE v > 10000000; خطای column "v" does not exist میدهد، چون WHERE قبل از SELECT اجرا میشود. راهحل: خود عبارت را تکرار کن: WHERE price * stock > 10000000.
۶) کوتیشن دوتایی برای متن
Section titled “۶) کوتیشن دوتایی برای متن”ERROR: column "هدفون" does not existLINE 1: SELECT name FROM products WHERE name = "هدفون"; ^راهحل: 'هدفون' (درس قبل).
اسم و موجودی همهی کالاهایی را بده که موجودیشان صفر نیست و قیمتشان زیر ۵۰۰ هزار تومان است، از ارزان به گران.
دیدن جواب
SELECT name, price, stock FROM products WHERE stock > 0 AND price < 500000 ORDER BY price; name | price | stock-------------+--------+------- کابل شبکه | 95000 | 120 فلش 64 گیگ | 290000 | 50 کتاب پایتون | 320000 | 12 کتاب داکر | 350000 | 5 ماوس بیسیم | 450000 | 30(5 rows)تمرین اصلی: فهرست کالاهایی را بده که تخفیف دارند، با اسم، دسته و درصد تخفیف، از بیشترین تخفیف به کمترین.
دیدن جواب
SELECT name, category, discountFROM productsWHERE discount IS NOT NULLORDER BY discount DESC; name | category | discount--------------+-------------+---------- سوئیچ 8 پورت | شبکه | 20 هدفون | لوازم جانبی | 15 کتاب پایتون | کتاب | 10 SSD 512 گیگ | ذخیرهسازی | 10 ماوس بیسیم | لوازم جانبی | 5(5 rows)اگر WHERE discount > 0 مینوشتی هم همین جواب میآمد، چون مقایسه با NULL هرگز درست نیست؛ ولی IS NOT NULL نیتت را صریحتر میگوید.
کالاهایی را پیدا کن که در سه ماه اول سال ۲۰۲۶ (ژانویه تا مارس) اضافه شدهاند، و برای هر کدام «قیمت نهایی» بعد از تخفیف را هم با اسم مستعار final_price نشان بده؛ مرتب بر اساس تاریخ.
دیدن جواب
SELECT name, added_on, price, price * (100 - COALESCE(discount, 0)) / 100 AS final_priceFROM productsWHERE added_on BETWEEN '2026-01-01' AND '2026-03-31'ORDER BY added_on; name | added_on | price | final_price-------------+------------+--------+------------- کابل شبکه | 2026-01-05 | 95000 | 95000 کتاب لینوکس | 2026-01-22 | 280000 | 280000 ماوس بیسیم | 2026-02-14 | 450000 | 427500 کتاب پایتون | 2026-03-10 | 320000 | 288000(4 rows)BETWEEN روی تاریخ هم دو سر را شامل میشود. (برای ستونهای TIMESTAMP که ساعت هم دارند، < '2026-04-01' امنتر است، چون '2026-03-31' یعنی نیمهشب آغاز آن روز.)
آزمونک
Section titled “آزمونک”کدام شرط کالاهای بدون تخفیف را پیدا میکند؟
جواب درست: discount IS NULL
هر مقایسه با NULL نامعلوم است.
در LIKE، الگوی 'a_c' با کدام جور است؟
جواب درست: abc
_ دقیقاً یک حرف است؛ % هر تعداد.
a OR b AND c چطور خوانده میشود؟
جواب درست: a OR (b AND c)
AND اولویت بالاتری دارد؛ پرانتز بگذار.
بدون ORDER BY ترتیب سطرهای SELECT…
جواب درست: تضمینشده نیست
اگر ترتیب مهم است، ORDER BY بنویس.
LIMIT 10 OFFSET 20 چه سطرهایی میدهد؟
جواب درست: ۲۱ تا ۳۰
۲۰ سطر رد، ۱۰ تا بعدی.
COALESCE(discount, 0) چه میکند؟
جواب درست: اگر discount خالی (NULL) بود صفر برمیگرداند، وگرنه خودش را
اولین مقدار غیر NULL.
جمعبندی
Section titled “جمعبندی”SELECT ستونها FROM جدول WHERE شرط ORDER BY ... LIMIT ...؛ ستونهای لازم را بخواه، نه*.- فیلترها:
=،<>، مقایسهها،BETWEEN(با دو سر)،IN،LIKE/ILIKEبا%و_. ANDقبل ازORحساب میشود؛ همیشه پرانتز.NULLیعنی نامعلوم:IS NULL/IS NOT NULL، وCOALESCEبرای مقدار پیشفرض.SELECTحساب میکند (price * stock AS v)؛ اسم مستعار درORDER BYکار میکند، درWHEREنه.DISTINCTبرای تکراریها،LIMIT ... OFFSET ...برای صفحهبندی (همیشه باORDER BY).
| دستور | کاری که میکند |
|---|---|
SELECT name, price FROM products WHERE category = 'کتاب'; | فیلتر ساده |
ORDER BY price DESC LIMIT 5 | پنج گرانترین |
WHERE price BETWEEN 1 AND 9 | بازه |
WHERE category IN ('a', 'b') | فهرست |
WHERE name ILIKE '%ssd%' | جستجوی متن بدون حساسیت به حروف |
WHERE discount IS NULL | خالیها |
COALESCE(discount, 0) | جایگزین NULL |
SELECT price * stock AS value | ستون محاسبهای |
SELECT DISTINCT category | مقدارهای یکتا |
psql shop -f file.sql | اجرای فایل SQL |