جواب کوتاه: INNER JOIN فقط ردیفهایی را برمیگرداند که در هر دو جدول طرف دارند؛ LEFT JOIN همهی ردیفهای جدول چپ را نگه میدارد، حتی اگر طرف مقابل چیزی نداشته باشد. اگر دنبال «کاربرانی که سفارش نداشتند» هستید، INNER JOIN همانهایی را که میخواهید ببینید، بیسروصدا حذف میکند.
یک مثال با دادهی واقعی
سه کاربر داریم؛ یکیشان (مریم) هیچ سفارشی نداده:
sqlSELECT users.name, orders.amount
FROM users INNER JOIN orders ON orders.user_id = users.id;
name amount
---- ------
سارا 150000
سارا 90000
رضا 300000
مریم اصلاً در خروجی نیست — نه خطا، نه هشدار، فقط یک ردیف که هیچوقت وجود نداشت.
LEFT JOIN همان کاربر را با NULL نگه میدارد
sqlSELECT users.name, orders.amount
FROM users LEFT JOIN orders ON orders.user_id = users.id;
name amount
---- ------
سارا 90000
سارا 150000
رضا 300000
مریم NULL
حالا مریم هست، با amount خالی. این خالیبودن، دقیقاً همان اطلاعاتی است که در نسخهی INNER JOIN گم شده بود.
پیدا کردن «چه کسی هیچکدام را ندارد»
sqlSELECT users.name
FROM users LEFT JOIN orders ON orders.user_id = users.id
WHERE orders.id IS NULL;
این الگو — LEFT JOIN بهعلاوهی WHERE ... IS NULL روی کلید جدول راست — تنها راه استاندارد برای «چیزی که وجود ندارد» است. با INNER JOIN اصلاً نمیشود این سؤال را پرسید، چون ردیفی که وجود ندارد را نمیشود فیلتر کرد.
گیری که COUNT با آن میخورد
sqlSELECT users.name, COUNT(*) AS order_count
FROM users LEFT JOIN orders ON orders.user_id = users.id
GROUP BY users.id;
name order_count
---- -----------
سارا 2
رضا 1
مریم 1 -- غلط! مریم صفر سفارش دارد
LEFT JOIN برای مریم یک ردیف با NULL میسازد، و COUNT(*) همان یک ردیف را میشمارد — نتیجه میشود ۱، نه ۰. راه درست، شمردن ستونی از جدول راست است، نه *:
sqlSELECT users.name, COUNT(orders.id) AS order_count
FROM users LEFT JOIN orders ON orders.user_id = users.id
GROUP BY users.id;
-- مریم: 0
COUNT(orders.id) مقدارهای NULL را نمیشمارد، پس مریم درست صفر میشود. این یککلمه فرق — * بهجای orders.id — دلیل کلاسیک گزارشهای اشتباه است.
یک گیر دیگر: شرط در WHERE، LEFT JOIN را دوباره INNER میکند
sqlSELECT users.name, orders.amount
FROM users LEFT JOIN orders ON orders.user_id = users.id
WHERE orders.amount > 100000;
name amount
---- ------
سارا 150000
رضا 300000
مریم دوباره غیب شد — چون NULL > 100000 نه true است نه false، نامعلوم است، و WHERE هر ردیفی را که شرطش نامعلوم باشد حذف میکند. LEFT JOIN نوشته بودید، ولی نتیجه دقیقاً همان INNER JOIN شد. راهحل، جابهجا کردن شرط از WHERE به ON است:
sqlSELECT users.name, orders.amount
FROM users LEFT JOIN orders ON orders.user_id = users.id AND orders.amount > 100000;
حالا مریم با NULL میماند، چون فیلتر قبل از پیوستن جدولها اعمال شده، نه بعدش. قانون کلی: هر شرطی که فقط روی ستونهای جدول راست باشد، در ON بنویسید — نه WHERE — وگرنه LEFT JOIN عملاً بیمعنی میشود.
اگر میخواهید SQL را از صفر و با کوئریهای واقعی یاد بگیرید، دورهی SQL دقیقاً همین گیرهای رایج را تمرین میکند.





نظرها
اولین نفری باشید که نظر میدهدسؤالتان را بپرسید یا تجربهتان را بنویسید — نویسندهی مطلب پاسخ میدهد.