এই পর্বে যা শিখবেন
- Relational model-এর ছয়টি মূল শব্দ, আর টেবিলের সঙ্গে তাদের মিল
- Relation schema আর relation instance-এর পার্থক্য, আর গাণিতিক সংজ্ঞা (Cartesian product-এর subset)
- Relation-এর চারটি বৈশিষ্ট্য, আর SQL টেবিল কোথায় সেগুলো মানে না
- NULL-এর তিন রকম অর্থ, আর NULL নিয়ে তুলনার ফাঁদ
- Database schema-র ছবি পড়া, আর Codd-এর ১২ নিয়মের সৎ মূল্যায়ন
১ · Codd-এর ধারণা — ডেটাকে শুধু টেবিল হিসেবে দেখা
আগের পর্বে (পর্ব ০৪) দেখেছেন, ১৯৬০-এর দশকের ডেটাবেসগুলো ছিল hierarchical বা network ধরনের। সেখানে ডেটা খুঁজতে প্রোগ্রামারকে রেকর্ড থেকে রেকর্ডে “হাঁটতে” হতো — আগে এই অফিসের রেকর্ড, তারপর তার নিচের কর্মচারী, তারপর তার বেতনের রেকর্ড। ডেটা কোন পথে সাজানো আছে, সেটা প্রোগ্রামের ভেতরেই লেখা থাকত। সাজানোর পথ বদলালে প্রোগ্রামও নতুন করে লিখতে হতো।
IBM-এর গবেষক Edgar F. Codd (সবাই ডাকতেন Ted) এই সমস্যার একটি সরল আর সাহসী সমাধান দিলেন। তাঁর মূল কথা তিনটি:
- সব ডেটা একই রূপে রাখুন — টেবিলে। কোনো লুকানো pointer নেই, কোনো “পথ” নেই। দুটি টেবিলের সম্পর্ক বোঝানো হয় শুধু মান দিয়ে — যেমন
students-এরdept_idকলামে 1 লেখা মানে CSE বিভাগ। - প্রশ্ন করুন “কী চাই” বলে। “২০২১ ব্যাচের CSE শিক্ষার্থীদের নাম চাই” — কীভাবে খুঁজবে, সেই সিদ্ধান্ত DBMS নেবে।
- ভিত্তি হোক গণিত। Set theory আর logic-এর ওপর দাঁড়ানো বলে প্রতিটি কোয়েরির অর্থ নিখুঁতভাবে বলা যায়, আর একটি কোয়েরিকে অন্য সমান কোয়েরিতে বদলে দ্রুত চালানো যায়।
বিশ্ববিদ্যালয়ের রেজিস্টার অফিসের পুরোনো খাতার কথা ভাবুন। একটি খাতায় শিক্ষার্থীদের তালিকা, আরেকটিতে বিভাগের তালিকা। শিক্ষার্থীর পাতায় বিভাগের পুরো ঠিকানা লেখা থাকে না — শুধু বিভাগের কোড লেখা থাকে। দরকার হলে কোড মিলিয়ে অন্য খাতা থেকে বিভাগ খুঁজে নেন। Codd ঠিক এই সহজ ব্যবস্থাটিকেই গণিতের ভাষায় নিখুঁত করেছিলেন। কেরানি জানেন কী খুঁজছেন; কোন তাক থেকে কোন খাতা আগে নামাবেন, সেটা অভিজ্ঞ কেরানির (DBMS-এর) কাজ।
Relational model হলো ডেটা সাজানোর একটি গাণিতিক মডেল। এতে ডেটা থাকে relation (টেবিল) আকারে। Relation-গুলোর মধ্যে সম্পর্ক বোঝানো হয় মান মিলিয়ে, pointer দিয়ে নয়। এই মডেল মেনে চলা DBMS-কে বলে RDBMS — যেমন PostgreSQL, MySQL, SQLite, Oracle, SQL Server. আর এদের সঙ্গে কথা বলার ভাষা SQL.
১৯৭০ সালের জুনে Communications of the ACM পত্রিকায় Codd-এর প্রবন্ধ “A Relational Model of Data for Large Shared Data Banks” প্রকাশিত হয়। তিনি তখন ক্যালিফোর্নিয়ার IBM San Jose Research Laboratory-তে কাজ করতেন। IBM-এর তখন নিজের সফল hierarchical ডেটাবেস IMS ছিল, তাই নতুন ধারণাটি কোম্পানির ভেতরে শুরুতে খুব একটা উৎসাহ পায়নি বলে প্রচলিত আছে। তবু ১৯৭০-এর দশকে IBM-এর System R আর UC Berkeley-র Ingres প্রজেক্ট দেখাল, ধারণাটি বাস্তবেও দ্রুত চালানো যায়। System R-এর জন্যই তৈরি হয় SEQUEL ভাষা, যা পরে নাম বদলে SQL হয়। এই কাজের স্বীকৃতিতে Codd ১৯৮১ সালে কম্পিউটার বিজ্ঞানের সর্বোচ্চ সম্মান Turing Award পান।
২ · ছয়টি শব্দ — relation, tuple, attribute, domain, degree, cardinality
Relational model-এর নিজস্ব কিছু শব্দ আছে। বইয়ে, বিশ্ববিদ্যালয়ের প্রশ্নে আর চাকরির পরীক্ষায় এই শব্দগুলোই আসে। অথচ প্রতিটির একটি সহজ, চেনা প্রতিশব্দ আছে:
| তাত্ত্বিক শব্দ | SQL / দৈনন্দিন শব্দ | ফাইলের যুগের শব্দ | students-এ উদাহরণ |
|---|---|---|---|
| Relation | Table (টেবিল) | File | students টেবিল |
| Tuple | Row (সারি) | Record | Arif Hossain-এর সারি |
| Attribute | Column (কলাম) | Field | cgpa |
| Domain | কলামের বৈধ মানের সেট (প্রায় data type + নিয়ম) | — | 0 থেকে 4 পর্যন্ত সংখ্যা |
| Degree (arity) | কলামের সংখ্যা | — | 5 |
| Cardinality | সারির সংখ্যা | — | 8 |
এই পর্বের বেশিরভাগ উদাহরণ চলবে বিশ্ববিদ্যালয়ের নমুনা ডেটাবেস db-uni-এর students টেবিলে। এর পাঁচটি কলাম: student_id (রোল নম্বরের মতো পরিচয় নম্বর), name (নাম), dept_id (বিভাগের নম্বর — departments টেবিলের দিকে নির্দেশ করে), batch (ভর্তির বছর) আর cgpa. নিচের ডায়াগ্রামে ছয়টি শব্দ একে একে টেবিলের গায়ে বসিয়ে দেখুন:
| শব্দ | |
| SQL-এ যাকে বলে | |
| মান |
- Relation. পুরো টেবিলটিই একটি relation. এর একটি নাম আছে (STUDENT), আর এটি একই রকম তথ্যের একটি সংগ্রহ — প্রতিটি সারি একজন শিক্ষার্থীর কথা বলে।
- Tuple. একটি সারি = একটি tuple.
(2101, Arif Hossain, 1, 2021, 3.75)— একজন শিক্ষার্থী সম্পর্কে একটি পূর্ণ তথ্য। “tuple” শব্দটি এসেছে গণিতের pair, triple, quadruple … n-tuple থেকে। - Attribute. একটি কলাম = একটি attribute. প্রতিটি attribute-এর একটি নাম আছে (
cgpa), আর প্রতিটি tuple-এ সেই নামে একটি করে মান থাকে। - Domain.
cgpa-র domain হলো সেই মানগুলোর সেট, যা এই কলামে বসতে পারে — এখানে 0.00 থেকে 4.00. 4.5 বা “ভালো” এই domain-এর বাইরে। খেয়াল করুন, Fahim Karim-এর ঘরে কোনো মানই নেই — NULL. NULL কোনো domain-এর সদস্য নয়; এ নিয়ে অংশ ৭-এ বিস্তারিত। - Degree. কলাম গুনুন: student_id, name, dept_id, batch, cgpa — পাঁচটি। তাই এই relation-এর degree (বা arity) 5. Degree 1 হলে unary, 2 হলে binary relation বলে।
- Cardinality. সারি গুনুন — আটটি। তাই এখন cardinality 8. Degree সাধারণত বছরের পর বছর একই থাকে, কিন্তু cardinality প্রতিটি ভর্তি বা বাদ পড়ার সঙ্গে বদলায়।
এবার একই দুটি সংখ্যা SQL দিয়ে বের করি। নিচের এডিটরটি এই পাতাতেই আসল SQLite চালায়। “চালান” চাপুন; চাইলে কোড বদলে আবার চালান।
-- cardinality: কয়টি tuple (সারি)?
SELECT COUNT(*) AS cardinality FROM students;
-- degree: কয়টি attribute (কলাম)? — SQLite-এর catalog থেকে
SELECT COUNT(*) AS degree FROM pragma_table_info('students');
-- attribute-গুলোর নাম আর ঘোষিত টাইপ
SELECT name, type FROM pragma_table_info('students');প্রথম কোয়েরি দেয় cardinality = 8, দ্বিতীয়টি degree = 5. তৃতীয়টি পাঁচটি সারি দেখায়: student_id INTEGER, name TEXT, dept_id INTEGER, batch INTEGER, cgpa REAL. COUNT(*) সারি গোনে — এটি সব ডেটাবেসে একই। কিন্তু কলাম গোনার জন্য টেবিলের “বিবরণ” পড়তে হয়, আর সেটা প্রতিটি সিস্টেমে আলাদা। pragma_table_info শুধু SQLite-এর জিনিস।
PostgreSQL, MySQL বা SQL Server-এ একই কাজ হয় SQL স্ট্যান্ডার্ডের information_schema দিয়ে। এটি এই পাতায় চলবে না, শুধু চিনে রাখুন:
-- degree: students টেবিলের কলাম সংখ্যা
SELECT COUNT(*) AS degree
FROM information_schema.columns
WHERE table_name = 'students';Domain আর data type এক নয়। REAL একটি data type — এতে −৫ বা ১০০০-ও রাখা যায়। Domain আরও সরু: “০ থেকে ৪-এর মধ্যে বাস্তব সংখ্যা।” SQL-এ domain বোঝাতে data type-এর সঙ্গে CHECK নিয়ম জুড়ে দিতে হয় — db-uni-তে ঠিক তাই আছে: cgpa REAL CHECK (cgpa BETWEEN 0 AND 4). PostgreSQL-এ CREATE DOMAIN দিয়ে নাম দেওয়া domain-ও বানানো যায়। Constraint নিয়ে বিস্তারিত পর্ব ১৩-তে।
৩ · Relation schema বনাম relation instance
একটি টেবিলের দুটি দিক আছে — তার কাঠামো আর তার ভেতরের ডেটা। কাঠামোকে বলে relation schema; লেখা হয় relation-এর নাম আর attribute-গুলোর তালিকা দিয়ে:
আরও নিখুঁতভাবে লিখলে প্রতিটি attribute-এর domain-ও বলে দেওয়া হয়: STUDENT(student_id: INTEGER, name: TEXT, dept_id: INTEGER, batch: INTEGER, cgpa: REAL). সাধারণ সংকেতে একটি schema লেখা হয় R(A1, A2, …, An) — এখানে R নাম, Ai attribute, আর n হলো degree. Primary key-র নিচে সাধারণত দাগ টানা হয় (student_id) — key নিয়ে পরের পর্বে।
আর কোনো এক মুহূর্তে টেবিলে যে tuple-গুলো আছে, তাদের সেটকে বলে relation instance (বা relation state); লেখা হয় r(R). আজ সকালের students টেবিলে আটজন — এটি একটি instance. দুপুরে একজন নতুন শিক্ষার্থী ভর্তি হলে নতুন instance তৈরি হলো, কিন্তু schema একই রইল।
বোর্ড পরীক্ষার ফলাফলের ছাপানো ফর্মের কথা ভাবুন। ফর্মের ঘরগুলো — রোল, নাম, GPA — হলো schema; সারা দেশে এক। প্রতিটি স্কুলের পূরণ করা ফর্মগুলো হলো instance. ফর্মের নকশা বদলায় কালেভদ্রে, কিন্তু পূরণ করা কাগজ প্রতি বছর নতুন।
নিজে দেখুন: নতুন একটি tuple ঢোকালে cardinality বদলায়, degree বদলায় না।
-- নতুন শিক্ষার্থী ভর্তি: instance বদলাল
INSERT INTO students VALUES (2401, 'Ishrat Jahan', 1, 2024, 3.65);
SELECT COUNT(*) AS cardinality FROM students;
SELECT COUNT(*) AS degree FROM pragma_table_info('students');INSERT-এর পর আসে “১টি সারি বদলেছে”। তারপর cardinality = 9 (আগে ছিল 8), কিন্তু degree = 5 — আগের মতোই। Schema বদলাতে হলে ALTER TABLE লাগে (পর্ব ২৩)। প্রতিবার “চালান” চাপলে ডেটাবেস নতুন করে তৈরি হয়, তাই যতবার চালান, ফল 9-ই আসবে।
| বিষয় | Relation schema | Relation instance |
|---|---|---|
| কী বোঝায় | কাঠামো: নাম, attribute, domain, নিয়ম | এই মুহূর্তের tuple-গুলোর সেট |
| কত ঘন ঘন বদলায় | কালেভদ্রে (নতুন কলাম, নতুন নিয়ম) | প্রতিটি INSERT, UPDATE, DELETE-এ |
| সংকেত | R(A1, …, An) | r(R) = {t1, …, tm} |
| SQL-এ | CREATE TABLE, ALTER TABLE | INSERT, UPDATE, DELETE |
| গোনার সংখ্যা | degree | cardinality |
পর্ব ০৩-এর three-schema architecture-এর সঙ্গে এর মিল লক্ষ করুন: schema হলো “intension” (কী রকম ডেটা থাকতে পারে), instance হলো “extension” (এই মুহূর্তে আসলে কী আছে)। পুরোনো বইয়ে এই দুটি শব্দও পাবেন।
৪ · গাণিতিক সংজ্ঞা — Cartesian product-এর একটি subset
“Relation” শব্দটি Codd গণিত থেকে নিয়েছিলেন। স্কুলের গণিতে হয়তো পড়েছেন — দুটি set A আর B-র Cartesian product A × B হলো সব সম্ভাব্য জোড়া (a, b)-এর set, আর A × B-এর যেকোনো subset-ই A থেকে B-তে একটি relation. Codd এই ধারণাকে দুটি থেকে n-টি set-এ বাড়িয়ে দিলেন।
ধরুন D1, D2, …, Dn কয়েকটি domain. তাদের Cartesian product
D1 × D2 × … × Dn = { (d1, d2, …, dn) : প্রতিটি di ∈ Di }
এই domain-গুলোর ওপর একটি relation r হলো এই product-এর যেকোনো একটি subset: r ⊆ D1 × D2 × … × Dn. Relation-এর প্রতিটি সদস্যই একটি n-tuple.
অর্থাৎ Cartesian product হলো “সম্ভাব্য সব কথা”, আর relation হলো তার মধ্যে “যে কথাগুলো এই মুহূর্তে সত্য”। (2101, CSE) মানে “2101 নম্বর শিক্ষার্থী CSE-তে পড়েন” — একটি দাবি। টেবিলে tuple-টি থাকা মানে দাবিটি সত্য। একটি ছোট উদাহরণ ধাপে ধাপে দেখুন:
| সেট | |
| tuple-এর সংখ্যা | |
| relation কি? |
- দুটি domain. D1 = {2101, 2102} — দুজন শিক্ষার্থীর id. D2 = {CSE, EEE} — দুটি বিভাগ। প্রতিটির আকার ২।
- Cartesian product. প্রতিটি id-কে প্রতিটি বিভাগের সঙ্গে জোড়া দিলে ২ × ২ = ৪টি tuple. এটি সব সম্ভাব্য জোড়া — বাস্তবে সত্য হোক বা না হোক। সাধারণভাবে |D1 × D2 × … × Dn| = |D1| × |D2| × … × |Dn|.
- r1 — একটি relation. বাস্তবে 2101 CSE-তে, 2102 EEE-তে। এই দুটি tuple বেছে নিলাম: r1 = {(2101, CSE), (2102, EEE)}. r1 হলো product-এর একটি subset, তাই সংজ্ঞা অনুযায়ী এটি একটি relation.
- r2 — এটিও relation, কিন্তু অর্থহীন। r2 = {(2101, CSE), (2101, EEE)}-ও একটি subset, তাই গাণিতিকভাবে relation. কিন্তু একজন শিক্ষার্থী একসঙ্গে দুই বিভাগে — বাস্তব নিয়মে এটি চলে না। এমন অবস্থা আটকাতেই আসে key আর integrity constraint (পর্ব ০৬)।
- কতগুলো relation সম্ভব? ৪টি tuple-এর প্রতিটি থাকতে পারে বা না-ও থাকতে পারে, তাই subset-এর সংখ্যা 24 = ১৬ — খালি set ∅ আর পুরো product-সহ। “প্রতিটি id সর্বোচ্চ একবার” নিয়ম মানলে প্রতিটি id-এর জন্য তিনটি পথ (নেই / CSE / EEE), তাই ৩ × ৩ = ৯টি বৈধ instance থাকে। Constraint মানে সম্ভাব্য instance-এর সংখ্যা কমিয়ে আনা।
ধাপ ৫-এর হিসাবটি একটি সাধারণ সত্যের বিশেষ রূপ। প্রমাণটি ছোট:
দাবি: domain D1, …, Dn সসীম হলে তাদের ওপর মোট 2Nটি আলাদা relation সম্ভব, যেখানে N = |D1| × … × |Dn|.
প্রমাণ: Relation মানে product P = D1 × … × Dn-এর একটি subset. P-তে ঠিক N-টি tuple আছে (প্রতিটি অবস্থানে |Di|-টি পছন্দ, গুণনের নিয়মে)। একটি subset বানাতে প্রতিটি tuple-এর জন্য দুটি সিদ্ধান্তের একটি নিতে হয় — “রাখব” বা “রাখব না”। N-টি স্বাধীন দুই-পথের সিদ্ধান্ত, তাই মোট 2 × 2 × … × 2 = 2Nটি subset. আলাদা সিদ্ধান্ত মানে আলাদা subset, তাই প্রতিটি গোনা একবারই। ∎
সংখ্যাটি কত দ্রুত বাড়ে, দেখুন: মাত্র ১০টি id আর ৪টি বিভাগ হলে N = ৪০, আর সম্ভাব্য relation 240 — এক লক্ষ কোটিরও বেশি। ডেটাবেস ডিজাইনের কাজ হলো এই বিশাল সম্ভাবনার মধ্য থেকে শুধু অর্থবহগুলোকে অনুমতি দেওয়া।
SQL-এ Cartesian product বানায় CROSS JOIN (পর্ব ২০-এ বিস্তারিত)। নিচের এডিটরে দুটি ছোট “domain টেবিল” আগে থেকেই বানানো আছে — d_id (কলাম student_id) আর d_dept (কলাম dept).
-- D1 × D2: সম্ভাব্য সব tuple
SELECT student_id, dept
FROM d_id CROSS JOIN d_dept
ORDER BY student_id, dept;
-- একটি relation = এর একটি subset (r1)
SELECT student_id, dept
FROM d_id CROSS JOIN d_dept
WHERE (student_id = 2101 AND dept = 'CSE')
OR (student_id = 2102 AND dept = 'EEE');প্রথম কোয়েরি ৪টি সারি দেয়: (2101, CSE), (2101, EEE), (2102, CSE), (2102, EEE) — ঠিক স্টেপারের ধাপ ২. দ্বিতীয়টি WHERE দিয়ে product থেকে দুটি সারি বেছে নেয়: (2101, CSE) আর (2102, EEE) — এটাই r1. Relational algebra-তে এই “product, তারপর বাছাই” জুটিই join-এর ভিত্তি (পর্ব ৩২–৩৩)।
Tuple-কে ক্রমের বদলে নাম দিয়ে দেখা
গণিতের সংজ্ঞায় tuple-এর মানগুলো অবস্থান দিয়ে চেনা হয় — প্রথম মান D1 থেকে, দ্বিতীয়টি D2 থেকে। কিন্তু ডেটাবেসে আমরা কলামকে নাম দিয়ে ডাকি। তাই বেশিরভাগ পাঠ্যবই একটি দ্বিতীয় সংজ্ঞাও দেয়: tuple হলো একটি ফাংশন, যা প্রতিটি attribute-নামকে তার domain-এর একটি মানে নিয়ে যায় — t(name) = 'Arif Hossain', t(cgpa) = 3.75. এই দৃষ্টিতে attribute-এর কোনো ক্রম থাকে না; {name ↦ Arif, cgpa ↦ 3.75} আর {cgpa ↦ 3.75, name ↦ Arif} একই tuple. সংকেতে t[cgpa] বা t.cgpa লেখা হয়। পরের অংশের একটি বৈশিষ্ট্য ঠিক এখান থেকেই আসে।
৫ · Relation-এর চারটি বৈশিষ্ট্য
Relation যেহেতু একটি set, তাই set-এর নিয়ম থেকেই কয়েকটি বৈশিষ্ট্য সরাসরি আসে। পরীক্ষায় এগুলো প্রায়ই জিজ্ঞেস করা হয়:
১. কোনো duplicate tuple নেই
Set-এ একই সদস্য দুবার থাকে না: {a, a, b} = {a, b}. তাই একই tuple দুবার রাখলে আসলে কিছুই যোগ হয় না।
set-এর সংজ্ঞা থেকে২. Tuple-এর কোনো ক্রম নেই
{a, b} আর {b, a} একই set. কোন সারি আগে দেখাবে, সেটা relation-এর অংশ নয় — ক্রম চাইলে কোয়েরিতে বলতে হয়।
set-এর সংজ্ঞা থেকে৩. Attribute-এর ক্রম নেই
Attribute চেনা হয় নাম দিয়ে, অবস্থান দিয়ে নয় (tuple = নাম থেকে মানের ফাংশন)। কলাম সাজানোর ক্রম শুধু দেখানোর সুবিধা।
নামভিত্তিক সংজ্ঞা থেকে৪. প্রতিটি মান atomic
প্রতিটি ঘরে domain থেকে একটিমাত্র অবিভাজ্য মান — তালিকা বা নিজস্ব ছোট টেবিল নয়। এটিই first normal form.
Codd-এর নকশার সিদ্ধান্তচতুর্থটি অন্য তিনটির মতো set theory থেকে আপনাআপনি আসে না — এটি Codd-এর সচেতন নকশা। ঘরে একাধিক মান রাখলে কোয়েরির ভাষা জটিল হয়ে যায়, তাই তিনি বললেন প্রতিটি মান হবে atomic. এই শর্ত মানা relation-কে বলা হয় first normal form (1NF)-এ আছে। Normalization-এর পুরো গল্প পর্ব ৩৬-এ; এখানে শুধু মূল ছবিটি দেখুন:
| কোন বৈশিষ্ট্য | |
| relation হিসেবে | |
| SQL টেবিলে |
- মূল relation. তিনটি tuple — Arif, Bristy আর Dilruba. প্রতিটির তিনটি attribute: student_id, name, batch. এটিকে তুলনার মাপকাঠি ধরি।
- সারির ক্রম বদলালাম। Dilruba-কে ওপরে আনলাম। Set হিসেবে {t1, t2, t3} আর {t3, t1, t2} একই, তাই relation একই। SQL-ও তা-ই মানে:
ORDER BYনা দিলে সারি যেকোনো ক্রমে আসতে পারে। - কলামের ক্রম বদলালাম — নামসহ। প্রতিটি মান তার attribute-এর নাম সঙ্গে নিয়ে সরেছে, তাই প্রতিটি tuple-এর তথ্য অপরিবর্তিত। নামহীনভাবে শুধু অবস্থান বদলালে (যেমন name-এর মানগুলো batch কলামে চলে গেলে) সেটা হতো অন্য relation.
- Bristy-র সারি দুবার। Set-এ {t1, t2, t3, t2} = {t1, t2, t3} — relation-এ এখনো তিনটি tuple. কিন্তু SQL টেবিলে key না থাকলে সত্যিই চারটি সারি জমা হয়, আর
COUNT(*)বলবে 4. এই পার্থক্যই পরের অংশের বিষয়। - একটি ঘরে দুটি ফোন নম্বর। “01711000001, 01811000002” একটি তালিকা, atomic মান নয় — 1NF ভাঙে। “018 দিয়ে শুরু নম্বর কার?” খুঁজতে তখন string কেটে দেখতে হবে। ঠিক উপায়: প্রতিটি নম্বর আলাদা tuple-এ, সম্ভব হলে আলাদা টেবিলে (student_id, phone).
“Atomic” মানে “আর ভাঙা যায় না” নয়। একটি নাম ভাঙা যায় অক্ষরে, একটি তারিখ ভাঙা যায় বছর-মাস-দিনে। আসল প্রশ্ন হলো: আপনার কোয়েরিগুলো কি মানটিকে একটি একক হিসেবে ব্যবহার করে? যদি নিয়মিত তারিখের শুধু মাস দিয়ে খুঁজতে হয়, বা ঠিকানার শুধু জেলা দিয়ে, তাহলে সেটিকে আলাদা কলামে রাখার কথা ভাবুন। এই বিতর্ক নিয়ে নিচের ভাবনার প্রশ্ন ৫ দেখুন।
৬ · SQL টেবিল কোথায় বিশুদ্ধ relation নয় — bag semantics
এখন একটি গুরুত্বপূর্ণ সত্য, যা অনেক বইয়ে চাপা পড়ে যায়: SQL-এর টেবিল আসলে relation নয়। তিনটি জায়গায় SQL গণিতের নিয়ম থেকে সরে এসেছে:
| বিষয় | বিশুদ্ধ relation | SQL টেবিল / কোয়েরির ফল |
|---|---|---|
| Duplicate সারি | অসম্ভব (set) | সম্ভব — টেবিলে key না থাকলে, আর কোয়েরির ফলে প্রায় সবসময় (bag / multiset) |
| কলামের ক্রম | নেই | আছে — SELECT * আর INSERT ... VALUES ঘোষণার ক্রম মেনে চলে |
| সারির ক্রম | নেই | নেই — ORDER BY না দিলে নিশ্চয়তা নেই (এখানে SQL তত্ত্ব মানে) |
| মান না থাকা | মূল মডেলে ছিল না | NULL আছে, আর তার জন্য তিন-মানের যুক্তি |
| নামহীন বা একই নামের কলাম | অসম্ভব | সম্ভব — যেমন SELECT 1, 1 বা দুটি টেবিলের name একসঙ্গে |
যে সংগ্রহে একই সদস্য একাধিকবার থাকতে পারে, গণিতে তাকে বলে multiset বা bag. SQL-এর এই আচরণকে তাই বলে bag semantics. প্রথমে কোয়েরির ফলে দেখুন:
-- bag: প্রতিটি শিক্ষার্থীর জন্য একটি করে সারি
SELECT batch FROM students;
-- set: duplicate বাদ
SELECT DISTINCT batch FROM students;প্রথম কোয়েরি ৮টি সারি দেয়: 2021 তিনবার, 2022 তিনবার, 2023 দুবার। শুধু একটি কলাম রাখলে অনেক সারি দেখতে একই হয়ে যায়, কিন্তু SQL সেগুলো মুছে দেয় না। দ্বিতীয়টিতে DISTINCT duplicate বাদ দিয়ে ৩টি সারি দেয় — 2021, 2022, 2023. Relational algebra-র projection (π) সবসময় দ্বিতীয় ফলটি দেয় (পর্ব ৩২)। মনে রাখুন: SQL-এ set চাইলে নিজে DISTINCT লিখতে হয়।
শুধু কোয়েরির ফল নয়, টেবিলেও duplicate জমতে পারে — যদি টেবিলে কোনো key না থাকে। ধরুন হাজিরা রাখার একটি টেবিল attendance; এর দুটি কলাম student_id আর day, কোনো key নেই:
CREATE TABLE attendance (student_id INTEGER, day TEXT);
-- ভুল করে একই হাজিরা দুবার
INSERT INTO attendance VALUES (2101, '2025-10-01');
INSERT INTO attendance VALUES (2101, '2025-10-01');
SELECT * FROM attendance;
SELECT COUNT(*) AS rows_now FROM attendance;দুটি INSERT-ই সফল (“১টি সারি বদলেছে” দুবার)। SELECT * দেখায় হুবহু একই দুটি সারি (2101, 2025-10-01), আর rows_now = 2. বিশুদ্ধ relation-এ এটি অসম্ভব, কিন্তু SQL টেবিল এতে আপত্তি করে না। ফল: Arif-এর হাজিরা দ্বিগুণ গোনা হবে, অথচ দুটি সারিকে আলাদা করে মুছে দেওয়ারও কোনো সহজ উপায় নেই — দুটি দেখতে হুবহু এক।
সমাধান হলো টেবিলে একটি key ঘোষণা করা। তাহলে DBMS নিজেই set-এর নিয়ম পাহারা দেয়। নিচের কোডটি ইচ্ছা করে error দেখানোর জন্য:
CREATE TABLE attendance2 (
student_id INTEGER,
day TEXT,
PRIMARY KEY (student_id, day)
);
INSERT INTO attendance2 VALUES (2101, '2025-10-01');
INSERT INTO attendance2 VALUES (2101, '2025-10-01'); -- দ্বিতীয়বারটেবিল তৈরি হয় (✓), প্রথম INSERT সফল হয়, কিন্তু দ্বিতীয়টিতে আসে UNIQUE constraint failed: attendance2.student_id, attendance2.day. Primary key বলে দিচ্ছে — (student_id, day) জোড়াটি পুরো টেবিলে একবারই থাকতে পারবে। এভাবেই SQL টেবিলকে আবার “set”-এর কাছাকাছি আনা হয়। বাস্তবের প্রায় প্রতিটি টেবিলে তাই primary key থাকে; বিস্তারিত পরের পর্বে।
তৃতীয় পার্থক্য — কলামের ক্রম। তত্ত্বে কলামের ক্রম নেই, আর কোয়েরিতে আপনি যেকোনো ক্রমে কলাম চাইতে পারেন:
SELECT student_id, name FROM students WHERE batch = 2023;
-- একই তথ্য, অন্য কলাম-ক্রম
SELECT name, student_id FROM students WHERE batch = 2023;প্রথম ফল: (2301, Gulshan Ara), (2302, Habib Ullah). দ্বিতীয় ফল: (Gulshan Ara, 2301), (Habib Ullah, 2302). তথ্য হুবহু এক — প্রতিটি মান তার কলামের নাম সঙ্গে নিয়ে এসেছে। তবে SQL-এ ক্রমের একটি প্রভাব থেকেই যায়: SELECT * কলামগুলো ঘোষণার ক্রমে দেখায়, আর কলামের নাম ছাড়া INSERT INTO students VALUES (…) লিখলে মানগুলো অবস্থান মেনে বসে। তাই অ্যাপের কোডে SELECT * আর নামহীন INSERT এড়িয়ে চলা ভালো অভ্যাস — কেউ টেবিলে একটি কলাম যোগ করলেই সেগুলো ভেঙে যেতে পারে।
ডিস্কে সারিগুলোর একটি ক্রম অবশ্যই থাকে — SQLite প্রতিটি সাধারণ টেবিল একটি B-tree-তে rowid অনুযায়ী রাখে, PostgreSQL রাখে heap page-এ (প্রতিটি সারির ঠিকানা ctid). কিন্তু এই ক্রম physical স্তরের ব্যাপার, relation-এর অর্থের অংশ নয়; index বদলালে, parallel scan চললে বা VACUUM-এর পর সারি অন্য ক্রমে আসতে পারে। তাই ফলাফলের ক্রম শুধু তখনই নিশ্চিত, যখন ORDER BY লেখা থাকে। পর্ব ০৩-এর physical data independence ঠিক এটাই নিশ্চিত করে — আর পর্ব ৩৯-এ ডিস্কের ভেতরটা দেখবেন।
৭ · NULL — “মান নেই”, আর তার তিন অর্থ
db-uni-তে Fahim Karim-এর cgpa ঘরটি খালি, আর Habib Ullah-র dept_id ঘরটি খালি। এই “খালি”-র নাম NULL. NULL কোনো মান নয় — শূন্যও নয়, ফাঁকা লেখা ''-ও নয়। এটি একটি চিহ্ন, যা বলে “এখানে কোনো মান নেই।” কিন্তু কেন নেই, সেটা NULL বলে না। অন্তত তিনটি আলাদা কারণ হতে পারে:
অজানা (unknown)
মান আছে, কিন্তু আমরা জানি না। Fahim-এর CGPA এখনো হিসাব হয়ে আসেনি — CGPA একটা হবেই, শুধু এখনো জানা নেই। একইভাবে Dilruba-র ২০২৪-এর একটি কোর্সের গ্রেড এখনো প্রকাশ হয়নি।
enrollments.grade = NULLপ্রযোজ্য নয় (not applicable)
এখানে মান থাকারই কথা নয়। জ্যেষ্ঠ শিক্ষক Dr. Anisur Rahman-এর কোনো mentor নেই, তাই তাঁর mentor_id-এ কোনো মান হয় না।
হারানো / দেওয়া হয়নি (missing)
মান আছে এবং কেউ হয়তো জানেও, কিন্তু ডেটাবেসে তোলা হয়নি। Habib-এর বিভাগ ফর্মে লেখা ছিল, কিন্তু কেউ টাইপ করেননি।
students.dept_id = NULLতিনটি অর্থের জন্য একটিই চিহ্ন — এটাই NULL-এর মূল দুর্বলতা। তার চেয়েও বড় ব্যাপার হলো তুলনা। “Fahim-এর CGPA কি 3.5-এর বেশি?” — উত্তর “হ্যাঁ” বা “না” নয়, উত্তর “জানি না”। তাই SQL-এ NULL-এর সঙ্গে যেকোনো তুলনার ফল হয় তৃতীয় একটি মান: UNKNOWN. আর WHERE শুধু সেই সারিগুলো রাখে, যেখানে শর্ত TRUE — UNKNOWN বাদ পড়ে যায়। এবার সেই বিখ্যাত ফাঁদটি দেখুন:
-- ভুল: কিছুই আসে না!
SELECT name FROM students WHERE cgpa = NULL;
-- ঠিক
SELECT name FROM students WHERE cgpa IS NULL;
-- কেন? NULL-এর সঙ্গে তুলনার ফল নিজেই NULL
SELECT NULL = NULL AS eq, NULL <> NULL AS ne, NULL IS NULL AS is_null;প্রথম কোয়েরি একটিও সারি দেয় না — কোনো error-ও না। এটাই বিপদ: ভুলটা চুপচাপ ঘটে। দ্বিতীয়টি দেয় Fahim Karim. তৃতীয়টির ফল: eq = NULL, ne = NULL, is_null = 1. অর্থাৎ “NULL কি NULL-এর সমান?” প্রশ্নের উত্তরও “জানি না” — দুটি অজানা মান সমান কি না, কেউ বলতে পারে না। IS NULL তুলনা করে না, শুধু জিজ্ঞেস করে “এখানে কি মান নেই?” — তাই সবসময় TRUE বা FALSE দেয়। (SQLite-এ TRUE দেখায় 1 হিসেবে।)
NULL শুধু =-কেই নয়, গোনা আর হিসাবকেও প্রভাবিত করে। আরেকটি চমক দেখুন — একটি শর্ত, যা “সবসময় সত্য” হওয়ার কথা:
SELECT COUNT(*) AS all_rows,
COUNT(cgpa) AS has_cgpa,
COUNT(dept_id) AS has_dept
FROM students;
-- "৩.৫-এর বেশি অথবা ৩.৫ বা কম" — সবাই তো পড়ার কথা?
SELECT COUNT(*) AS covered FROM students
WHERE cgpa > 3.5 OR cgpa <= 3.5;
SELECT name, dept_id, cgpa FROM students
WHERE cgpa IS NULL OR dept_id IS NULL;প্রথম ফল: all_rows = 8, has_cgpa = 7, has_dept = 7. COUNT(*) সারি গোনে, কিন্তু COUNT(কলাম) শুধু NULL-নয় এমন মান গোনে। দ্বিতীয় ফল covered = 7, 8 নয়! Fahim-এর জন্য দুটি তুলনাই UNKNOWN, আর UNKNOWN OR UNKNOWN = UNKNOWN — তাই তিনি বাদ। তৃতীয় কোয়েরি দুজনকে দেখায়: (Fahim Karim, 2, NULL) আর (Habib Ullah, NULL, 2.8). AND, OR, NOT-এর পুরো তিন-মানের সত্যসারণি পর্ব ১৬-এ।
NULL-এর সঙ্গে =, <>, <, > — যেকোনো তুলনা = UNKNOWN. পরীক্ষা করতে শুধু IS NULL / IS NOT NULL. কোনো কলামে NULL থাকতে পারলে প্রতিটি কোয়েরিতে ভাবুন — “NULL-ওয়ালা সারিগুলো কোথায় গেল?” এই ধারণাকে বলে three-valued logic (TRUE, FALSE, UNKNOWN).
একটি সিস্টেম-ভেদ জেনে রাখুন: Oracle-এ ফাঁকা string ''-কেই NULL ধরা হয়, অথচ PostgreSQL, MySQL, SQLite আর SQL Server-এ '' একটি সাধারণ মান। তাই একটি ডেটাবেস থেকে আরেকটিতে ডেটা সরালে “খালি নাম”-এর সারিগুলোর আচরণ বদলে যেতে পারে।
৮ · Relational database schema — অনেক relation-এর একটি নকশা
একটি টেবিল দিয়ে বিশ্ববিদ্যালয় চলে না। বিভাগ, শিক্ষক, শিক্ষার্থী, কোর্স, ভর্তি — প্রত্যেকটির আলাদা relation লাগে। এই relation schema-গুলোর সেটকে (সঙ্গে তাদের নিয়মগুলো) বলে relational database schema: S = {R1, R2, …, Rm}. db-uni-র schema লিখলে:
DEPARTMENTS (dept_id, name, building)
INSTRUCTORS (instructor_id, name, dept_id, salary, mentor_id)
STUDENTS (student_id, name, dept_id, batch, cgpa)
COURSES (course_id, title, dept_id, credits, instructor_id)
ENROLLMENTS (student_id, course_id, term, grade)
আর একই schema ছবিতে আঁকলে তাকে বলে schema diagram. প্রতিটি তীর একটি foreign key — “এই কলামের মান ওই টেবিলের key-তে থাকতে হবে”:
db-uni-র schema diagram
Arrows point from a foreign key to the primary key it references
mentor_id অন্য একজন instructor-এর instructor_id.খেয়াল করুন, তীরগুলো কোনো pointer নয় — শুধু মান মেলানোর নিয়ম। একটি ভর্তির সারি থেকে মান মিলিয়ে মিলিয়ে কীভাবে পুরো ছবিটি পাওয়া যায়, ধাপে ধাপে দেখুন:
| যে মান মেলাচ্ছি | |
| যে টেবিলে খুঁজছি | |
| জানা গেল |
- শুরু: একটি ভর্তির tuple. enrollments-এ (2101, CSE301, 2023-Fall, A-). এটি শুধু দুটি নম্বর আর একটি গ্রেড — কার, কোন কোর্স, কিছুই নাম দিয়ে লেখা নেই।
- student_id 2101 → students. students-এ যে tuple-এর key 2101, সেটি খুঁজলাম: Arif Hossain, dept_id 1, ২০২১ ব্যাচ। কোনো pointer নেই — শুধু একই মান দুই টেবিলে।
- dept_id 1 → departments. একই কৌশল আবার: dept_id 1 মানে CSE, ভবন Academic-1.
- course_id CSE301 → courses. ভর্তির অন্য foreign key ধরে courses-এ গেলাম: Database Systems, ৩ ক্রেডিট, পড়ান instructor 6.
- instructor_id 6 → instructors. Tasnim Chowdhury, CSE বিভাগ, বেতন 65000. তাঁর mentor_id 2.
- mentor_id 2 → instructors (একই টেবিল!). এই foreign key নিজের টেবিলের দিকেই নির্দেশ করে — একে বলে self-reference. Shahana Parvin-এর mentor আবার 1 (Dr. Anisur Rahman), যাঁর mentor_id NULL — “প্রযোজ্য নয়”। SQL-এ এই পুরো পথচলাই একটি JOIN কোয়েরি (পর্ব ১৯–২০)।
Key-র এক ঝলক
Schema-র ছবিতে দুটি নতুন শব্দ এসেছে। Primary key হলো এমন এক বা একাধিক attribute, যার মান দিয়ে একটি tuple-কে অনন্যভাবে চেনা যায় — দুটি tuple-এর key কখনো এক হয় না। Foreign key হলো এমন attribute, যার মান অন্য (বা একই) relation-এর key-তে থাকতেই হবে। অংশ ৪-এর r2-এর মতো অর্থহীন instance আটকানো, আর অংশ ৬-এর duplicate হাজিরা থামানো — দুটোরই হাতিয়ার এই key. Super key, candidate key, primary key আর foreign key-র নিখুঁত সংজ্ঞা, প্রমাণ আর SQL — সব পরের পর্বে (পর্ব ০৬)।
৯ · Codd-এর ১২ নিয়ম — আসলে ১৩টি, আর কেউ পুরোপুরি মানে না
১৯৮০-এর দশকের শুরুতে relational ধারণা জনপ্রিয় হতেই অনেক কোম্পানি তাদের পুরোনো পণ্যের গায়েও “relational” লেবেল লাগাতে শুরু করে। বিরক্ত হয়ে Codd ১৯৮৫ সালে Computerworld পত্রিকায় দুটি প্রবন্ধ লেখেন, যেখানে একটি DBMS-কে সত্যিকারের relational বলার জন্য নিয়মের একটি তালিকা দেন। নাম “১২ নিয়ম” হলেও নম্বর শুরু হয় ০ থেকে — তাই আসলে নিয়ম ১৩টি। সবগুলো মুখস্থ করার দরকার নেই; গুরুত্বপূর্ণগুলো নিচে:
| নিয়ম | সহজ ভাষায় | আজকের বাস্তবতা |
|---|---|---|
| ০ · Foundation | পুরো ডেটাবেস পরিচালনা হবে শুধু relational সুবিধা দিয়ে | মূল নীতি; বাকি সব নিয়ম এর ব্যাখ্যা |
| ১ · Information | সব তথ্য — এমনকি টেবিলের বিবরণও — টেবিলের মান হিসেবে থাকবে | সাধারণত মানা হয় |
| ২ · Guaranteed access | টেবিলের নাম + key-র মান + কলামের নাম দিয়ে যেকোনো একটি মান পাওয়া যাবে | key থাকলে হ্যাঁ; key-হীন টেবিলে duplicate থাকলে নিশ্চয়তা নেই |
| ৩ · Systematic NULL | অনুপস্থিত মানের জন্য একটি নিয়মিত, type-নিরপেক্ষ ব্যবস্থা | NULL আছে, কিন্তু সিস্টেমভেদে আচরণ আলাদা (Oracle-এর '') |
| ৪ · Online catalog | টেবিলের বিবরণ (catalog) রাখা থাকবে টেবিলেই, আর একই ভাষায় কোয়েরি করা যাবে | মানা হয় — information_schema, sqlite_master |
| ৫ · Comprehensive sublanguage | সংজ্ঞা, কোয়েরি, পরিবর্তন, নিয়ম, অনুমতি, transaction — সবের জন্য একটি ভাষা | SQL এই ভূমিকা নিয়েছে |
| ৬ · View updating | তাত্ত্বিকভাবে আপডেটযোগ্য সব view-কে সিস্টেম আপডেট করতে দেবে | আংশিক; সাধারণভাবে কোন view আপডেটযোগ্য, তা নির্ধারণ করাই কঠিন |
| ৭ · Set-level insert/update/delete | একসঙ্গে অনেক সারি বদলানো যাবে, এক এক করে নয় | মানা হয় |
| ৮ ও ৯ · Physical ও logical data independence | স্টোরেজ বা টেবিলের কাঠামো বদলালেও অ্যাপ ভাঙবে না | physical মোটামুটি হ্যাঁ; logical আংশিক (পর্ব ০৩) |
| ১০ · Integrity independence | ডেটার নিয়ম (constraint) catalog-এ থাকবে, অ্যাপের কোডে নয় | অনেকটা; জটিল নিয়ম প্রায়ই অ্যাপে চলে যায় |
| ১১ · Distribution independence | ডেটা কয়টি সার্ভারে ছড়ানো, ব্যবহারকারীকে জানতে হবে না | আংশিক — distributed SQL সিস্টেম চেষ্টা করছে (পর্ব ৫৪) |
| ১২ · Nonsubversion | নিচু স্তরের পথে (রেকর্ড-বাই-রেকর্ড) নিয়ম এড়ানো যাবে না | প্রায়ই ভাঙে — bulk load-এ constraint বন্ধ রাখা যায় |
নিয়ম ৪ এখনই পরখ করা যায়। SQLite তার সব টেবিলের বিবরণ রাখে sqlite_master নামের একটি টেবিলে — আর সেটি সাধারণ SELECT দিয়েই পড়া যায়:
-- catalog-ও একটি টেবিল (Codd-এর নিয়ম ৪)
SELECT type, name
FROM sqlite_master
WHERE type = 'table'
ORDER BY name;ফল ৫টি সারি: (table, courses), (table, departments), (table, enrollments), (table, instructors), (table, students). ডেটা আর ডেটার বিবরণ — দুটোই relation, দুটোই একই ভাষায় পড়া যায়। এই “ডেটার বিবরণের” নাম system catalog বা data dictionary. PostgreSQL-এ একই কাজ করে information_schema.tables বা pg_catalog, MySQL-এ information_schema.
সৎ মূল্যায়ন: আজ পর্যন্ত কোনো বাণিজ্যিক বা ওপেন-সোর্স DBMS Codd-এর সব নিয়ম পুরোপুরি মানে না। শুরু থেকেই SQL নিজেই কয়েকটি নীতি ভেঙেছে — duplicate সারি, কলামের ক্রম, নামহীন কলাম। তাই পরীক্ষায় “কোন DBMS সব ১২ নিয়ম মানে?” প্রশ্নের সঠিক উত্তর: কোনোটিই না। নিয়মগুলোকে ভাবুন একটি মাপকাঠি হিসেবে, যা দিয়ে কোনো সিস্টেম কতটা relational, তা যাচাই করা যায় — হ্যাঁ/না সার্টিফিকেট হিসেবে নয়।
- Relation আর relationship কি এক? না। Relation = টেবিল; relationship = ER মডেলে entity-দের মধ্যে সম্পর্ক (পর্ব ০৭)।
- Degree আর cardinality-র পার্থক্য? Degree = attribute-এর সংখ্যা (schema-র বৈশিষ্ট্য); cardinality = tuple-এর সংখ্যা (instance-এর বৈশিষ্ট্য)।
- Domain কী? একটি attribute যে atomic মানগুলো নিতে পারে, তাদের set.
- Relation-এ duplicate tuple থাকে না কেন? কারণ relation একটি set; তবে SQL টেবিলে key না থাকলে থাকতে পারে (bag semantics).
- Codd-এর নিয়ম কয়টি? “১২ নিয়ম” নামে পরিচিত, কিন্তু নম্বর ০ থেকে ১২ — মোট ১৩টি; কোনো DBMS সবগুলো পুরোপুরি মানে না।
১০ · AI-এর যুগে relational ধারণা কেন জরুরি
আজ ChatGPT বা অন্য যেকোনো AI কয়েক সেকেন্ডে SQL লিখে দেয়। কোয়েরিগুলো সাধারণত চলেও। সমস্যা হলো, এই পর্বের তিনটি বিষয় — duplicate, NULL আর কলামের অর্থ — ঠিক সেখানেই AI সবচেয়ে বেশি ভুল করে, আর ভুলগুলো error দেয় না, শুধু ভুল সংখ্যা দেয়।
Relation, bag আর NULL বুঝলে আপনি ভুল সংখ্যাটা ধরতে পারবেন।
AI সাধারণত যেসব ভুল করে
| AI-এর ভুল | কী ঘটে | কীভাবে ধরবেন |
|---|---|---|
WHERE col = NULL লেখা | শূন্য সারি, কোনো error নেই | NULL আছে এমন সারি আছে কি না আগে দেখুন; IS NULL লিখুন |
“কতজন আলাদা…” প্রশ্নে DISTINCT ভুলে যাওয়া | bag গোনে, সংখ্যা বেশি আসে | COUNT(*) আর COUNT(DISTINCT …) দুটোই চালিয়ে তুলনা |
নিজে থেকে কলামের নাম বানানো (student_name, gpa) | “no such column” error, অথবা অন্য অর্থের কলাম | schema দিয়ে প্রশ্ন করুন; pragma_table_info / information_schema দেখুন |
| key ছাড়া টেবিল বানানো | পরে duplicate জমে | প্রতিটি CREATE TABLE-এ primary key খুঁজুন |
ORDER BY ছাড়া “প্রথম ৫ জন” | প্রতিবার ভিন্ন ৫ জন আসতে পারে | ক্রম চাইলে ORDER BY আছে কি না দেখুন |
AI-কে প্রশ্ন করার সময় schema আর ডেটার বিশেষ অবস্থা (কোথায় NULL আছে, duplicate সম্ভব কি না) নিজেই বলে দিন। তাহলে AI অনুমানের বদলে আপনার বাস্তব টেবিল ধরে কাজ করবে:
AI-এর লেখা SQL হাতে পেলে — যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১Codd টেবিলকে “relation” বললেন কেন? গণিতের ভিত্তি বাস্তবে কী সুবিধা দিল?
“টেবিল” শব্দটি একটি ছবি বোঝায় — সারি আর কলামের একটি গ্রিড। কিন্তু ছবির নিয়ম অস্পষ্ট: দুটি একই সারি থাকলে কী হবে? সারির ক্রম কি তথ্যের অংশ? Codd গণিতের “relation” শব্দটি বেছে নিয়েছিলেন, কারণ set theory এই প্রশ্নগুলোর উত্তর আগে থেকেই নিখুঁতভাবে দিয়ে রেখেছে। Relation একটি set, তাই duplicate নেই, ক্রম নেই — আলোচনার দরকারই নেই।
এর বাস্তব সুবিধা তিনটি:
- Data independence: ১৯৭০-এর আগের IMS (hierarchical) বা CODASYL (network) ডেটাবেসে প্রোগ্রাম লেখা হতো ডেটার সাজানো পথ ধরে। পথ বদলালে প্রোগ্রাম ভাঙত। Relation-এ কোনো পথ নেই, শুধু মান — তাই স্টোরেজ বদলালেও কোয়েরি একই থাকে। Codd-এর ১৯৭০-এর প্রবন্ধের শুরুর অংশেই এই সমস্যার কথা ছিল।
- Declarative কোয়েরি আর optimizer: যেহেতু প্রতিটি কোয়েরির অর্থ গণিতে সংজ্ঞায়িত, তাই DBMS প্রমাণসহ বলতে পারে দুটি কোয়েরি সমান কি না, আর দ্রুততরটি বেছে নিতে পারে। আধুনিক query optimizer (পর্ব ৪৩) এই ভিত্তির ওপরই দাঁড়িয়ে।
- একটি সাধারণ ভাষা: Relational algebra আর calculus (পর্ব ৩২–৩৪) একটি “মাপকাঠি” দিল — কোনো কোয়েরি ভাষা এগুলোর সমান ক্ষমতার হলে তাকে relationally complete বলা হয়।
সব কিছু সহজে আসেনি। ১৯৭৪ সালের একটি ACM কর্মশালায় Codd আর network মডেলের প্রবক্তা Charles Bachman-এর মধ্যে প্রকাশ্য বিতর্ক হয়, যা “Great Debate” নামে পরিচিত। Bachman-এর প্রধান আপত্তি ছিল গতি নিয়ে — মান মিলিয়ে join করা কি pointer ধরে হাঁটার মতো দ্রুত হবে? System R আর Ingres প্রজেক্ট কয়েক বছরের মধ্যে দেখাল, ভালো optimizer আর index থাকলে হ্যাঁ, হয়।
মূল উপলব্ধি: একটি শক্ত তাত্ত্বিক ভিত্তি শুধু পরীক্ষার বিষয় নয় — এটি পুরো একটি শিল্পকে পঞ্চাশ বছরের বেশি সময় ধরে স্থিতিশীল রেখেছে। যে ভাষার অর্থ নিখুঁত, তাকেই নিরাপদে স্বয়ংক্রিয় করা যায়।
প্র ০২SQL duplicate সারি রাখতে দেয় কেন? এটা কি নকশার ভুল, নাকি ইচ্ছাকৃত কৌশল?
দুটোরই কিছুটা। ১৯৭০-এর দশকে System R-এর দল যখন SEQUEL (পরে SQL) বানাচ্ছিল, তখন তাদের সামনে একটি বাস্তব প্রশ্ন ছিল: প্রতিটি কোয়েরির ফল থেকে duplicate বাদ দিতে কত খরচ?
- Duplicate বাদ দেওয়া সস্তা নয়: n-টি সারি থেকে duplicate খুঁজতে হলে সেগুলোকে sort করতে হয় (প্রায় n log n তুলনা) বা hash table-এ রাখতে হয় (গড়ে প্রায় n ধাপ, কিন্তু বাড়তি মেমরি)। লক্ষ লক্ষ সারির ফলে এটি বড় খরচ, আর অনেক সময় অপ্রয়োজনীয় — যেমন ফলের সারিগুলো আগে থেকেই আলাদা হলে।
- Aggregation-এর জন্য bag দরকার: “সব অর্ডারের মোট টাকা” হিসাবে দুটি অর্ডারের দাম একই (৫০০ টাকা) হলে set হিসেবে একটি ৫০০ হারিয়ে যেত। তাই
SUM,AVG,COUNTস্বাভাবিকভাবেই bag-এর ওপর কাজ করে। - পছন্দ দেওয়া: SQL তাই দুটি রূপই রাখল —
SELECTবনামSELECT DISTINCT,UNION ALLবনামUNION(পর্ব ২২)। নিয়মটি হলো: duplicate রাখা ডিফল্ট, বাদ দিতে হলে বলতে হয়।
তবে সমালোচনাও কঠোর। Codd নিজে পরে SQL-কে relational model-এর দুর্বল রূপায়ণ বলে সমালোচনা করেছিলেন। C. J. Date আর Hugh Darwen তাঁদের “The Third Manifesto”-তে যুক্তি দেন — duplicate থাকলে “এই সারিটি” বলে কোনো কিছু নির্দিষ্ট করা যায় না (ওপরের হাজিরার উদাহরণে দুটি একই সারির একটিকে মুছবেন কীভাবে?), আর কিছু কোয়েরি-রূপান্তর, যা set-এ সঠিক, bag-এ ভুল হয়ে যায়। ফলে optimizer-কেও বাড়তি সতর্ক হতে হয়।
বাস্তবে পেশাদাররা একটি মাঝামাঝি নিয়ম মানেন: প্রতিটি base টেবিলে primary key রাখুন (তাহলে টেবিল সবসময় set), আর কোয়েরির ফলে duplicate আসবে কি না, প্রতিবার সচেতনভাবে ভাবুন।
মূল উপলব্ধি: SQL-এর bag semantics দক্ষতার জন্য তত্ত্ব থেকে সচেতনভাবে সরে আসা। দামটা দেন ব্যবহারকারী — যদি না তিনি জানেন কোথায় duplicate জন্ম নেয়। JOIN-এর পর গোনার সময় এই জ্ঞানই সবচেয়ে বেশি কাজে লাগবে।
প্র ০৩NULL কি একটি মান, নাকি মানের অনুপস্থিতি? NULL নিয়ে বিশেষজ্ঞরা এত বিভক্ত কেন?
SQL স্ট্যান্ডার্ড অনুযায়ী NULL কোনো মান নয় — এটি একটি চিহ্ন (marker), যা বলে “এখানে মান নেই”। কিন্তু এটি টেবিলের ঘরে বসে, কলামে গোনা হয়, GROUP BY-এ একটি দল তৈরি করে — অনেকটা মানের মতোই আচরণ করে। এই দ্বৈততা থেকেই বিভ্রান্তি।
Codd-এর অবস্থান: ১৯৭০-এর মূল প্রবন্ধে NULL ছিল না। পরে তিনি অনুপস্থিত তথ্যের জন্য NULL আর তিন-মানের যুক্তি প্রস্তাব করেন। ১৯৯০ সালের বই “The Relational Model for Database Management: Version 2”-এ তিনি আরও এগিয়ে দুই রকম চিহ্নের কথা বলেন — একটি “প্রযোজ্য, কিন্তু অজানা”-র জন্য, আরেকটি “প্রযোজ্য নয়”-এর জন্য, ফলে চার-মানের যুক্তি। এই অংশের তিনটি অর্থ (অজানা, প্রযোজ্য নয়, হারানো) দেখলে বুঝবেন কেন একটি চিহ্ন যথেষ্ট নয়।
বিরোধী অবস্থান: C. J. Date আর Hugh Darwen বলেন, NULL-এর তিন-মানের যুক্তি মানুষের স্বাভাবিক চিন্তার সঙ্গে মেলে না, আর এটিই অসংখ্য ভুল কোয়েরির উৎস। যেমন: x = x সাধারণত সত্য, কিন্তু x NULL হলে UNKNOWN. এই পর্বেই দেখেছেন, “3.5-এর বেশি অথবা 3.5 বা কম” শর্তটি সবাইকে ধরে না। আরও কুখ্যাত উদাহরণ NOT IN: subquery-র ফলে একটি NULL থাকলে পুরো NOT IN কোনো সারিই দেয় না (পর্ব ২১)। Date-এর প্রস্তাব — NULL বাদ দিয়ে অনুপস্থিত তথ্যকে আলাদা টেবিলে রাখা (যার CGPA জানা, শুধু তাদের সারি থাকবে CGPA টেবিলে)।
একটি পাশের গল্প: প্রোগ্রামিং ভাষায় “null reference” আলাদা জিনিস, তবে সমস্যার শিকড় কাছাকাছি। Tony Hoare ১৯৬৫ সালে ALGOL W ভাষায় null reference যোগ করেছিলেন, আর পরে প্রকাশ্যে একে নিজের “billion-dollar mistake” বলেছেন।
বাস্তবের নিয়ম: যেখানে সম্ভব NOT NULL দিন (db-uni-তে name আর batch-এর মতো); যেখানে NULL দরকার, তার অর্থ ডকুমেন্টে লিখে রাখুন; আর প্রতিটি কোয়েরিতে NULL-এর সারিগুলোর গন্তব্য ভাবুন।
মূল উপলব্ধি: NULL হলো একটি সুবিধাজনক কিন্তু ধারালো হাতিয়ার। এটি ছাড়া বাস্তবের অসম্পূর্ণ ডেটা রাখা কঠিন, আবার এর জন্যই সহজ প্রশ্নের উত্তরেও যুক্তির নিয়ম বদলে যায়।
প্র ০৪Codd-এর নিয়ম কোনো DBMS পুরোপুরি মানে না কেন? তাহলে নিয়মগুলোর মূল্য কোথায়?
Codd ১৯৮৫ সালে Computerworld-এর প্রবন্ধে নিয়মগুলো দেন একটি নির্দিষ্ট কারণে — বাজারে “relational” শব্দের অপব্যবহার থামাতে। সেই সময় অনেক পণ্য পুরোনো নকশার ওপর শুধু একটি টেবিলের মতো দেখানোর স্তর বসিয়ে নিজেকে relational বলত। নিয়মগুলো ছিল একটি পরীক্ষা: “আপনার পণ্য আসলেই কতটা relational?”
সব নিয়ম পুরোপুরি মানা কঠিন হওয়ার কয়েকটি কারণ:
- নিয়ম ৬ (view updating) তাত্ত্বিকভাবেই কঠিন: একটি view (পর্ব ২৪) অনেক টেবিল join বা aggregate করে বানানো হলে view-এ একটি সারি বদলানো মানে মূল টেবিলে কী বদলানো — অনেক সময় এর একাধিক উত্তর থাকে, বা কোনো উত্তরই থাকে না। গবেষণায় দেখা গেছে, সাধারণভাবে কোন view-আপডেট ঠিকভাবে অনুবাদ করা যায়, তা নির্ধারণ করা অত্যন্ত কঠিন সমস্যা। তাই বাস্তব DBMS শুধু সহজ view-এ আপডেট দেয়।
- নিয়ম ১১ (distribution independence) প্রকৌশলের দিক থেকে দামি: ডেটা কয়েকটি দেশে ছড়ানো থাকলে একটি join-এর গতি নির্ভর করে নেটওয়ার্কের ওপর — ব্যবহারকারীর কাছে পুরোপুরি লুকানো প্রায় অসম্ভব (পর্ব ৫৪-এর CAP আলোচনা)।
- নিয়ম ১২ (nonsubversion) বাস্তব চাপে ভাঙে: কোটি সারি দ্রুত লোড করতে প্রায় সব সিস্টেম constraint সাময়িক বন্ধ রাখার সুযোগ দেয়।
- SQL নিজেই: duplicate সারি, কলামের ক্রম, নামহীন কলাম — শিল্পের মানদণ্ড ভাষাটিই মূল মডেল থেকে সরে এসেছে। পরে Codd নিজের মডেলের দ্বিতীয় সংস্করণে (১৯৯০) নিয়মের তালিকা আরও অনেক বড় করেন; কোনো পণ্য সেটিও পূরণ করেনি।
তাহলে মূল্য কোথায়? নিয়মগুলো একটি চিন্তার কাঠামো দেয়। নিয়ম ৪ (catalog টেবিলে) থেকেই এসেছে information_schema, যা দিয়ে আজকের migration টুল আর ORM কাজ করে। নিয়ম ৮–৯ থেকেই data independence-এর ধারণা স্পষ্ট হয়েছে। নিয়ম ১০ মনে করিয়ে দেয় — ডেটার নিয়ম ডেটাবেসে রাখুন, শুধু অ্যাপের কোডে নয়; নইলে দ্বিতীয় অ্যাপ সেই নিয়ম জানবে না।
মূল উপলব্ধি: আদর্শ মানদণ্ড পুরোপুরি পূরণ না হলেও কাজে লাগে — এটি দেখায় কোথায় আপস করা হয়েছে। একজন ভালো ইঞ্জিনিয়ার জানেন তাঁর সিস্টেম কোন নিয়মটি ভাঙে, আর তার জন্য কী সতর্কতা নিতে হবে।
প্র ০৫“Atomic মান” আসলে কী? আধুনিক ডেটাবেসের JSON বা array কলাম কি 1NF ভাঙে?
শব্দটি শুনে মনে হয় “যা আর ভাঙা যায় না”। কিন্তু প্রায় সব মানই ভাঙা যায়। একটি নাম অক্ষরে ভাঙে, একটি তারিখ বছর-মাস-দিনে, একটি ফোন নম্বর অপারেটর-কোড আর বাকি অংশে। তাহলে কোনটি atomic?
Codd-এর মূল উদ্দেশ্য ছিল ব্যবহারিক: relation-এর কোনো ঘরে যেন আরেকটি relation (একটি তালিকা বা টেবিল) না বসে, কারণ তাহলে কোয়েরির ভাষায় “ঘরের ভেতরে ঢুকে খোঁজার” আলাদা নিয়ম লাগবে, আর সব কোয়েরি জটিল হবে। পরে C. J. Date-সহ অনেকে যুক্তি দেন — atomicity কোনো মানের নিজস্ব গুণ নয়, বরং DBMS-এর অপারেটর আর আপনার ব্যবহারের সাপেক্ষে। তারিখকে আপনি একক হিসেবে তুলনা করেন (order_date < '2025-10-01'), তাই এটি atomic. কিন্তু যদি প্রতিদিন “জন্মমাস” দিয়ে খুঁজতে হয়, তাহলে সেই ব্যবহারে তারিখটি আর একক নয়।
আধুনিক ডেটাবেস এই সীমা অনেকটাই ঢিলে করেছে। PostgreSQL-এ array কলাম আর jsonb আছে, MySQL-এ JSON টাইপ, SQLite-এ JSON ফাংশন (পর্ব ৩০)। SQL:1999 স্ট্যান্ডার্ডেই array আর গঠনযুক্ত টাইপ যোগ হয়েছিল। তাহলে কি এগুলো 1NF ভাঙে?
- কঠোর দৃষ্টিতে: হ্যাঁ — একটি ঘরে একাধিক মান।
- ব্যবহারিক দৃষ্টিতে: নির্ভর করে। যদি JSON-টিকে সবসময় একসঙ্গে পড়া-লেখা হয় (যেমন একটি পেমেন্ট গেটওয়ের পুরো উত্তর লগ হিসেবে রাখা), তাহলে সেটি কার্যত একটি একক মান। কিন্তু যদি JSON-এর ভেতরের কোনো ক্ষেত্র দিয়ে নিয়মিত খোঁজা, join বা constraint দরকার হয়, তাহলে সেটি আলাদা কলাম বা টেবিলে রাখাই নিরাপদ।
একটি ব্যবহারিক পরীক্ষা: “এই ঘরের ভেতরের একটি অংশ ধরে আমি কি WHERE, JOIN বা UNIQUE লিখতে চাই?” উত্তর হ্যাঁ হলে ভেঙে আলাদা করুন। অংশ ৫-এর ফোন নম্বরের উদাহরণে “এই নম্বর কার?” প্রশ্নটিই সিদ্ধান্ত দিয়ে দেয়।
মূল উপলব্ধি: 1NF কোনো অন্ধ নিয়ম নয়, এটি কোয়েরিকে সরল রাখার একটি চুক্তি। কোন মান atomic, তা ঠিক হয় আপনি ডেটাকে কীভাবে প্রশ্ন করবেন তা দিয়ে।
অনুশীলন
ওপরের যেকোনো db-uni এডিটরে কোড বদলে নিজের উত্তর যাচাই করতে পারবেন।
-
হাতে হিসাব: db-uni-র
enrollmentsটেবিলে চারটি কলাম (student_id, course_id, term, grade) আর ১৩টি সারি। (ক) এর degree আর cardinality কত? (খ) সারিগুলোর term হলো: 2022-Spring তিনবার, 2023-Fall পাঁচবার, 2022-Fall দুবার, 2023-Spring দুবার, 2024-Fall একবার।SELECT term FROM enrollments;আরSELECT DISTINCT term FROM enrollments;কয়টি করে সারি দেবে? আগে হাতে বলুন, তারপর চালিয়ে মেলান।(ক) degree = ৪, cardinality = ১৩. (খ) প্রথম কোয়েরি bag দেয় — ১৩টি সারি (৩ + ৫ + ২ + ২ + ১ = ১৩)। দ্বিতীয়টি set দেয় — ৫টি আলাদা term, তাই ৫টি সারি। লক্ষ করুন,
enrollments-এর primary key (student_id, course_id, term) — তাই পুরো টেবিলে duplicate নেই, কিন্তু শুধু একটি কলাম নিলেই duplicate জন্ম নেয়। -
কোয়েরি লিখুন: students টেবিল থেকে (ক) যাদের বিভাগ জানা নেই, তাদের নাম বের করুন; (খ) কয়টি আলাদা বিভাগে অন্তত একজন শিক্ষার্থী আছেন, তা এক লাইনে গুনুন। (খ)-এর উত্তরে NULL গোনা হবে কি?
SELECT name FROM students WHERE dept_id IS NULL; -- Habib Ullah SELECT COUNT(DISTINCT dept_id) AS depts FROM students; -- 3(ক) ফল একটি সারি: Habib Ullah.
= NULLলিখলে কিছুই আসত না। (খ) ফল ৩ — বিভাগ 1, 2 আর 3.COUNT(কলাম)NULL গোনে না, তাইCOUNT(DISTINCT dept_id)-ও NULL বাদ দেয়। অথচSELECT DISTINCT dept_idচালালে ৪টি সারি আসে (1, 2, 3 আর NULL) — DISTINCT সব NULL-কে একটি দল ধরে দেখায়, কিন্তু COUNT সেটি গোনে না। এই সূক্ষ্ম পার্থক্যটি ইন্টারভিউতে প্রায়ই আসে। -
ফল অনুমান করুন: students টেবিলে ৮ জন; dept_id 1-এ চারজন, 2-এ দুজন, 3-এ একজন, আর একজনের dept_id NULL.
SELECT COUNT(*) FROM students WHERE dept_id = 1 OR dept_id <> 1;কত দেবে? কেন?ফল ৭, ৮ নয়। ৪ জনের জন্য
dept_id = 1TRUE, ৩ জনের জন্যdept_id <> 1TRUE — মোট ৭. Habib Ullah-র dept_id NULL, তাই দুটি তুলনাই UNKNOWN, আর UNKNOWN OR UNKNOWN = UNKNOWN;WHEREতাঁকে বাদ দেয়। সবাইকে চাইলে লিখতে হতো... OR dept_id IS NULL. দুই-মানের যুক্তিতে “p অথবা p নয়” সবসময় সত্য; তিন-মানের যুক্তিতে নয় — এটাই NULL-এর মূল শিক্ষা। -
Schema নকশা: একটি পাড়ার লাইব্রেরির ক্যাটালগের জন্য BOOK relation-এর schema লিখুন — প্রতিটি বইয়ের একটি নম্বর, নাম, প্রকাশের বছর আর এক বা একাধিক লেখক থাকে। প্রতিটি attribute-এর domain বলুন, কোথায় NULL আসতে পারে বলুন, আর “লেখক”-কে কীভাবে রাখবেন যাতে 1NF না ভাঙে?
একটি ভালো উত্তর: BOOK(book_id, title, published_year) আর BOOK_AUTHOR(book_id, author_name). Domain: book_id — ধনাত্মক পূর্ণসংখ্যা; title — খালি নয় এমন লেখা; published_year — যুক্তিসংগত সীমার পূর্ণসংখ্যা (যেমন ১৫০০ থেকে চলতি বছর); author_name — লেখা। BOOK-এর degree ৩, BOOK_AUTHOR-এর ২. NULL আসতে পারে published_year-এ — পুরোনো বইয়ের বছর অজানা (“unknown” অর্থে)। লেখকদের এক ঘরে “Humayun Ahmed, Muhammed Zafar Iqbal” লিখলে 1NF ভাঙত, আর “এই লেখকের সব বই” খোঁজা কঠিন হতো। আলাদা relation-এ প্রতিটি (বই, লেখক) জোড়া একটি tuple — ঠিক অংশ ৫-এর ফোন নম্বরের সমাধানের মতো। আরও ভালো ডিজাইনে লেখকেরও আলাদা AUTHOR টেবিল আর id থাকে — সে আলোচনা পর্ব ১০-১১-তে।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমঘটনাগুলো সময়ের ক্রমে সাজান (▲▼ চেপে সরান)
- ১৯৭০ — Codd-এর প্রবন্ধ “A Relational Model of Data for Large Shared Data Banks”
- ১৯৭৪ — System R প্রজেক্টের জন্য SEQUEL ভাষার প্রস্তাব
- ১৯৭৯ — Oracle-এর প্রথম বাণিজ্যিক SQL ডেটাবেস বাজারে
- ১৯৮১ — Codd-এর Turing Award
- ১৯৮৫ — Computerworld-এ Codd-এর ১২ নিয়ম
- ১৯৮৬ — ANSI-র প্রথম SQL স্ট্যান্ডার্ড
একটি relation-এ ৫টি attribute আর ৮টি tuple আছে। এর degree আর cardinality কত?
- degree 8, cardinality 5
- degree 5, cardinality 8
- degree 40, cardinality 40
- দুটোই 13
নিচের কোনটি বিশুদ্ধ (গাণিতিক) relation-এর বৈশিষ্ট্য নয়?
- কোনো duplicate tuple নেই
- Tuple-গুলোর কোনো ক্রম নেই
- প্রতিটি attribute-এর মান atomic
- Tuple-গুলো primary key অনুযায়ী সাজানো থাকতে হবে
students টেবিলের ৮টি সারির মধ্যে একটিতে cgpa NULL. SELECT name FROM students WHERE cgpa = NULL; কী দেবে?
- যার cgpa NULL, শুধু তার নাম
- একটি syntax error
- কোনো সারিই না
- সব ৮টি সারি
Domain D1-এ ৩টি মান আর D2-এ ২টি মান। D1 × D2-এ কয়টি tuple, আর D1 ও D2-এর ওপর মোট কয়টি আলাদা relation সম্ভব?
- 6টি tuple, 64টি relation
- 5টি tuple, 32টি relation
- 6টি tuple, 1টি relation
- 6টি tuple, 720টি relation
“SQL bag semantics মেনে চলে” — এর সবচেয়ে সঠিক অর্থ কোনটি?
- SQL টেবিলের সারিগুলো সবসময় ঢোকানোর ক্রমে থাকে
- একই সারি একাধিকবার থাকতে পারে; duplicate বাদ দিতে DISTINCT লাগে
- একটি ঘরে একাধিক মান রাখা যায়
- SQL প্রতিটি কোয়েরির ফল থেকে duplicate নিজেই বাদ দেয়
Codd-এর “১২ নিয়ম” সম্পর্কে কোন বক্তব্যটি সঠিক?
- নিয়মগুলো Codd-এর ১৯৭০ সালের মূল প্রবন্ধে ছিল
- আধুনিক PostgreSQL সব নিয়ম পুরোপুরি মানে
- নম্বর ০ থেকে ১২ — মোট ১৩টি, আর কোনো DBMS সবগুলো পুরোপুরি মানে না
- নিয়ম অনুযায়ী টেবিলের বিবরণ (catalog) ব্যবহারকারীর কাছে লুকানো থাকবে
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- Relation = টেবিল, tuple = সারি, attribute = কলাম, domain = বৈধ মানের set; degree = কলামের সংখ্যা, cardinality = সারির সংখ্যা।
- Schema (STUDENT(student_id, name, …)) কালেভদ্রে বদলায়; instance বদলায় প্রতিটি INSERT/UPDATE/DELETE-এ।
- গণিতে relation হলো domain-গুলোর Cartesian product-এর একটি subset — তাই duplicate নেই, সারি বা কলামের ক্রম নেই, আর মান atomic.
- SQL টেবিল bag: duplicate সম্ভব (DISTINCT, primary key দিয়ে আটকান), কলামের ক্রম আছে, ক্রম চাইলে
ORDER BY. - NULL মানে “মান নেই”; তুলনা দেয় UNKNOWN — পরীক্ষা করুন
IS NULLদিয়ে। Codd-এর নিয়ম ০–১২ (১৩টি) একটি মাপকাঠি, কেউ পুরোপুরি মানে না।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ০৬ · Key আর integrity constraint — super, candidate, primary আর foreignপরবর্তী পর্বকোন attribute দিয়ে tuple চেনা যায়, আর টেবিলগুলো কীভাবে একে অপরকে পাহারা দেয়।
- ডেটাবেস (DBMS) ও SQL · কোর্স হোম৬৭টি পর্বপুরো কোর্সের রোডম্যাপ — ER ডিজাইন থেকে transaction আর NoSQL পর্যন্ত।
- Python থেকে SQLite ডেটাবেসপাশের ট্র্যাকএকই ধরনের টেবিল Python-এর sqlite3 দিয়ে কীভাবে তৈরি ও পড়া যায়।
- কম্পিউটার ফান্ডামেন্টালস · ডেটাবেসের মৌলিক ধারণাসহজ শুরুটেবিল, রেকর্ড আর ফিল্ডের প্রাথমিক পরিচিতি — একেবারে নতুনদের জন্য।
- DSA · Hash tableগভীরে যানDISTINCT আর duplicate খোঁজা ভেতরে প্রায়ই hashing দিয়ে হয় — কীভাবে কাজ করে।