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**, und nicht vom Kunden abhängig. Dieses Feld wird also in einer weiteren dedizierten Tabelle 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| Orte werden nun in einer dedizierten Tabelle gesichert - eine Verknüpfung zu den Kundeninformationen erfolgt über einen Fremdschlüssel. 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.