Dies ist eine alte Version des Dokuments!
Normalisierung beschreibt den Vorgang, Tabellen einer Datenbank dahingehend zu strukturieren, sodass sie keine vermeidbaren Redundanzen enthalten. Normalisierte Tabellen sorgen für eine konsistente und fehlerunanfällige Datenhaltung. ======Beispiel====== Ein Entwickler hat die Aufgabe bekommen, die Datenbank für das Wirtschaftssystem der Firma Failution zu implementieren. Die Firma möchte folgenden Informationen seiner Kunden speichern: * Kunden * Name * Firma * Adresse * Notiz (//Hinweis auf offene Rechnung//) * Bestellung * Datum * Bezahlung schon abgeschlossen - ja/nein? * Artikel * Bezeichnung * Details * Einzelpreis * Auslaufartikel - ja/nein? Der Entwurf des Entwicklers sieht wie folgt aus: ^KND_Name^KND_Firma^KND_Adresse^KND_Notiz^KND_Notiz2^BST_Datum^BST_Bezahlt^ART_1^ART_2^ |Max Mustermann|Mustermann Consulting|Musterstrasse 1, 12345 Musterstadt| | |10.10.2010|1|10x Thin-Client BAER (1.6 Ghz,Sound,VGA,USB) 199.99|15x Thin-Client NP (1.0 Ghz,Sound,VGA+DVI,USB) 179.99 Auslauf| |Theodor Tester|Test-Solutions AG|Testweg 16, 55353 Testort|Offene Rechnung| |15.02.2011| |1x Thin-Client BAER (1.6 Ghz,Sound,VGA,USB) 199.99| | |Theodor Tester|Test-Solutions AG|Testweg 16, 55353 Testort|Offene Rechnung| |15.02.2011| |1x Thin-Client BAER (1.6 Ghz,Sound,VGA,USB) 199.99| | ======1.Normalform====== Die erste Normalform liegt vor, wenn eine Tabelle die folgenden Bedingungen erfüllt: * Es dürfen keine Spalten mit gleichen Inhalten vorliegen * Die Werte dürfen nicht weiter teilbar sein (//man sagt auch, sie müssen **atomar** sein//) * Es dürfen keine doppelten Einträge/Zeilen enthalten sein Der oben angezeigt Entwurf erfüllt keine der drei Bedingungen - die Gründe sind: * Es sind Spalten mit gleichen Inhalten vorhanden - es gibt zwei Spalten für Kundennotizen und bestellte Artikel: **KND_Notiz** und **KND_Notiz2** sowie **ART_1** und **ART_2**. * Es gibt Werte, die sich weiter teilen lassen. * Das Feld **KND_Name** lässt sich in zwei seperate Felder für den Vor- und Nachnamen des Kunden aufteilen * Das Feld **KND_Adresse** vereint neben der Adresse auch die Hausnummer, die PLZ und den Ortnamen. * Es gibt zwei Felder **ART_1** und **ART_2** - diese enthalten neben der Artikelbezeichnung noch Artikeldetails, den Einzelpreis und die Anzahl der erworbenen Artikel * Da es nur zwei Spalten gibt, können Bestellungen nur zwei Positionen umfassen - oder alle Posistionen müssen in die beiden Spalten geschrieben werden * Es gibt doppelte Einträge - die letzten beiden Datensätze sind identisch - hier hat sich der Entwickler wohl vertippt und somit eine unnötige Redundanz erschaffen. Solche Mehrfach-Einträge lassen sich mit dem Verwenden eines **Primärschlüssels** vermeiden. Beherzigt man die oben genannten drei Regeln lässt sich das Konzept wie folgt überarbeiten: ^ID^KND_Vorname^KND_Nachname^KND_Firma^KND_Strasse^KND_HausNr^KND_PLZ^KND_Ort^KND_Notiz^BST_Datum^BST_Bezahlt^ART_Anzahl^ART_Bez^ART_Details^ART_Auslauf^ART_Preis^ |1|Max|Mustermann|Mustermann Consulting|Musterstrasse|1|12345|Musterstadt| |10.10.2010|ja|10|Thin-Client BAER|1.6 Ghz,Sound,VGA,USB|nein|199.99| |2|Max|Mustermann|Mustermann Consulting|Musterstrasse|1|12345|Musterstadt| |10.10.2010|ja|15|Thin-Client NP|1.0 Ghz,Sound,VGA+DVI,USB|ja|179.99| |3|Theodor|Tester|Test-Solutions AG|Testweg|16|55353|Testort|Offene Rechnung|15.02.2011|nein|1|Thin-Client BAER|1.6 Ghz,Sound,VGA,USB|nein|199.99| Was wurde geändert? * Es wurde ein Primärschlüssel **ID** eingefügt, somit gibt es einzigartige Einträge (//kein Eintrag gleicht dem anderen, da er eine andere ID hat//) * Die Felder für den Kundennamen, die Kundenadresse, Kundennotizen und das Feld mit Informationen über die bestellten Artikel wurden in **atomare** Felder aufgeteilt * Die Felder **KND_Notiz** und **KND_Notiz2** sowie **ART1** und **ART2** waren "//doppelt//", es waren zwei Felder mit dem selben informationstechnischen Nutzen - sie sollten Informationen über bestellte Artikel beinhalten. Sie wurden aufgeteilt, für alle Artikelinformationen (//Bezeichnung, Details, Auslaufartikel, Preis//) gibt es nun dedizierte Felder. ======2.Normalform====== Die zweite Normalform liegt vor, wenn die folgenden Bedingungen erfüllt werden: * Erfüllung der 1.Normalform * alle Spalten sind vom Primärschlüssel abhängig * alle Informationen werden an einer Stelle und nicht mehrfach gesichert (//keine Datenredundanz//) Diese Bedingungen werden vom aktuellen Entwurf nicht erfüllt: ^ID^KND_Vorname^KND_Nachname^KND_Firma^KND_Strasse^KND_HausNr^KND_PLZ^KND_Ort^KND_Notiz^BST_Datum^BST_Bezahlt^ART_Anzahl^ART_Bez^ART_Details^ART_Auslauf^ART_Preis^ |1|Max|Mustermann|Mustermann Consulting|Musterstrasse|1|12345|Musterstadt| |10.10.2010|ja|10|Thin-Client BAER|1.6 Ghz,Sound,VGA,USB|nein|199.99| |2|Max|Mustermann|Mustermann Consulting|Musterstrasse|1|12345|Musterstadt| |10.10.2010|ja|15|Thin-Client NP|1.0 Ghz,Sound,VGA+DVI,USB|ja|179.99| |3|Theodor|Tester|Test-Solutions AG|Testweg|16|55353|Testort|Offene Rechnung|15.02.2011|nein|1|Thin-Client BAER|1.6 Ghz,Sound,VGA,USB|nein|199.99| Es sind Spalten vorhanden, die nicht vom Primärschlüssel **ID** (//Kunde//) abhängig sind: * BST_Datum * BST_Bezahlt * ART_Anzahl * ART_Bez * ART_Details * ART_Auslauf * ART_Preis Abgesehen davon, dass die Tabelle sehr unübersichtlich ist, werden Informationen mehrfach definiert (//beispielsweise die Kunden- und Artikelinformationen, unnötige Datenredundanz//) und sind somit anfällig für [[anomalie|Anomalien]]. Diese Tabelle muss in mehrere Tabellen aufgeteilt werden - ein korrekter Ansatz wäre: Dedizierte Tabellen für: * Kunden * Artikel * Bestellungen * Bestellungspositionen ^KUNDEN^^^^^^^^^ ^KND_Nr^KND_Vorname^KND_Nachname^KND_Firma^KND_Strasse^KND_HausNr^KND_PLZ^KND_Ort^KND_Notiz^ |1|Max|Mustermann|Mustermann Consulting|Musterstrasse|1|12345|Musterstadt| | |2|Theodor|Tester|Test-Solutions AG|Testweg|16|55353|Testort|Offene Rechnung Nr.3| ^ARTIKEL^^^^^ ^ART_Nr^ART_Bezeichnung^ART_Details^ART_Auslauf^ART_Einzelpreis^ |1|Thin-Client BAER|1.6 Ghz,Sound,VGA,USB|nein|199.99| |2|Thin-Client NP|1.0 Ghz,Sound,VGA+DVI,USB|ja|179.99| ^BESTELLUNGEN^^^^ ^BST_Nr^KND_Nr^BST_Datum^BST_Bezahlt^ |1|1|10.10.2010|ja| |2|2|15.02.2011|nein| ^BESTELL_POS^^^^ ^BPOS_Nr^BST_Nr^ART_Nr^BPOS_Anzahl^ |1|1|1|10| |2|1|2|15| |3|2|1|1| Was wurde geändert? * Es gibt nun seperate Tabellen für Kunden, Artikel, Bestellungen und Bestellungspositionen (//Definition gekaufter Artikeln//) * Alle Informationen in den Tabellen sind vom Primärschlüssel abhängig ======3.Normalform====== Die dritte Normalform liegt vor, wenn die folgenden Bedingungen erfüllt werden: * Erfüllung der 2.Normalform * Auslagerung aller Felder die inhaltlich nicht vom Primärschlüssel abhängig sind Die Tabellen **ARTIKEL**, **BESTELLUNGEN** und **BESTELL_POS** liegen bereits in der dritten Normalform vor - lediglich die Tabelle **KUNDEN** liegt noch nicht in der dritten Normalform vor. Der Grund ist das Feld **KND_Ort**. Der Name eines Orts ist von seiner zugehörigen Postleitzahl, **KND_PLZ**, abhängig. Dieses Feld wird also ausgelagert: ^KUNDEN^^^^^^^^ ^KND_Nr^KND_Vorname^KND_Nachname^KND_Firma^KND_Strasse^KND_HausNr^KND_Ort^KND_Notiz^ |1|Max|Mustermann|Mustermann Consulting|Musterstrasse|1|1| | |2|Theodor|Tester|Test-Solutions AG|Testweg|16|2|Offene Rechnung Nr.3| ^ORTE^^^ ^ORT_Nr^ORT_PLZ^ORT_Name^ |1|12345|Musterstadt| |2|55353|Testort| <note>In dieser Tabelle wird explizit ein eigener Primärschlüssel definiert. Die Spalte **ORT_PLZ** eignet sich nicht als Primärschlüssel. Warum? Ganz einfach - Postleitzahlen können auch durchaus mit einer 0 beginnen, in einem solchen Fall würde die 0 abgeschnitten werden und zu Fehlinformationen führen.</note>