# ডেটার সাথে কাজ করা: রিলেশনাল ডেটাবেস |![ [(@sketchthedocs)](https://sketchthedocs.dev) এর স্কেচনোট ](../../sketchnotes/05-RelationalData.png)| |:---:| | ডেটার সাথে কাজ করা: রিলেশনাল ডেটাবেস - _[@nitya](https://twitter.com/nitya) এর স্কেচনোট_ | সম্ভবত আপনি অতীতে তথ্য সংরক্ষণ করার জন্য একটি স্প্রেডশিট ব্যবহার করেছেন। সেখানে সারি এবং কলামের একটি সেট ছিল, যেখানে সারিগুলো তথ্য (বা ডেটা) ধারণ করত এবং কলামগুলো সেই তথ্যের বর্ণনা দিত (যাকে কখনও কখনও মেটাডেটা বলা হয়)। একটি রিলেশনাল ডেটাবেস এই মূল নীতির উপর ভিত্তি করে তৈরি হয়, যেখানে টেবিলের মধ্যে কলাম এবং সারি থাকে, যা আপনাকে একাধিক টেবিলে তথ্য ছড়িয়ে রাখতে দেয়। এটি আপনাকে আরও জটিল ডেটার সাথে কাজ করতে, পুনরাবৃত্তি এড়াতে এবং ডেটা অনুসন্ধানের ক্ষেত্রে নমনীয়তা প্রদান করে। চলুন রিলেশনাল ডেটাবেসের ধারণাগুলো অন্বেষণ করি। ## [পূর্ব-লেকচার কুইজ](https://purple-hill-04aebfb03.1.azurestaticapps.net/quiz/8) ## সবকিছু শুরু হয় টেবিল দিয়ে একটি রিলেশনাল ডেটাবেসের মূল অংশ হলো টেবিল। স্প্রেডশিটের মতোই, একটি টেবিল হলো কলাম এবং সারির একটি সংগ্রহ। সারি ডেটা বা তথ্য ধারণ করে, যেমন একটি শহরের নাম বা বৃষ্টিপাতের পরিমাণ। কলামগুলো সেই ডেটার বর্ণনা দেয় যা তারা সংরক্ষণ করে। চলুন আমাদের অনুসন্ধান শুরু করি একটি টেবিল তৈরি করে যেখানে শহরগুলোর তথ্য সংরক্ষণ করা হবে। আমরা তাদের নাম এবং দেশ দিয়ে শুরু করতে পারি। আপনি এটি একটি টেবিলে নিম্নরূপ সংরক্ষণ করতে পারেন: | শহর | দেশ | | -------- | ------------- | | টোকিও | জাপান | | আটলান্টা | যুক্তরাষ্ট্র | | অকল্যান্ড | নিউজিল্যান্ড | লক্ষ করুন **শহর**, **দেশ** এবং **জনসংখ্যা** কলামগুলো সংরক্ষিত ডেটার বর্ণনা দেয়, এবং প্রতিটি সারি একটি শহরের তথ্য ধারণ করে। ## একটি একক টেবিল পদ্ধতির সীমাবদ্ধতা সম্ভবত উপরের টেবিলটি আপনার কাছে বেশ পরিচিত মনে হচ্ছে। চলুন আমাদের ডেটাবেসে কিছু অতিরিক্ত তথ্য যোগ করি - বার্ষিক বৃষ্টিপাত (মিলিমিটারে)। আমরা ২০১৮, ২০১৯ এবং ২০২০ সালের দিকে মনোযোগ দেব। যদি আমরা টোকিওর জন্য এটি যোগ করি, এটি নিম্নরূপ হতে পারে: | শহর | দেশ | বছর | পরিমাণ | | ----- | ------- | ---- | ------ | | টোকিও | জাপান | ২০২০ | ১৬৯০ | | টোকিও | জাপান | ২০১৯ | ১৮৭৪ | | টোকিও | জাপান | ২০১৮ | ১৪৪৫ | আমাদের টেবিল সম্পর্কে আপনি কী লক্ষ্য করেন? আপনি লক্ষ্য করতে পারেন যে আমরা শহরের নাম এবং দেশ বারবার পুনরাবৃত্তি করছি। এটি অনেক বেশি স্টোরেজ নিতে পারে এবং এটি মূলত অপ্রয়োজনীয়। কারণ, টোকিওর জন্য আমরা শুধুমাত্র একটি নামের তথ্য চাই। ঠিক আছে, চলুন অন্য কিছু চেষ্টা করি। প্রতিটি বছরের জন্য নতুন কলাম যোগ করি: | শহর | দেশ | ২০১৮ | ২০১৯ | ২০২০ | | -------- | ------------- | ---- | ---- | ---- | | টোকিও | জাপান | ১৪৪৫ | ১৮৭৪ | ১৬৯০ | | আটলান্টা | যুক্তরাষ্ট্র | ১৭৭৯ | ১১১১ | ১৬৮৩ | | অকল্যান্ড | নিউজিল্যান্ড | ১৩৮৬ | ৯৪২ | ১১৭৬ | যদিও এটি সারির পুনরাবৃত্তি এড়ায়, এটি কয়েকটি অন্যান্য চ্যালেঞ্জ যোগ করে। প্রতিবার নতুন বছর যোগ করার সময় আমাদের টেবিলের কাঠামো পরিবর্তন করতে হবে। এছাড়াও, আমাদের ডেটা বাড়ার সাথে সাথে বছরের তথ্য কলাম হিসেবে রাখা আরও জটিল হয়ে উঠবে। এ কারণেই আমাদের একাধিক টেবিল এবং সম্পর্কের প্রয়োজন। ডেটা ভাগ করে আমরা পুনরাবৃত্তি এড়াতে পারি এবং ডেটার সাথে কাজ করার ক্ষেত্রে আরও নমনীয়তা পেতে পারি। ## সম্পর্কের ধারণা চলুন আমাদের ডেটায় ফিরে যাই এবং এটি কীভাবে ভাগ করা যায় তা নির্ধারণ করি। আমরা জানি যে আমরা শহরের নাম এবং দেশ সংরক্ষণ করতে চাই, তাই এটি সম্ভবত একটি টেবিলে ভালোভাবে কাজ করবে। | শহর | দেশ | | -------- | ------------- | | টোকিও | জাপান | | আটলান্টা | যুক্তরাষ্ট্র | | অকল্যান্ড | নিউজিল্যান্ড | কিন্তু পরবর্তী টেবিল তৈরি করার আগে, আমাদের প্রতিটি শহরকে কীভাবে রেফারেন্স করতে হবে তা নির্ধারণ করতে হবে। আমাদের একটি আইডেন্টিফায়ার, আইডি বা (প্রযুক্তিগত ডেটাবেস পরিভাষায়) একটি প্রাইমারি কী প্রয়োজন। একটি প্রাইমারি কী হলো একটি মান যা একটি টেবিলের একটি নির্দিষ্ট সারি চিহ্নিত করতে ব্যবহৃত হয়। যদিও এটি নিজেই একটি মানের উপর ভিত্তি করে হতে পারে (যেমন আমরা শহরের নাম ব্যবহার করতে পারি), এটি প্রায়শই একটি সংখ্যা বা অন্য কোনো আইডেন্টিফায়ার হওয়া উচিত। আমরা চাই না যে আইডি কখনও পরিবর্তিত হোক, কারণ এটি সম্পর্ক ভেঙে দেবে। বেশিরভাগ ক্ষেত্রে প্রাইমারি কী বা আইডি একটি স্বয়ংক্রিয়ভাবে তৈরি সংখ্যা হবে। > ✅ প্রাইমারি কী প্রায়ই সংক্ষেপে PK বলা হয় ### শহরসমূহ | city_id | শহর | দেশ | | ------- | -------- | ------------- | | 1 | টোকিও | জাপান | | 2 | আটলান্টা | যুক্তরাষ্ট্র | | 3 | অকল্যান্ড | নিউজিল্যান্ড | > ✅ আপনি লক্ষ্য করবেন যে আমরা এই পাঠে "id" এবং "প্রাইমারি কী" শব্দগুলো বিনিময়যোগ্যভাবে ব্যবহার করছি। এই ধারণাগুলো ডেটাফ্রেমের ক্ষেত্রেও প্রযোজ্য, যা আপনি পরে অন্বেষণ করবেন। ডেটাফ্রেমগুলো "প্রাইমারি কী" পরিভাষা ব্যবহার করে না, তবে আপনি লক্ষ্য করবেন যে তারা একইভাবে আচরণ করে। আমাদের শহর টেবিল তৈরি করার পর, চলুন বৃষ্টিপাত সংরক্ষণ করি। শহরের সম্পূর্ণ তথ্য পুনরাবৃত্তি করার পরিবর্তে, আমরা আইডি ব্যবহার করতে পারি। আমরা নিশ্চিত করতে পারি যে নতুন তৈরি টেবিলেও একটি *id* কলাম রয়েছে, কারণ সব টেবিলে একটি id বা প্রাইমারি কী থাকা উচিত। ### বৃষ্টিপাত | rainfall_id | city_id | বছর | পরিমাণ | | ----------- | ------- | ---- | ------ | | 1 | 1 | ২০১৮ | ১৪৪৫ | | 2 | 1 | ২০১৯ | ১৮৭৪ | | 3 | 1 | ২০২০ | ১৬৯০ | | 4 | 2 | ২০১৮ | ১৭৭৯ | | 5 | 2 | ২০১৯ | ১১১১ | | 6 | 2 | ২০২০ | ১৬৮৩ | | 7 | 3 | ২০১৮ | ১৩৮৬ | | 8 | 3 | ২০১৯ | ৯৪২ | | 9 | 3 | ২০২০ | ১১৭৬ | লক্ষ করুন **city_id** কলামটি নতুন তৈরি **rainfall** টেবিলের মধ্যে রয়েছে। এই কলামটি **cities** টেবিলের আইডিগুলোকে রেফারেন্স করে। প্রযুক্তিগত রিলেশনাল ডেটা পরিভাষায়, এটি একটি **ফরেন কী** বলা হয়; এটি অন্য একটি টেবিলের প্রাইমারি কী। আপনি এটিকে একটি রেফারেন্স বা পয়েন্টার হিসেবে ভাবতে পারেন। **city_id** 1 টোকিওকে রেফারেন্স করে। > [!NOTE] ফরেন কী প্রায়ই সংক্ষেপে FK বলা হয় ## ডেটা পুনরুদ্ধার করা আমাদের ডেটা দুটি টেবিলে ভাগ করার পর, আপনি হয়তো ভাবছেন কীভাবে এটি পুনরুদ্ধার করা যায়। যদি আমরা MySQL, SQL Server বা Oracle-এর মতো একটি রিলেশনাল ডেটাবেস ব্যবহার করি, আমরা একটি ভাষা ব্যবহার করতে পারি যার নাম Structured Query Language বা SQL। SQL (কখনও কখনও সিকুয়েল উচ্চারণ করা হয়) একটি স্ট্যান্ডার্ড ভাষা যা রিলেশনাল ডেটাবেসে ডেটা পুনরুদ্ধার এবং পরিবর্তন করতে ব্যবহৃত হয়। ডেটা পুনরুদ্ধার করতে আপনি `SELECT` কমান্ড ব্যবহার করেন। এর মূল অংশ হলো, আপনি যে কলামগুলো দেখতে চান তা **select** করেন এবং সেগুলো যে টেবিলে রয়েছে তা **from** করেন। যদি আপনি শুধুমাত্র শহরের নামগুলো প্রদর্শন করতে চান, আপনি নিম্নলিখিতটি ব্যবহার করতে পারেন: ```sql SELECT city FROM cities; -- Output: -- Tokyo -- Atlanta -- Auckland ``` `SELECT` হলো যেখানে আপনি কলামগুলো তালিকাভুক্ত করেন, এবং `FROM` হলো যেখানে আপনি টেবিলগুলো তালিকাভুক্ত করেন। > [NOTE] SQL সিনট্যাক্স কেস-ইনসেনসিটিভ, অর্থাৎ `select` এবং `SELECT` একই জিনিস। তবে, আপনি যে ডেটাবেস ব্যবহার করছেন তার উপর নির্ভর করে কলাম এবং টেবিলগুলো কেস-সেনসিটিভ হতে পারে। ফলস্বরূপ, প্রোগ্রামিংয়ে সবকিছু কেস-সেনসিটিভ হিসেবে বিবেচনা করা সর্বদা একটি ভালো অভ্যাস। SQL কোয়েরি লেখার সময় সাধারণত কীওয়ার্ডগুলো সব বড় অক্ষরে লেখা হয়। উপরের কোয়েরি সব শহর প্রদর্শন করবে। চলুন কল্পনা করি আমরা শুধুমাত্র নিউজিল্যান্ডের শহরগুলো প্রদর্শন করতে চাই। আমাদের একটি ফিল্টার দরকার। SQL-এর জন্য এই কীওয়ার্ড হলো `WHERE`, বা "যেখানে কিছু সত্য"। ```sql SELECT city FROM cities WHERE country = 'New Zealand'; -- Output: -- Auckland ``` ## ডেটা যোগ করা এখন পর্যন্ত আমরা একটি একক টেবিল থেকে ডেটা পুনরুদ্ধার করেছি। এখন আমরা **cities** এবং **rainfall** উভয় টেবিলের ডেটা একত্রিত করতে চাই। এটি *joining* এর মাধ্যমে করা হয়। আপনি কার্যত দুটি টেবিলের মধ্যে একটি সিম তৈরি করবেন এবং প্রতিটি টেবিলের একটি কলামের মানগুলো মিলিয়ে দেবেন। আমাদের উদাহরণে, আমরা **rainfall** টেবিলের **city_id** কলামকে **cities** টেবিলের **city_id** কলামের সাথে মিলাব। এটি বৃষ্টিপাতের মানকে তার সংশ্লিষ্ট শহরের সাথে মিলাবে। আমরা যে ধরনের যোগ করব তা হলো *inner* join, অর্থাৎ যদি কোনো সারি অন্য টেবিলের কিছু সঙ্গে মেলে না, তবে তা প্রদর্শিত হবে না। আমাদের ক্ষেত্রে প্রতিটি শহরের বৃষ্টিপাত রয়েছে, তাই সবকিছু প্রদর্শিত হবে। চলুন ২০১৯ সালের জন্য আমাদের সব শহরের বৃষ্টিপাত পুনরুদ্ধার করি। আমরা এটি ধাপে ধাপে করব। প্রথম ধাপ হলো ডেটা একত্রিত করা, যেখানে আমরা সিমের জন্য কলামগুলো নির্দেশ করব - **city_id** যেমন আগে হাইলাইট করা হয়েছে। ```sql SELECT cities.city rainfall.amount FROM cities INNER JOIN rainfall ON cities.city_id = rainfall.city_id ``` আমরা দুটি কলাম হাইলাইট করেছি এবং টেবিলগুলোকে **city_id** দ্বারা একত্রিত করতে চাই তা উল্লেখ করেছি। এখন আমরা `WHERE` স্টেটমেন্ট যোগ করতে পারি যাতে শুধুমাত্র ২০১৯ সালের বছরটি ফিল্টার করা যায়। ```sql SELECT cities.city rainfall.amount FROM cities INNER JOIN rainfall ON cities.city_id = rainfall.city_id WHERE rainfall.year = 2019 -- Output -- city | amount -- -------- | ------ -- Tokyo | 1874 -- Atlanta | 1111 -- Auckland | 942 ``` ## সারসংক্ষেপ রিলেশনাল ডেটাবেসের মূল ধারণা হলো তথ্যকে একাধিক টেবিলে ভাগ করা, যা পরে প্রদর্শন এবং বিশ্লেষণের জন্য একত্রিত করা হয়। এটি গণনা এবং ডেটা পরিচালনার ক্ষেত্রে উচ্চ মাত্রার নমনীয়তা প্রদান করে। আপনি একটি রিলেশনাল ডেটাবেসের মূল ধারণাগুলো এবং দুটি টেবিলের মধ্যে যোগ করার পদ্ধতি দেখেছেন। ## 🚀 চ্যালেঞ্জ ইন্টারনেটে অসংখ্য রিলেশনাল ডেটাবেস উপলব্ধ রয়েছে। আপনি উপরের শেখা দক্ষতাগুলো ব্যবহার করে ডেটা অন্বেষণ করতে পারেন। ## পোস্ট-লেকচার কুইজ ## [পোস্ট-লেকচার কুইজ](https://purple-hill-04aebfb03.1.azurestaticapps.net/quiz/9) ## পর্যালোচনা ও স্ব-অধ্যয়ন SQL এবং রিলেশনাল ডেটাবেস ধারণাগুলো অন্বেষণ চালিয়ে যাওয়ার জন্য [Microsoft Learn](https://docs.microsoft.com/learn?WT.mc_id=academic-77958-bethanycheum)-এ বেশ কয়েকটি রিসোর্স উপলব্ধ রয়েছে: - [রিলেশনাল ডেটার ধারণাগুলো বর্ণনা করুন](https://docs.microsoft.com//learn/modules/describe-concepts-of-relational-data?WT.mc_id=academic-77958-bethanycheum) - [Transact-SQL দিয়ে কোয়েরি শুরু করুন](https://docs.microsoft.com//learn/paths/get-started-querying-with-transact-sql?WT.mc_id=academic-77958-bethanycheum) (Transact-SQL হলো SQL-এর একটি সংস্করণ) - [Microsoft Learn-এ SQL বিষয়বস্তু](https://docs.microsoft.com/learn/browse/?products=azure-sql-database%2Csql-server&expanded=azure&WT.mc_id=academic-77958-bethanycheum) ## অ্যাসাইনমেন্ট [অ্যাসাইনমেন্ট শিরোনাম](assignment.md) --- **অস্বীকৃতি**: এই নথিটি AI অনুবাদ পরিষেবা [Co-op Translator](https://github.com/Azure/co-op-translator) ব্যবহার করে অনুবাদ করা হয়েছে। আমরা যথাসম্ভব সঠিক অনুবাদের চেষ্টা করি, তবে অনুগ্রহ করে মনে রাখবেন যে স্বয়ংক্রিয় অনুবাদে ত্রুটি বা অসঙ্গতি থাকতে পারে। নথিটির মূল ভাষায় লেখা সংস্করণটিকেই প্রামাণিক উৎস হিসেবে বিবেচনা করা উচিত। গুরুত্বপূর্ণ তথ্যের জন্য, পেশাদার মানব অনুবাদ ব্যবহার করার পরামর্শ দেওয়া হচ্ছে। এই অনুবাদ ব্যবহারের ফলে সৃষ্ট কোনো ভুল বোঝাবুঝি বা ভুল ব্যাখ্যার জন্য আমরা দায়ী নই।