Free tutorials & notes in Hindi & English · Clean code examples 🧰 मुफ़्त PDF और फ़ोटो टूल्स →
MySQL + SQL · Lesson 137

DBMS में Normalization — 1NF, 2NF, 3NF Examples

DBMS में normalization क्या है?

Normalization relational database के columns और tables को क्रम से व्यवस्थित करने की प्रक्रिया है, ताकि हर जानकारी ठीक एक जगह store हो। आप एक चौड़ी, गड़बड़ table से शुरू करते हैं, देखते हैं कि उसके columns एक-दूसरे पर कैसे निर्भर हैं, और उसे keys से जुड़ी छोटी tables में बाँट देते हैं। हर बँटवारा एक नियम के अनुसार होता है जिसे normal form कहते हैं — 1NF, 2NF, 3NF, BCNF, 4NF और 5NF — और हर नियम एक ख़ास तरह का दोहराव हटाता है।

यह विचार Edgar F. Codd का है, IBM के उस शोधकर्ता का जिसने relational model बनाया। उन्होंने 1970 में First Normal Form और 1971 में दूसरा और तीसरा form परिभाषित किया। 1974 में Boyce–Codd Normal Form आया, और Ronald Fagin ने चौथा (1977) और पाँचवाँ (1979) form जोड़ा। पचास साल बाद भी हर अच्छा MySQL schema इन्हीं नियमों पर बनता है।

स्कूल के दफ़्तर की अलमारी सोचिए। अगर हर student की file में principal के पते की photocopy लगी हो, तो जिस दिन पता बदलेगा, किसी को सैकड़ों copies ढूँढकर सुधारनी होंगी — और कुछ ज़रूर छूट जाएँगी। Normalization कहता है: पता एक ही file में रखो, और बाक़ी हर file बस उसकी ओर इशारा करे।

💡 एक पंक्ति में: normalization = हर जानकारी एक बार store करो, और tables को keys से जोड़ो।

बात आसान रखने के लिए यह lesson एक ही चलता हुआ उदाहरण लेता है — एक college register जिसमें students, उनके courses, marks और departments हैं — गड़बड़ शुरुआत से लेकर 3NF तक। BCNF, 4NF और 5NF को अपने छोटे उदाहरण मिलते हैं, क्योंकि वे ऐसी स्थितियों से जुड़े हैं जो इस register में नहीं हैं। हर diagram notebook के पन्ने जैसा बनाया गया है, ताकि आप उसे अपने notes में उतार सकें।

Normalize क्यों? तीन anomalies

ख़राब design वाली table पहले दिन नहीं टूटती। वह धीरे-धीरे टूटती है, जैसे-जैसे data जुड़ता, बदलता और मिटता है। Database की किताबें इन गड़बड़ियों को anomalies कहती हैं, और ये ठीक तीन हैं।

गड़बड़ table की तीन anomaliesUpdate, insert और delete anomaly को तीन sticky notes पर हाथ से समझाया गया है।गड़बड़ table की तीन anomaliesUPDATE anomalyComputer का head बदला।Row 101 बदली, 102 भूले।Row 101: Dr. R. RaoRow 102: Dr. Rao→ सच कौन-सा है?INSERT anomalyनया dept: Commerce,head: Dr. Khanअभी कोई student नहीं,तो roll = ???→ insert नहीं हो सकता!DELETE anomalyRahul (103) चला गया।उसकी row delete की…Science + Dr. Mehtaभी ग़ायब!→ ज़रूरी जानकारी खो गई
Update, insert और delete anomalies — sticky notes पर हाथ से समझाई गईं।
  • Update anomaly — एक ही जानकारी कई rows में store है, इसलिए एक बदलाव सब rows में करना पड़ता है। एक row भी छूटी तो table ख़ुद से ही उलटी बात कहने लगती है।
  • Insert anomaly — एक जानकारी दर्ज करने के लिए दूसरी नकली जानकारी गढ़नी पड़ती है। नया department तब तक नहीं जुड़ सकता जब तक कम से कम एक student उसमें न आए, क्योंकि हर row में student का roll number ज़रूरी है।
  • Delete anomaly — एक जानकारी हटाने पर ग़लती से दूसरी भी हट जाती है। Science का आख़िरी student गया, तो Science के head का नाम भी उसके साथ चला गया।

Normalization इन तीनों को जड़ से हटाता है। साथ में storage कम लगता है, UPDATE statements सरल हो जाते हैं, और reports पर सच में भरोसा किया जा सकता है।

Keys और dependencies पाँच मिनट में

हर normal form कुछ गिने-चुने शब्दों से परिभाषित होता है। इन्हें एक बार समझ लीजिए, आगे के नियम लगभग अपने-आप साफ़ हो जाएँगे।

शब्दअर्थइस lesson से उदाहरण
Functional dependency (X → Y)X पता हो तो Y की सिर्फ़ एक ही value हो सकती है।roll → name
Super keyColumns का कोई भी समूह जो row को अलग से पहचान ले।(roll, c_code, name)
Candidate keyसबसे छोटी super key — कोई भी column हटाओ तो unique नहीं रहती।(roll, c_code)
Primary keyवह candidate key जिसे table के लिए चुना जाए।enrolments में (roll, c_code)
Prime attributeऐसा column जो कम से कम एक candidate key का हिस्सा हो।roll, c_code
Partial dependencyNon-key column composite key के सिर्फ़ एक हिस्से पर निर्भर हो।roll → name
Transitive dependencyNon-key column किसी दूसरे non-key column पर निर्भर हो।dept → dept_head
Multi-valued dependency (X ↠ Y)X से Y की पूरी सूची तय हो, जो बाक़ी columns से स्वतंत्र हो।roll ↠ club

अगर functional dependency आपके लिए नई है, तो functional dependency वाला lesson closure और candidate key ढूँढने का तरीक़ा क़दम-दर-क़दम समझाता है।

शुरुआत: unnormalized table (UNF)

नया सीखने वाला अक्सर सब कुछ एक ही sheet में ऐसे लिखता है — हर student की एक row, जिसमें उसके सारे phones, courses और marks ठूँस दिए गए हों:

Student register — UNF (गड़बड़ table)एक ही table में students, phones, courses, marks और departments; समस्या वाली जगहें लाल पेन से घेरी गई हैं।Student register — UNF (गड़बड़ table)rollnamephonecoursesmarksdeptdept_head101Aman98765-43210, 91234-56780DBMS, Maths78, 85ComputerDr. Rao102Priya99887-76655DBMS91ComputerDr. Rao103Rahul90011-22334Physics66ScienceDr. Mehtaएक cell में दो values→ atomic नहीं (1NF टूटा)कौन-से marks किस course के?जोड़ी सिर्फ़ अंदाज़ा है!Dr. Rao बार-बार लिखा→ दोहराव (repetition)
Unnormalized register — समस्या वाली जगहें लाल पेन से घेरी गई हैं।

पहली नज़र में यह छोटी और साफ़ लगती है। ध्यान से देखें तो तीन समस्याएँ दिखती हैं:

  1. Cells के अंदर सूचियाँ। Aman की row में दो phone numbers, दो courses और दो marks हैं। SQL साफ़ तरीक़े से नहीं बता सकता कि "Maths कौन पढ़ता है", और table में कहीं नहीं लिखा कि 78 DBMS के हैं, Maths के नहीं।
  2. दोहराई गई जानकारी। "Computer → Dr. Rao" हर Computer student की row में दोबारा लिखा है।
  3. एक table में बहुत सारे विषय। यह table एक साथ चार चीज़ें बताने की कोशिश कर रही है: students, courses, परिणाम और departments।

ऐसी table UNF (unnormalized form) में कहलाती है। अब हम इसे एक-एक normal form करके ठीक करेंगे।

First Normal Form (1NF)

नियम: table 1NF में तब है जब हर cell में एक ही, न टूटने वाली (atomic) value हो, हर column में एक ही तरह का data हो, कोई दोहराता समूह न हो, और हर row किसी key से अलग पहचानी जा सके।

बदलने का तरीक़ा:

  1. हर सूची को अलग rows में तोड़िए — हर student की हर course के लिए एक row।
  2. हर course को एक code (c_code) दीजिए ताकि वह key का हिस्सा बन सके।
  3. जिस दोहराते समूह का courses से कोई लेना-देना नहीं — phone numbers — उसे अपनी अलग table student_phone में ले जाइए।
  4. Primary key चुनिए। एक student कई courses लेता है, इसलिए key है जोड़ी (roll, c_code)।
1NF: हर cell में एक valueLists वाले cell को अलग rows में बाँटकर 1NF enrolment table और अलग student_phone table बनाई गई।1NF: हर cell में एक valuecoursesmarksDBMS, Maths78, 85rows मेंबाँटोcoursemarksDBMS78Maths85हर cell में एक valueenrolment (1NF)rollnamec_codec_namemarksdeptdept_head101AmanCS101DBMS78ComputerDr. Rao101AmanMA101Maths85ComputerDr. Rao102PriyaCS101DBMS91ComputerDr. Rao103RahulPH101Physics66ScienceDr. Mehtastudent_phonerollphone10198765-4321010191234-5678010299887-7665510390011-22334PK = (roll, c_code)name और dept_head अब भी दोहराते हैं → 2NF, 3NF
सूचियों को rows में बाँटने से 1NF enrolment table और अलग phone table मिलती है।

Phone numbers भी हर row में क्यों न दोहरा दें? Aman के 2 phones और 2 courses हैं, तो उसकी 2 × 2 = 4 rows बनेंगी, और हर नया phone rows को फिर गुणा कर देगा। स्वतंत्र सूचियों को अलग रखना ही वह बात है जिसे आगे 4NF औपचारिक रूप देता है।

अब table 1NF में है और SQL उस पर ठीक से query चला सकता है। पर ध्यान दीजिए, "Aman" और "Dr. Rao" अब भी दोहरा रहे हैं। 1NF data का आकार ठीक करता है, दोहराव नहीं।

💡 आम शंका: VARCHAR column में "DBMS,Maths" जैसी comma से अलग की गई value हमेशा 1NF तोड़ती है — भले ही आपका PHP code उसे explode() से तोड़ ले। Database ख़ुद उन टुकड़ों पर index, join या जाँच नहीं कर सकता।

Second Normal Form (2NF)

नियम: table 1NF में हो, और हर non-key column पूरी primary key पर निर्भर हो, उसके सिर्फ़ एक हिस्से पर नहीं। यानी कोई partial dependency न हो।

जाँचने के लिए 1NF table की functional dependencies लिखिए:

roll → name, dept
dept → dept_head
c_code → c_name
(roll, c_code) → marks
1NF table की functional dependenciesDependency diagram: roll से name और dept, c_code से c_name (partial), dept से dept_head (transitive), और पूरी key से marks (full)।1NF table की functional dependenciesprimary keynamedeptdept_headrollc_codemarksc_namepartialtransitivefullpartialसंकेतनारंगी = partial→ 2NF में ठीकलाल dashed = transitive→ 3NF में ठीकहरा = full→ साथ रहने दोसिर्फ़ marks को roll और c_code दोनों चाहिए।
1NF table का dependency नक्शा: नारंगी तीर partial हैं, लाल dashed तीर transitive है।

सिर्फ़ marks को key के दोनों हिस्से चाहिए — एक mark एक student के एक course का होता है। name और dept सिर्फ़ roll पर निर्भर हैं, और c_name सिर्फ़ c_code पर। ये partial dependencies हैं, और इन्हीं की वजह से "Aman" और "DBMS" बार-बार लिखे जा रहे हैं।

बदलने का तरीक़ा: हर partial dependency को उसकी अपनी table में ले जाइए, जिसकी key key का वही हिस्सा हो जिस पर वह निर्भर है।

students(roll, name, dept, dept_head)
courses(c_code, c_name)
enrolments(roll, c_code, marks)
2NF: partial dependency अलग करो1NF table तीन tables में बँटी: students, courses और enrolments।2NF: partial dependency अलग करोstudentsrollnamedeptdept_head101AmanComputerDr. Rao102PriyaComputerDr. Rao103RahulScienceDr. Mehtacoursesc_codec_nameCS101DBMSMA101MathsPH101Physicsenrolmentsrollc_codemarks101CS10178101MA10185102CS10191103PH10166dept_head अब भी दोहराता है→ 3NF इसे ठीक करेगाcourse का नाम: एक बारपूरी key → marksPK = (roll, c_code)
2NF design: तीन tables, हर table एक ही चीज़ के बारे में।

अब course के नाम एक बार store होते हैं, और enrolment table में सिर्फ़ वही है जो सच में student–course जोड़ी से जुड़ा है। एक काम का shortcut: अगर 1NF table की primary key एक ही column की है, तो वह अपने-आप 2NF में है, क्योंकि key का कोई "हिस्सा" ही नहीं जिस पर कुछ निर्भर हो।

फिर भी students table हर Computer student के लिए Dr. Rao दोहरा रही है। अगली समस्या यही है।

Third Normal Form (3NF)

नियम: table 2NF में हो, और कोई non-key column किसी दूसरे non-key column पर निर्भर न हो — यानी कोई transitive dependency न हो। औपचारिक रूप से: हर dependency X → A में या तो X super key हो, या A prime attribute हो।

students में शृंखला है roll → dept → dept_head। Department का head department की जानकारी है, student की नहीं; वह student तक सिर्फ़ dept के रास्ते पहुँचती है।

बदलने का तरीक़ा: निर्भर column को, उस column के साथ जिस पर वह सच में निर्भर है, बाहर ले जाइए।

students(roll, name, dept)
departments(dept, dept_head)
courses(c_code, c_name)
enrolments(roll, c_code, marks)
student_phone(roll, phone)
3NF: transitive dependency हटाओdept_head को departments table में ले जाया गया; Commerce बिना students के भी जोड़ा जा सकता है।3NF: transitive dependency हटाओstudentsrollnamedept101AmanComputer102PriyaComputer103RahulSciencedepartmentsdeptdept_headComputerDr. RaoScienceDr. MehtaCommerceDr. KhanFK3NF पूराDr. Rao सिर्फ़ एक बार।Head बदला? बस1 row update।Commerce बिनाstudents के: चलेगा!courses और enrolments पहले से 3NF में थीं — कोई बदलाव नहीं।
3NF में हर department head एक बार store है, और department बिना students के भी रह सकता है।

अब तीनों anomalies फिर से जाँचिए:

Anomalyपहले (UNF)बाद में (3NF)
UpdateDr. Rao कई rows में लिखाdepartments में एक row
Insertनए department के लिए नकली student चाहिएसीधे departments में insert
Deleteआख़िरी Science student हटाया तो Dr. Mehta भी गएDepartment की row सुरक्षित रहती है

पहले तीन forms याद रखने का मशहूर तरीक़ा William Kent का सार है: हर non-key column को "key, पूरी key, और key के सिवा कुछ नहीं" पर निर्भर होना चाहिए। 1NF key देता है, 2NF उसे पूरी key बनाता है, और 3NF पक्का करता है कि key के सिवा कुछ नहीं।

Boyce–Codd Normal Form (BCNF)

नियम: हर non-trivial functional dependency X → Y में X super key होना चाहिए। BCNF थोड़ा और सख़्त 3NF है: इसमें "या A prime attribute हो" वाली छूट नहीं है।

यह अंतर तभी दिखता है जब table में आपस में overlap करती candidate keys हों। एक coaching centre सोचिए जहाँ:

  • हर teacher ठीक एक subject पढ़ाता है (teacher → subject), और
  • किसी subject में एक student सिर्फ़ एक teacher से पढ़ता है ((student, subject) → teacher)।
BCNF: जब 3NF काफ़ी न होclass_teacher table में teacher → subject है पर teacher super key नहीं; इसे teacher_subject और student_teacher में बाँटा गया।BCNF: जब 3NF काफ़ी न होclass_teacherstudentsubjectteacherAmanDBMSMr. SharmaAmanMathsMs. IyerPriyaDBMSMr. SharmaRahulDBMSMs. Khanteacher → subjectCandidate keys:(student, subject) और (student, teacher)तीनों columns prime → 3NF ठीकपर teacher → subject,और teacher super key नहीं है→ BCNF टूटाबाँटोteacher_subjectteachersubjectMr. SharmaDBMSMs. IyerMathsMs. KhanDBMSstudent_teacherstudentteacherAmanMr. SharmaAmanMs. IyerPriyaMr. SharmaRahulMs. Khanसमझौताअब BCNF है, पर नियम(student, subject) → teacherअब एक table की keyसे नहीं रुकेगा।App code में जाँचिए।
teacher → subject BCNF तोड़ता है क्योंकि अकेला teacher key नहीं; table बाँटने से ठीक होता है।

Candidate keys हैं (student, subject) और (student, teacher)। हर column किसी न किसी key का हिस्सा है, इसलिए table 3NF पास कर लेती है। पर teacher → subject में बायाँ हिस्सा super key नहीं, इसलिए BCNF फ़ेल — और anomalies असली हैं। "Mr. Sharma DBMS पढ़ाते हैं" दो बार store है, और अगर Rahul छोड़ दे तो यह जानकारी ही खो जाएगी कि Ms. Khan DBMS पढ़ाती हैं।

बदलने का तरीक़ा: गड़बड़ dependency पर table को teacher_subject(teacher, subject) और student_teacher(student, teacher) में बाँटिए। क्योंकि teacher पहली table की key है, दोनों को join करने पर मूल rows हूबहू वापस मिलती हैं — इसे lossless decomposition कहते हैं।

समझौता: नियम "(student, subject) → teacher" अब किसी एक table के अंदर नहीं रहा, इसलिए primary key उसे लागू नहीं कर सकती। उसे trigger या application code में जाँचना होगा। इसी वजह से कुछ designers 3NF पर रुक जाते हैं जब BCNF में जाने से कोई ज़रूरी dependency खो जाए।

Fourth Normal Form (4NF)

नियम: table BCNF में हो और उसमें super key के अलावा कोई non-trivial multi-valued dependency न हो। Multi-valued dependency X ↠ Y का मतलब है कि X से Y values की पूरी सूची तय होती है, और उस सूची का बाक़ी columns से कोई संबंध नहीं।

मान लीजिए college यह दर्ज करता है कि हर student किन clubs में है और कौन-सी भाषाएँ बोलता है। Clubs और भाषाओं का आपस में कोई संबंध नहीं, पर दोनों एक table में हों तो हर combination लिखना पड़ता है:

4NF: स्वतंत्र lists rows को गुणा कर देती हैंदो clubs और दो भाषाएँ एक table में 4 rows बनाती हैं; दो अलग tables में बाँटने पर दोहराव ख़त्म।4NF: स्वतंत्र lists rows को गुणा कर देती हैंstudent 101 (Aman)clubsभाषाएँCodingMusicHindiEnglish2 × 2 = 4 rows!student_activityrollclublanguage101CodingHindi101CodingEnglish101MusicHindi101MusicEnglishGerman जोड़ना?2 rows जोड़नी होंगी(हर club की एक)।एक भी भूले →गलत data!4NF सुधार: स्वतंत्र lists अलग करोstudent_clubrollclub101Coding101Musicstudent_languagerolllanguage101Hindi101EnglishGerman जोड़ना = बस 1 rowroll ->> club, roll ->> language
दो स्वतंत्र सूचियाँ rows का गुणनफल बनाती हैं; दो अलग tables इसे हटा देती हैं।

2 clubs और 2 भाषाओं के लिए Aman को 4 rows चाहिए। German जोड़ें तो 2 rows और जोड़नी होंगी — हर club के लिए एक — वरना table कुछ ग़लत बात कहने लगेगी। दिलचस्प बात यह है कि यह table पहले से BCNF में है (इसकी इकलौती key तीनों columns हैं और कोई functional dependency नहीं), फिर भी दोहराव से भरी है। 4NF यही कमी पूरी करता है।

बदलने का तरीक़ा: हर स्वतंत्र multi-valued जानकारी को अपनी table में रखिए: student_club(roll, club) और student_language(roll, language)। अब भाषा जोड़ना सिर्फ़ एक row है।

Fifth Normal Form (5NF)

नियम: table 5NF (जिसे Project-Join Normal Form भी कहते हैं) में तब है जब उसे जानकारी खोए बिना छोटी tables में बाँटा न जा सके, सिवाय उन तरीक़ों के जो उसकी candidate keys से पहले ही तय हैं। इसका निशाना join dependency है: ऐसी table जो अपने तीन या अधिक projections के join के बराबर हो, पर किन्हीं दो के join के बराबर नहीं।

स्कूल का एक timetable लीजिए जिसका नियम यह है: अगर teacher कोई subject पढ़ा सकता है, teacher किसी class को दिया गया है, और वह class वह subject पढ़ती है, तो teacher उस class में वह subject पढ़ाता है।

5NF: तीन tables, एक नियमteacher_subject, teacher_class और class_subject को join करने पर teaching table बनती है; सिर्फ़ दो को join करने से नकली row आती है।5NF: तीन tables, एक नियमteacher_subjectteachersubjectSharmaDBMSSharmaPythonIyerPythonteacher_classteacherclassSharmaXII-ASharmaXII-BIyerXII-Bclass_subjectclasssubjectXII-ADBMSXII-BDBMSXII-BPythonतीनों को join करोteaching (3-तरफ़ा join)teachersubjectclassSharmaDBMSXII-ASharmaDBMSXII-BSharmaPythonXII-BIyerPythonXII-Bसिर्फ़ 2 tables join?teacher_subject JOIN teacher_classसे नकली row बनती है:Sharma | Python | XII-AXII-A में Python है ही नहीं!
Timetable तीनों जोड़ियों के join के बराबर है; सिर्फ़ दो को join करने से ग़लत row बनती है।

तीनों जानकारियाँ अलग store कीजिए — teacher_subject, teacher_class और class_subject — और पूरा timetable तीनों को join करके दोबारा बन जाता है। सिर्फ़ दो को join करने पर एक नकली row बनती है (Sharma XII-A में Python पढ़ा रहे हैं, जबकि उस class में Python है ही नहीं), इसलिए यहाँ दो हिस्सों में बाँटना सुरक्षित नहीं। तीनों जोड़ी वाली tables बन जाने के बाद किसी class में subject जोड़ना timetable की कई rows की जगह एक insert है।

सच कहें तो 5NF वाले मामले रोज़ के projects में कम आते हैं। इसे exams और interviews के लिए जानिए, और ऐसे तीन-तरफ़ा संबंधों पर नज़र रखिए जो असल में किसी नियम से चलते हैं।

सभी normal forms एक नज़र में

Normal formअतिरिक्त शर्तहटने वाली समस्याइस lesson में सुधार
1NFAtomic values, कोई दोहराता समूह नहीं, एक keyCells के अंदर सूचियाँहर course की एक row, student_phone
2NFकोई partial dependency नहींKey के हिस्से की जानकारीstudents, courses, enrolments
3NFकोई transitive dependency नहींNon-key column की जानकारीdepartments
BCNFहर determinant super key होOverlap करती keys के अंदर dependenciesteacher_subject, student_teacher
4NFकोई non-trivial multi-valued dependency नहींस्वतंत्र सूचियों से rows का गुणाstudent_club, student_language
5NFKeys के अलावा कोई join dependency नहींतीन-तरफ़ा जानकारी जो सिर्फ़ 3-तरफ़ा join से बनेteacher_subject, teacher_class, class_subject
Normal forms की सीढ़ीUNF से 5NF तक सीढ़ी, हर पायदान पर उसका नियम; 3NF पर खड़ा एक व्यक्ति कहता है कि ज़्यादातर apps यहीं रुकते हैं।Normal forms की सीढ़ीUNFcells मेंlists1NFatomic values,unique rows2NFpartial dep.नहीं3NFtransitive dep.नहींBCNFहर LHS एकsuper key4NFmulti-valueddep. नहीं5NFjoin dep.नहींज़्यादातर असली apps यहीं रुकते हैं(3NF या BCNF काफ़ी है)↑ सख़्त नियम, कम दोहराव
हर पायदान नीचे वाले से ज़्यादा सख़्त है; ज़्यादातर असली systems 3NF या BCNF पर रुकते हैं।

MySQL में अंतिम design

यह रहा college register का 3NF रूप, असली MySQL code में। इसे editor में चलाइए, फिर आख़िर के पास वाला UPDATE देखिए: department का head ठीक एक row में बदलता है, और हर report उसे अपने-आप ले लेती है।

CREATE TABLE departments (
  dept      VARCHAR(30) PRIMARY KEY,
  dept_head VARCHAR(50) NOT NULL
);

CREATE TABLE students (
  roll INT PRIMARY KEY,
  name VARCHAR(50) NOT NULL,
  dept VARCHAR(30) NOT NULL,
  FOREIGN KEY (dept) REFERENCES departments(dept)
);

CREATE TABLE student_phone (
  roll  INT,
  phone VARCHAR(15),
  PRIMARY KEY (roll, phone),
  FOREIGN KEY (roll) REFERENCES students(roll)
);

CREATE TABLE courses (
  c_code CHAR(5) PRIMARY KEY,
  c_name VARCHAR(40) NOT NULL
);

CREATE TABLE enrolments (
  roll   INT,
  c_code CHAR(5),
  marks  TINYINT UNSIGNED,
  PRIMARY KEY (roll, c_code),
  FOREIGN KEY (roll)   REFERENCES students(roll),
  FOREIGN KEY (c_code) REFERENCES courses(c_code)
);

INSERT INTO departments VALUES
  ('Computer', 'Dr. Rao'), ('Science', 'Dr. Mehta'), ('Commerce', 'Dr. Khan');
INSERT INTO students VALUES
  (101, 'Aman', 'Computer'), (102, 'Priya', 'Computer'), (103, 'Rahul', 'Science');
INSERT INTO student_phone VALUES
  (101, '98765-43210'), (101, '91234-56780'), (102, '99887-76655'), (103, '90011-22334');
INSERT INTO courses VALUES
  ('CS101', 'DBMS'), ('MA101', 'Maths'), ('PH101', 'Physics');
INSERT INTO enrolments VALUES
  (101, 'CS101', 78), (101, 'MA101', 85), (102, 'CS101', 91), (103, 'PH101', 66);

-- JOIN से पुरानी चौड़ी report दोबारा बनाइए
SELECT s.roll, s.name, c.c_name, e.marks, d.dept, d.dept_head
FROM enrolments e
JOIN students    s ON s.roll   = e.roll
JOIN courses     c ON c.c_code = e.c_code
JOIN departments d ON d.dept   = s.dept
ORDER BY s.roll, c.c_code;

-- सिर्फ़ एक row का update: अब कोई update anomaly नहीं
UPDATE departments SET dept_head = 'Dr. R. Rao' WHERE dept = 'Computer';
SELECT s.name, d.dept_head FROM students s JOIN departments d ON d.dept = s.dept;

पहला SELECT साफ़ tables से मूल चौड़ी report फिर से बनाता है। उसका output:

rollnamec_namemarksdeptdept_head
101AmanDBMS78ComputerDr. Rao
101AmanMaths85ComputerDr. Rao
102PriyaDBMS91ComputerDr. Rao
103RahulPhysics66ScienceDr. Mehta

UPDATE के बाद Aman और Priya दोनों के लिए "Dr. R. Rao" दिखता है — क्योंकि नाम सिर्फ़ एक जगह रहता है। इसकी क़ीमत report में तीन JOIN है, पर अब हर value सच के एक ही स्रोत से आती है। ऐसे और हल किए गए अभ्यास normalization examples में देखिए।

Denormalize कब करें (जान-बूझकर)

Normalization सही शुरुआती रास्ता है, पर कोई अटल नियम नहीं। ज़्यादा पढ़ने वाली जगहों पर — dashboards, reports, search pages, analytics — कई joins की लागत थोड़े दोहराव से ज़्यादा भारी पड़ सकती है। Denormalization का मतलब है पढ़ना तेज़ करने के लिए जान-बूझकर दोहराया हुआ column या सारांश table वापस जोड़ना।

  • व्यस्त dashboard के लिए हर class की row में student_count रखिए, जिसे trigger या admission वाला code update करे।
  • Principal की मासिक report के लिए हर रात normalized tables से एक सपाट reporting table बनाइए।
  • Invoice की row पर ही कुल रक़म store कीजिए, ताकि हज़ार invoices की सूची दिखाने के लिए हज़ार item सूचियाँ न जोड़नी पड़ें।

एक चीज़ जो denormalization जैसी दिखती है पर है नहीं: product की क़ीमत order line में copy करना। वह अलग जानकारी है — बिक्री के समय की क़ीमत — और आज की क़ीमत बदलने पर उसे नहीं बदलना चाहिए।

सुनहरा नियम: पहले normalize कीजिए, फिर सिर्फ़ वहीं denormalize कीजिए जहाँ असली ज़रूरत मापी गई हो, और लिखकर रखिए कि सच का स्रोत कौन-सी copy है।

आम गलतियाँ

  • Comma से अलग की गई सूचियाँ store करना। subjects = 'DBMS,Maths' जैसा column 1NF तोड़ता है। हर value की एक row वाली child table इस्तेमाल कीजिए।
  • एक column वाली key में partial dependency ढूँढना। Partial dependency सिर्फ़ composite key में संभव है; ऐसी 1NF table पहले से 2NF में होती है।
  • 2NF और 3NF में उलझना। दो अलग सवाल पूछिए: "क्या यह column key के सिर्फ़ हिस्से पर निर्भर है?" (2NF) और "क्या यह किसी दूसरे non-key column पर निर्भर है?" (3NF)।
  • यह सोचना कि AUTO_INCREMENT id सब ठीक कर देगी। नई id जोड़ने से dept → dept_head नहीं हटता; दोहराव वहीं का वहीं रहता है।
  • ऐसे बाँटना कि data खो जाए। Decompose करते समय साझा column कम से कम एक नई table की key होना चाहिए, वरना joins नकली rows बनाते हैं।
  • बाँटने के बाद foreign keys भूल जाना। इनके बिना कोई enrolment ऐसे student की ओर इशारा कर सकता है जो अब है ही नहीं।
  • सिर्फ़ normalize करने के लिए normalize करना। हर column को अलग table में डालने से सरल queries भी मुश्किल हो जाती हैं। जब तक कोई असली anomaly न बचे, 3NF या BCNF पर रुकिए।

अभ्यास प्रश्न (उत्तर सहित)

प्रश्न 1. order_items(order_id, book_id, book_title, qty, customer_name) की primary key (order_id, book_id) है। इसका सबसे ऊँचा normal form क्या है, और इसे कैसे ठीक करेंगे?

उत्तर देखें

सिर्फ़ 1NF। book_title सिर्फ़ book_id पर और customer_name सिर्फ़ order_id पर निर्भर है — दोनों partial dependencies हैं। इसे orders(order_id, customer_name), books(book_id, book_title) और order_items(order_id, book_id, qty) में बाँटिए। तीनों BCNF में हैं।

प्रश्न 2. employees(emp_id, name, pin_code, city) की primary key emp_id है। मान लीजिए हर PIN code एक ही शहर का है। सबसे ऊँचा normal form क्या है?

उत्तर देखें

2NF। Key एक ही column की है, इसलिए partial dependency नहीं, पर emp_id → pin_code → city transitive है। 3NF तक पहुँचने के लिए इसे pin_codes(pin_code, city) में ले जाइए।

प्रश्न 3. Relation R(A, B, C) में dependencies AB → C और C → B हैं। Candidate keys और सबसे ऊँचा normal form बताइए।

उत्तर देखें

AB key है क्योंकि AB → C। AC भी key है, क्योंकि C → B से AC → B मिलता है। कोई अकेला column बाक़ी सब तय नहीं करता। हर attribute prime है, इसलिए R 3NF में है; पर C → B में C super key नहीं, इसलिए R BCNF में नहीं। इसका ढाँचा class_teacher उदाहरण जैसा ही है।

प्रश्न 4. क्या हर BCNF table 3NF में होती है? क्या हर 3NF table BCNF में होती है?

उत्तर देखें

हाँ, हर BCNF table 3NF में होती है। नहीं, overlap करती candidate keys वाली 3NF table BCNF में फ़ेल हो सकती है, जैसा class_teacher में दिखा।

प्रश्न 5. एक table उन students के लिए (roll, club, language) store करती है जो कई clubs में हैं और कई भाषाएँ बोलते हैं। यह कौन-सा normal form तोड़ती है, और सुधार क्या है?

उत्तर देखें

यह BCNF में हो सकती है पर 4NF तोड़ती है, क्योंकि roll ↠ club और roll ↠ language स्वतंत्र multi-valued dependencies हैं। इसे student_club(roll, club) और student_language(roll, language) में बाँटिए।

सारांश

  • Normalization हर जानकारी एक बार store करता है और tables को keys से जोड़ता है, जिससे update, insert और delete anomalies हटती हैं।
  • 1NF: atomic values, कोई दोहराता समूह नहीं, हर row के लिए key।
  • 2NF: कोई partial dependency नहीं — हर non-key column को पूरी composite key चाहिए।
  • 3NF: कोई transitive dependency नहीं — non-key columns सिर्फ़ key पर निर्भर।
  • BCNF: हर dependency का बायाँ हिस्सा super key हो।
  • 4NF स्वतंत्र multi-valued जानकारी अलग करता है; 5NF join dependencies हटाता है।
  • असली projects में 3NF या BCNF का लक्ष्य रखिए, फिर सिर्फ़ मापी गई वजह से denormalize कीजिए।

आगे, हल किए गए प्रश्नों से अभ्यास कीजिए normalization examples में, या theory और गहराई से समझिए functional dependency में।

अक्सर पूछे जाने वाले प्रश्न (FAQ)

DBMS में normalization क्या है?
Normalization tables को व्यवस्थित करने की क्रमबद्ध प्रक्रिया है, ताकि हर जानकारी सिर्फ़ एक बार store हो। एक बड़ी, दोहराव वाली table को primary और foreign keys से जुड़ी छोटी tables में बाँटा जाता है, normal forms नाम के नियमों के अनुसार: 1NF, 2NF, 3NF, BCNF, 4NF और 5NF।
Normalization की ज़रूरत क्यों है?
इसके बिना table में update, insert और delete anomalies आती हैं। एक ही value कई rows में बदलनी पड़ती है, कुछ जानकारी दूसरी नकली जानकारी के बिना store नहीं हो पाती, और एक row delete करने से असंबंधित जानकारी भी मिट जाती है। Normalization इन समस्याओं को हटाकर data को सुसंगत रखता है।
उदाहरण सहित 1NF क्या है?
Table First Normal Form में तब है जब हर cell में एक atomic value हो और हर row अलग से पहचानी जा सके। "DBMS, Maths" रखने वाला column 1NF तोड़ता है; हर row में एक course रखना और (roll, c_code) को key बनाना इसे ठीक करता है।
2NF और 3NF में क्या अंतर है?
2NF partial dependency हटाता है: non-key column पूरी composite key पर निर्भर होना चाहिए, उसके सिर्फ़ एक हिस्से पर नहीं। 3NF transitive dependency हटाता है: non-key column किसी दूसरे non-key column पर निर्भर नहीं होना चाहिए, जैसे dept_head का dept पर निर्भर होना।
3NF और BCNF में क्या अंतर है?
BCNF ज़्यादा सख़्त है। 3NF में dependency X → A तब भी चलती है जब A किसी candidate key का हिस्सा हो, जबकि BCNF में X का हमेशा super key होना ज़रूरी है। यह अंतर सिर्फ़ उन tables में दिखता है जिनमें candidate keys आपस में overlap करती हैं, जैसे student, subject और teacher वाली table जहाँ हर teacher एक ही subject पढ़ाता है।
4NF और 5NF क्या हैं?
4NF multi-valued dependency हटाता है, जहाँ दो स्वतंत्र lists (जैसे student के clubs और भाषाएँ) हर combination store करवाती हैं। 5NF join dependency हटाता है, जहाँ table सिर्फ़ अपने तीन या अधिक projections को join करके ही दोबारा बन पाती है।
असली database को किस normal form तक normalize करना चाहिए?
ज़्यादातर business applications 3NF तक जाते हैं, और BCNF तक तब, जब उससे कोई ज़रूरी dependency न खोए। 4NF और 5NF की समस्याएँ कम मिलती हैं, फिर भी यह देख लेना चाहिए कि एक table में स्वतंत्र multi-valued जानकारी तो नहीं रखी गई।
क्या normalization से queries धीमी हो जाती हैं?
कई tables से data पढ़ने के लिए joins लगते हैं, जिनमें थोड़ा अतिरिक्त काम होता है। Keys पर सही indexes हों तो यह शायद ही समस्या बनता है, और लिखना तेज़ तथा सुरक्षित हो जाता है। भारी reporting के लिए बाद में सीमित denormalization जोड़ा जा सकता है।
Denormalization क्या है?
Denormalization जान-बूझकर दोहराया हुआ data जोड़ना है, जैसे store किया हुआ total या एक सपाट reporting table, ताकि पढ़ना तेज़ हो। इसे normalize करने के बाद, सिर्फ़ वहीं करना चाहिए जहाँ performance की असली ज़रूरत मापी गई हो, और copies को मिलाकर रखने का साफ़ नियम हो।
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

💻 लाइव कोड एडिटर

इस पेज के प्रोग्राम यहीं तैयार हैं — चलाएँ, बदलें और सीखें। कुछ भी इंस्टॉल किए बिना।
OneCompiler द्वारा संचालित। कोड एडिटर में अपने आप आ जाता है — Run दबाकर आउटपुट देखें। अगर एडिटर न खुले तो नए टैब में खोलें.
अगला topicMySQL Installation और Setup आपकी प्रगति: 137 / 151 (91%) · Lesson 138 / 151 आगे बढ़ें →

यह lesson कैसा लगा?

आपकी राय से हम content और बेहतर बनाते हैं।

अपना review और सुझाव लिखें (वैकल्पिक)

Review approve होने के बाद आपका नाम और शहर इसके साथ public दिख सकते हैं। Email या phone न लिखें।

▶ CodingEasily on YouTube

Video से सीखें – आसान Hindi में

चुनी हुई video: RDBMS भाग 3 – Class XI Commerce IT

▶ Channel subscribe करें