JOINS (ডেটা জোড়া লাগানোর কৌশল)
এতক্ষণ আমরা একটি সিঙ্গেল টেবিল নিয়ে কাজ করেছি। কিন্তু বাস্তব প্রজেক্টে ডেটা কখনোই এক টেবিলে থাকে না। ইউজারের তথ্য থাকে users টেবিলে, আর অর্ডারের তথ্য থাকে orders টেবিলে।
এই আলাদা আলাদা টেবিল থেকে সম্পর্কযুক্ত ডেটা এক সাথে নিয়ে আসার প্রক্রিয়াকে বলা হয় JOIN।
৫.১ কেন JOIN প্রয়োজন? (বাস্তব উদাহরণ)
ধরি আমাদের দুটি টেবিল আছে:
Table A: users
| id | name |
|---|---|
| 1 | Shagor |
| 2 | Rabbi |
| 3 | Sakib |
Table B: orders
| id | user_id | amount |
|---|---|---|
| 10 | 1 | 500 |
| 11 | 1 | 300 |
| 12 | 2 | 200 |
লক্ষ করুন: Sakib (id: 3) এর কোনো অর্ডার নেই।
এখন যদি প্রশ্ন করা হয়: "কে কত টাকার অর্ডার করেছে?"—এই উত্তর এক টেবিলে নেই। তখনই আমাদের JOIN লাগবে।
৫.২ INNER JOIN (সবচেয়ে বেশি ব্যবহৃত)
এটি হলো Intersection বা সাধারণ এলাকা।
লজিক: দুটি টেবিলের মধ্যে শুধুমাত্র যে রোগুলোর মিল আছে, সেগুলোই দেখাবে। যার মিল নেই, সে বাদ।
Syntax:
SELECT users.name, orders.amount
FROM users
INNER JOIN orders ON users.id = orders.user_id;
Result:
- Shagor এবং Rabbi আসবে (কারণ তাদের অর্ডার আছে)।
- Sakib আসবে না (কারণ orders টেবিলে তার user_id নেই)।
ব্যবহার: রিপোর্ট, ইনভয়েস, ড্যাশবোর্ড—যেখানে মিসিং ডেটা বা নাল ভ্যালু দেখার দরকার নেই।
৫.৩ LEFT JOIN (মিসিং ডেটা বের করার বস)
এটি হলো Priority to Left Table।
লজিক: বাম পাশের টেবিলের (users) সব ডেটা আসবে। ডান পাশের টেবিলে (orders) মিল থাকলে ডেটা দেখাবে, আর মিল না থাকলে NULL দেখাবে।
Syntax:
SELECT users.name, orders.amount
FROM users
LEFT JOIN orders ON users.id = orders.user_id;
Result:
| name | amount |
|---|---|
| Shagor | 500 |
| Rabbi | 200 |
| Sakib | NULL |
Sakib কেন আসল? কারণ LEFT JOIN বাম পাশের users টেবিলের সবাইকে নিয়ে আসে, অর্ডার থাকুক বা না থাকুক।
ব্যবহার: "কোন ইউজার এখনো অর্ডার করেনি?" বা "কোন প্রোডাক্ট বিক্রি হয়নি?"—এসব বের করতে এটি অপরিহার্য।
৫.৪ RIGHT JOIN
এটি LEFT JOIN এর ঠিক উল্টো। ডান পাশের টেবিল প্রায়োরিটি পায়।
SELECT users.name, orders.amount
FROM users
RIGHT JOIN orders ON users.id = orders.user_id;
💡 বাস্তব কথা: প্রফেশনাল লাইফে RIGHT JOIN খুব কম ব্যবহার হয়। কারণ টেবিলগুলোর জায়গা অদলবদল করে LEFT JOIN দিয়েই সব কাজ করা যায় এবং LEFT JOIN পড়া সহজ।
৫.৫ FULL JOIN (MySQL Workaround)
MySQL-এ সরাসরি FULL OUTER JOIN সাপোর্ট করে না।
লজিক: বাম এবং ডান—উভয় টেবিলের সব ডেটা আসবে। মিললে ভালো, না মিললে NULL।
MySQL সমাধান (UNION দিয়ে):
SELECT * FROM users LEFT JOIN orders ON users.id = orders.user_id
UNION
SELECT * FROM users RIGHT JOIN orders ON users.id = orders.user_id;
UNION দুটি কুয়েরির রেজাল্ট জোড়া লাগিয়ে ডুপ্লিকেট বাদ দিয়ে দেয়।
৫.৬ SELF JOIN (নিজেকে নিজেই জয়েন করা)
এটি জুনিয়রদের জন্য একটু কনফিউজিং হতে পারে, কিন্তু হায়ারার্কি (Hierarchy) মেইনটেইন করতে এটি লাগে।
দৃশ্যপট:
এমপ্লয়ি টেবিলে manager_id আছে, যা ওই টেবিলেরই অন্য একজন এমপ্লয়ির id।
Table: employees
| id | name | manager_id |
|---|---|---|
| 1 | Boss | NULL |
| 2 | Dev A | 1 |
Query: কার বস কে?
SELECT e.name AS Employee, m.name AS Manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;
(এখানে আমরা একই টেবিলকে দুইটা আলাদা নাম e এবং m দিয়ে জয়েন করেছি)
৫.৭ CROSS JOIN (বিপজ্জনক কিন্তু দরকারি)
এটি কোনো শর্ত (ON) ছাড়া জয়েন করে। একে Cartesian Product বলে। টেবিল A-এর প্রতিটি রো, টেবিল B-এর প্রতিটি রো-এর সাথে গুণ হবে।
উদাহরণ:
Sizes: S, M, L (3টি) | Colors: Red, Blue (2টি)
SELECT * FROM sizes CROSS JOIN colors;
আউটপুট: ৩ x ২ = ৬টি রো (S-Red, S-Blue, M-Red... এভাবে সব কম্বিনেশন)।
⚠️ Warning:
বড় টেবিলে এটি চালাবেন না। ১০০০ রো x ১০০০ রো = ১০ লক্ষ রো হয়ে সার্ভার হ্যাং করতে পারে!
ব্যবহার: ই-কমার্সে প্রোডাক্ট ভেরিয়েন্ট (Size x Color) জেনারেট করতে।
৫.৮ Multiple Table JOIN (Real Project Scenario)
বাস্তব প্রজেক্টে ৩-৪টি টেবিল জয়েন করা খুব সাধারণ। ফ্লো: User -> Order -> OrderItems -> Product
SELECT
u.name AS customer,
o.id AS order_id,
p.name AS product_name,
oi.quantity
FROM users u
JOIN orders o ON u.id = o.user_id -- ১. ইউজার ও অর্ডার জয়েন
JOIN order_items oi ON o.id = oi.order_id -- ২. আইটেম জয়েন
JOIN products p ON oi.product_id = p.id; -- ৩. প্রোডাক্ট নাম আনলাম
৫.৯ JOIN + GROUP BY (Analytics Power)
প্রশ্ন: প্রত্যেক ইউজার মোট কত টাকার কেনাকাটা করেছে?
SELECT u.name, SUM(o.amount) AS total_spent
FROM users u
LEFT JOIN orders o ON u.id = o.user_id -- LEFT JOIN যাতে যারা কেনেনি তারাও লিস্টে আসে (0 বা NULL হিসেবে)
GROUP BY u.id;
৫.১০ Senior Level Real-World Patterns (Interview Favorites)
এই কুয়েরিগুলো ইন্টারভিউতে প্রায়ই আসে।
১. যারা কখনো অর্ডার করেনি তাদের খুঁজে বের করো (Find Inactive Users):
SELECT u.name
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
ব্যাখ্যা: LEFT JOIN সব ইউজার আনে। যাদের অর্ডার নেই তাদের o.id বা o.user_id হবে NULL। আমরা সেটাকেই টার্গেট করেছি।
২. টপ ৫ কাস্টমার (টাকার অংকে):
SELECT u.name, SUM(o.amount) AS total
FROM users u
JOIN orders o ON u.id = o.user_id
GROUP BY u.id
ORDER BY total DESC
LIMIT 5;
৫.১১ JOIN Performance Optimization (Senior Checklist)
একজন সিনিয়র ডেভেলপার হিসেবে কুয়েরি লেখার সময় নিচের বিষয়গুলো মাথায় রাখা ফরজ:
✅ Index on Foreign Keys:
ON users.id = orders.user_id — এখানে id এবং user_id দুটিতেই ইনডেক্স থাকতে হবে। ইনডেক্স না থাকলে এটি সুপার স্লো হবে।
✅ Same Data Type:
INT এর সাথে VARCHAR জয়েন করবেন না।
users.id (INT) = orders.user_id (VARCHAR)❌ (খুব স্লো)users.id (INT) = orders.user_id (INT)✅ (ফাস্ট)
✅ Avoid Functions in Join Condition:
ON DATE(a.created_at) = DATE(b.created_at) ❌ (ইনডেক্স কাজ করবে না)
✅ No SELECT *:
জয়েনে অনেক কলাম থাকে। SELECT * দিলে মেমোরি অনেক বেশি খরচ হয়। শুধু যা দরকার তা নিন।
✅ Use Explicit JOIN Syntax:
FROM users, orders WHERE... (Old Style) — ব্যবহার করবেন না। এটি পড়া কঠিন এবং অপটিমাইজ করা ঝামেলার।
সবসময় INNER JOIN, LEFT JOIN কিওয়ার্ড ব্যবহার করুন।
🎯 অধ্যায় ৫ এর সারাংশ (Summary)
এই অধ্যায়ে আপনি শিখলেন:
- ✓ INNER JOIN: শুধু ম্যাচিং ডেটা (কমন)।
- ✓ LEFT JOIN: সব ডেটা + ম্যাচিং ডেটা (মিসিং ডেটা বের করতে সেরা)।
- ✓ SELF JOIN: নিজের সাথে নিজে জয়েন (হায়ারার্কি)।
- ✓ Multi-Join: রিয়েল লাইফ অ্যাপ্লিকেশনের মেরুদণ্ড।
- ✓ Performance: ইনডেক্সিং এবং ডেটা টাইপের গুরুত্ব।
✨ JOIN বোঝা মানে আপনি এখন রিলেশনাল ডেটাবেসের আসল শক্তি ব্যবহার করতে প্রস্তুত। পরবর্তী অধ্যায়ে আমরা টেবিলের সুরক্ষা এবং কনসিস্টেন্সি নিয়ে কথা বলব—Keys & Constraints (Primary, Foreign, Unique etc.)।