تفاوت انواع JOIN در SQL با مثال: INNER، LEFT، RIGHT و FULL
JOIN ابزار وصل کردن اطلاعات چند جدول در یک پرسوجوست و یکی از مهمترین مباحث SQL (و پرتکرارترین سؤال امتحان و مصاحبه). تفاوت انواع آن فقط در یک چیز است: با ردیفهایی که جفت ندارند چه میکند؟
جدولهای مثال
دو جدول Customers و Orders داریم. مشتری «رضا» هنوز سفارشی ندارد و سفارش ۱۰۴ به هیچ مشتری وصل نیست (CustomerId آن NULL است):
CREATE TABLE Customers (CustomerId INT PRIMARY KEY, Name NVARCHAR(50)); CREATE TABLE Orders (OrderId INT PRIMARY KEY, CustomerId INT NULL, Amount INT); INSERT INTO Customers VALUES (1, N'Ali'), (2, N'Sara'), (3, N'Reza'); INSERT INTO Orders VALUES (101, 1, 500), (102, 1, 300), (103, 2, 700), (104, NULL, 900);
| Customers: CustomerId | Name |
|---|---|
| 1 | Ali |
| 2 | Sara |
| 3 | Reza |
| Orders: OrderId | CustomerId | Amount |
|---|---|---|
| 101 | 1 | 500 |
| 102 | 1 | 300 |
| 103 | 2 | 700 |
| 104 | NULL | 900 |
نمای کلی با نمودار
INNER JOIN: فقط ردیفهای مشترک
SELECT c.Name, o.OrderId, o.Amount FROM Customers c INNER JOIN Orders o ON o.CustomerId = c.CustomerId;
| Name | OrderId | Amount |
|---|---|---|
| Ali | 101 | 500 |
| Ali | 102 | 300 |
| Sara | 103 | 700 |
«رضا» (بدون سفارش) و سفارش ۱۰۴ (بدون مشتری) هر دو حذف شدهاند.
LEFT JOIN: همهی ردیفهای جدول چپ
SELECT c.Name, o.OrderId, o.Amount FROM Customers c LEFT JOIN Orders o ON o.CustomerId = c.CustomerId;
| Name | OrderId | Amount |
|---|---|---|
| Ali | 101 | 500 |
| Ali | 102 | 300 |
| Sara | 103 | 700 |
| Reza | NULL | NULL |
الگوی پرکاربرد: پیدا کردن ردیفهای بدون جفت. مشتریانی که هیچ سفارشی ندارند:
SELECT c.Name FROM Customers c LEFT JOIN Orders o ON o.CustomerId = c.CustomerId WHERE o.OrderId IS NULL; -- فقط Reza
RIGHT JOIN: همهی ردیفهای جدول راست
SELECT c.Name, o.OrderId, o.Amount FROM Customers c RIGHT JOIN Orders o ON o.CustomerId = c.CustomerId;
| Name | OrderId | Amount |
|---|---|---|
| Ali | 101 | 500 |
| Ali | 102 | 300 |
| Sara | 103 | 700 |
| NULL | 104 | 900 |
RIGHT JOIN دقیقاً همان LEFT JOIN با جابهجایی ترتیب جدولهاست؛ به همین دلیل در عمل کمتر استفاده میشود.
FULL JOIN: همهی ردیفهای هر دو طرف
SELECT c.Name, o.OrderId, o.Amount FROM Customers c FULL JOIN Orders o ON o.CustomerId = c.CustomerId;
| Name | OrderId | Amount |
|---|---|---|
| Ali | 101 | 500 |
| Ali | 102 | 300 |
| Sara | 103 | 700 |
| Reza | NULL | NULL |
| NULL | 104 | 900 |
CROSS JOIN و SELF JOIN
CROSS JOIN ضرب دکارتی است: هر ردیف جدول اول با تمام ردیفهای جدول دوم ترکیب میشود (۳×۴ = ۱۲ ردیف). برای تولید ترکیبها (مثل همهی سایز و رنگهای یک محصول) مفید است.
SELECT c.Name, o.OrderId FROM Customers c CROSS JOIN Orders o;
SELF JOIN یعنی جدول را با خودش JOIN کنی، برای ساختارهای سلسلهمراتبی مثل کارمند و مدیرش. حتماً به هر نمونه یک Alias متفاوت بده:
SELECT e.FullName AS Employee, m.FullName AS Manager FROM Employees e LEFT JOIN Employees m ON m.EmployeeId = e.ManagerId;
جدول مقایسه
| نوع JOIN | ردیفهای بدون جفت چپ | ردیفهای بدون جفت راست | کاربرد |
|---|---|---|---|
| INNER | حذف | حذف | فقط دادههای مرتبط |
| LEFT | نگهداری (NULL) | حذف | همهی جدول اصلی + اطلاعات اختیاری |
| RIGHT | حذف | نگهداری (NULL) | مثل LEFT با جهت برعکس |
| FULL | نگهداری | نگهداری | مقایسهی دو مجموعه |
| CROSS | — | — | ضرب دکارتی / تولید ترکیب |
نکتههایی که باعث خطا میشوند
- شرط روی جدول راست در WHERE:
LEFT JOIN ... WHERE o.Amount > 400ردیفهای NULL را حذف میکند و عملاً INNER JOIN میشود. شرط را در ON بنویس. - ردیفهای تکراری: اگر رابطه یکبهچند باشد، ردیف جدول «یک» به تعداد ردیفهای «چند» تکرار میشود؛ بعد از JOIN،
SUMوCOUNTرا با دقت بنویس. - ستون مبهم: اگر دو جدول ستون همنام دارند، همیشه با Alias مشخص کن (
c.CustomerId). - JOIN روی NULL:
NULL = NULLدرست نیست؛ ردیفهایی که کلید NULL دارند هیچوقت در JOIN جفت نمیشوند.
مثالها را در Playground امتحان کن (چون موتور آن SQLite است، حرف N قبل از رشتهها را بردار) و درسهای INNER JOIN و LEFT JOIN را برای تمرین بیشتر ببین.
سوالات متداول دربارهی این موضوع
تفاوت INNER JOIN و LEFT JOIN چیست؟
INNER JOIN فقط ردیفهایی را برمیگرداند که در هر دو جدول جفت دارند؛ LEFT JOIN همهی ردیفهای جدول چپ را برمیگرداند و اگر جفتی در جدول راست نباشد، ستونهای آن را NULL میگذارد.
شرط را در ON بنویسم یا WHERE؟
در INNER JOIN فرقی ندارد، اما در LEFT JOIN شرط روی جدول راست در WHERE ردیفهای NULL را حذف میکند و نتیجه را به INNER JOIN تبدیل میکند. شرطهای مربوط به جدول راست را در ON بگذار.
JOIN بدون شرط ON چه میشود؟
اگر از CROSS JOIN استفاده کنی ضرب دکارتی میگیری (هر ردیف جدول اول با همهی ردیفهای جدول دوم). فراموش کردن شرط در JOIN معمولاً به نتیجهی بسیار بزرگ و اشتباه منجر میشود.
میخوای SQL را از پایه و با تمرین یاد بگیری؟
دورهی رایگان SQLFarsi را با Playground و پروژههای واقعی دنبال کن.
شروع یادگیری