در SQL، خروجی هر پرسوجو در واقع یک مجموعه از ردیفها (Rows) است.
اما برخلاف مجموعههای ریاضی، SQL از نوع خاصی از مجموعه به نام Multi-Set یا Bag استفاده میکند — یعنی مجموعههایی که میتوانند دادههای تکراری داشته باشند.
به همین دلیل، در بسیاری از پرسوجوها با دادههای تکراری مواجه میشویم و لازم است بدانیم چطور آنها را مدیریت کنیم.
برای حذف دادههای تکراری از نتایج، میتوانیم از کلمه کلیدی DISTINCT استفاده کنیم:
SELECT DISTINCT country FROM customers;
💡 این دستور فقط مقادیر منحصربهفرد کشورها را برمیگرداند و تکراریها را حذف میکند. اگر ردیفهای تکراری چند ستونه را هم بخواهیم حذف کنیم این دستور آنها را هم حذف میکند رکوردهایی را بر میگرداند که ترکیب مقادیر ستونهای آنها منحصر بفرد و غیرتکراری باشد.
در زبان SQL، خروجی هر پرسوجو در واقع یک مجموعه از ردیفها (Rows) است. اما بر خلاف مجموعههای ریاضی، SQL با چیزی به نام Multi-Set یا Bag کار میکند – یعنی مجموعههایی که میتوانند دادههای تکراری داشته باشند.
این ویژگی مهم باعث میشود که هنگام ترکیب، مقایسه یا فیلتر کردن نتایج، بتوانیم رفتار دادههای تکراری را بهطور دقیق کنترل کنیم. مثلاً گاهی میخواهیم تمام ردیفها را حفظ کنیم (حتی تکراریها) و گاهی فقط دادههای یکتا را نگه داریم.
نکته مهم : در SQL، برای انجام عملیات مجموعهای (مثل UNION, INTERSECT, EXCEPT) بین دو نتیجه پرسوجو، دو شرط اصلی وجود دارد:
در غیر این صورت، با خطای نوع داده یا ساختار مواجه خواهیم شد.
در این بخش با عملیات مجموعهای (UNION, INTERSECT, EXCEPT) و عملگرهای عضویت (IN, SOME, ALL) آشنا میشویم و یاد میگیریم چطور نتایج چند پرسوجو را با هم ترکیب، مقایسه یا از هم تفکیک کنیم.
در SQL، هر کوئری یک «مجموعه از نتایج» را تولید میکند.
عملیات مجموعهای به ما اجازه میدهد تا این نتایج را با هم ترکیب یا مقایسه کنیم.
| عملیات | مفهوم | مثال |
|---|---|---|
UNION | ترکیب دو مجموعه و حذف تکراریها | همه مشتریان از دو منطقه |
UNION ALL | ترکیب دو مجموعه و حفظ تکراریها | ادغام دادهها بدون حذف تکرار |
INTERSECT | نگه داشتن عناصر مشترک | مشتریانی که از هر دو کشور خرید کردهاند |
EXCEPT | تفریق مجموعهها | سفارشهای سال ۱۹۹۷ که در ۱۹۹۸ تکرار نشدهاند |
SELECT customer_id, company_name, country
FROM customers
WHERE country IN ('Germany', 'France', 'UK')
UNION
SELECT customer_id, company_name, country
FROM customers
WHERE country IN ('Brazil', 'Argentina', 'Venezuela');
💡 نکته: دستور
UNIONبه طور پیشفرض تکراریها را حذف میکند.
UNION ALLSELECT ship_country
FROM orders
WHERE order_date < '1998-01-01'
UNION ALL
SELECT ship_country
FROM orders
WHERE order_date >= '1998-01-01';
🧠 در این حالت، اگر کشوری در هر دو مجموعه وجود داشته باشد، دو بار در خروجی دیده میشود.
SELECT DISTINCT product_id
FROM orders o
JOIN order_details od USING(order_id)
WHERE ship_country = 'France'
INTERSECT
SELECT DISTINCT product_id
FROM orders o
JOIN order_details od USING(order_id)
WHERE ship_country = 'Germany';
🧩 نتیجه: تمام محصولاتی که در هر دو مجموعه وجود دارند (یعنی در هر دو کشور ارسال شدهاند).
SELECT DISTINCT product_id
FROM orders o
JOIN order_details od USING(order_id)
WHERE ship_country = 'Germany'
EXCEPT
SELECT DISTINCT product_id
FROM orders o
JOIN order_details od USING(order_id)
WHERE ship_country = 'France';
⚙️ در واقع این دستور یعنی: مجموعه A منهای مجموعه B
در SQL نسخههای ALL برای حفظ تکراریها وجود دارند:
| دستور | رفتار |
|---|---|
UNION ALL | همه ردیفها را نگه میدارد |
INTERSECT ALL | فقط تکرارهایی که در هر دو مجموعه وجود دارند را نگه میدارد |
EXCEPT ALL | فقط یک نسخه از دادههایی که در مجموعه دوم وجود دارند را حذف میکند |
SELECT 'A' AS letter
UNION ALL
SELECT 'A'
UNION ALL
SELECT 'B';
خروجی: دو مقدار “A” و یک مقدار “B”
(SQL رفتار Multi-Set را نشان میدهد)
SELECT *
FROM customers
WHERE country IN ('France', 'Germany', 'UK');
نتیجه: مشتریانی که کشورشان در این لیست است.
در SQL میتوان چند ستون را همزمان مقایسه کرد:
SELECT *
FROM employees e
WHERE (e.employee_id, e.title) = (2, 'Sales Manager');
💡 زمانی مفید است که بخواهیم ترکیب چند ویژگی را در یک شرط بررسی کنیم.
عملگرهای SOME (یا ANY) و ALL برای مقایسه با خروجی زیرپرسوجوها (Subqueries) استفاده میشوند.
SELECT product_name, unit_price
FROM products
WHERE unit_price > SOME (
SELECT unit_price
FROM products p
JOIN order_details od USING(product_id)
JOIN orders o USING(order_id)
WHERE ship_country = 'France'
);
SELECT product_name, unit_price
FROM products
WHERE unit_price > ALL (
SELECT unit_price
FROM products p
JOIN order_details od USING(product_id)
JOIN orders o USING(order_id)
WHERE ship_country = 'Brazil'
);
💬
SOMEیعنی شرط برای حداقل یکی از ردیفها برقرار است.
💬ALLیعنی شرط باید برای تمام ردیفها برقرار باشد.
SELECT product_id, SUM(quantity) AS total_qty
FROM order_details od
JOIN orders o USING(order_id)
WHERE ship_country = 'France'
GROUP BY product_id
HAVING SUM(quantity) > 10
INTERSECT
SELECT product_id, SUM(quantity) AS total_qty
FROM order_details od
JOIN orders o USING(order_id)
WHERE ship_country = 'Germany'
GROUP BY product_id
HAVING SUM(quantity) > 10;
در SQL، هر مقایسه با NULL نتیجهای نامشخص (UNKNOWN) دارد.
SELECT (5 < NULL); -- → NULL
SELECT (NULL = NULL); -- → NULL
SELECT (NULL <> NULL); -- → NULL
بنابراین:
IN و NOT IN اگر زیرپرسوجو شامل NULL باشد، نتایج ممکن است غیرمنتظره باشند.IS NULL یا IS NOT NULL استفاده کنید تا رفتار دقیقتر و قابل پیشبینی باشد.| مفهوم | دستور | توضیح |
|---|---|---|
| ترکیب نتایج | UNION, UNION ALL | ادغام مجموعهها |
| یافتن اشتراک | INTERSECT, INTERSECT ALL | ردیفهای مشترک |
| یافتن تفاوت | EXCEPT, EXCEPT ALL | حذف دادههای مشترک |
| بررسی عضویت | IN, NOT IN, SOME, ALL | بررسی وجود در مجموعه |
| مقایسه چندستونه | (a, b) = (x, y) | بررسی چند ستون همزمان |
| رفتار NULL | IS NULL, IS NOT NULL | مقایسه دقیقتر مقادیر تهی |