Normalisierung: 1NF bis 3NF praktisch erklaert
AI generated
SELECT
JOIN
SQL · Datenmodellierung · Normalisierung · Datenbankdesign
Normalisierung: 1NF bis 3NF praktisch erklaert
vom Vorher-Nachher-Beispiel zur anomaliefreien Tabelle

Normalisierung ist der systematische Prozess, eine Tabelle so in kleinere, verknuepfte Tabellen aufzuteilen, dass jede Information genau einmal gespeichert wird. Dieser Beitrag zeigt anhand einer einzigen, durchgehenden Bestelltabelle Schritt fuer Schritt, was die erste, zweite und dritte Normalform jeweils fordern, welche konkrete Anomalie sie beseitigen und wie das Ergebnis als echte SQL-Tabellenstruktur aussieht.

18 Min. Lesezeit 1NF · 2NF · 3NF · funktionale Abhaengigkeit Datenbankagnostisch: MySQL · PostgreSQL · SQL Server

1. Warum Normalisierung ueberhaupt notwendig ist

Normalisierung ist keine akademische Uebung, sondern eine direkte Antwort auf ein Problem, das in fast jeder gewachsenen Tabelle auftaucht: dieselbe Information wird mehrfach gespeichert, und diese Kopien laufen frueher oder spaeter auseinander. Eine Tabelle, die Kundendaten, Bestelldaten und Produktdaten in einer einzigen breiten Zeile vermischt, sieht auf den ersten Blick praktisch aus, weil man scheinbar alles mit einem einzigen SELECT bekommt. In der Praxis fuehrt genau dieses Design aber dazu, dass eine Adressaenderung an zwanzig Stellen gleichzeitig nachgezogen werden muesste und dass ein einziger vergessener Datensatz die Datenbank in einen inkonsistenten Zustand bringt.

Der Kern der Normalisierung ist die funktionale Abhaengigkeit: Attribut B ist funktional abhaengig von Attribut A, wenn zu jedem Wert von A genau ein Wert von B gehoert. Eine Kundennummer bestimmt eindeutig den Kundennamen, eine Bestellnummer bestimmt eindeutig das Bestelldatum. Normalisierung sortiert Spalten so in Tabellen ein, dass jede Spalte tatsaechlich vom Primaerschluessel dieser Tabelle abhaengt, und von nichts anderem. Dieser Beitrag geht die drei wichtigsten Normalformen, 1NF, 2NF und 3NF, an einem einzigen durchgehenden Beispiel durch, damit der Effekt jeder Stufe konkret sichtbar wird statt abstrakt zu bleiben.

2. Erste Normalform (1NF): atomare Werte statt Wiederholungsgruppen

Die erste Normalform verlangt zwei Dinge: jede Spalte enthaelt nur atomare, nicht weiter zerlegbare Werte, und es gibt keine Wiederholungsgruppen, also keine sich wiederholenden Spaltengruppen fuer mehrere Werte desselben Typs in einer Zeile. Eine Tabelle, die Produkte einer Bestellung als kommagetrennte Liste in einer einzigen Spalte ablegt, verstoesst gegen die Normalisierung auf der ersten Stufe, weil SQL keine Moeglichkeit hat, effizient nach einem einzelnen Produkt in dieser Liste zu suchen, zu zaehlen oder zu aggregieren. Genauso problematisch sind Spalten wie produkt_1, produkt_2, produkt_3: sie begrenzen die Anzahl der Produkte pro Bestellung willkuerlich und erzeugen bei weniger Produkten leere Spalten.

Die Loesung fuer 1NF ist, aus jeder Wiederholungsgruppe eine eigene Zeile zu machen. Eine Bestellung mit drei Produkten wird zu drei Zeilen, eine pro Bestellposition, mit der Bestellnummer als gemeinsamem Bezug. Das erzeugt zwar zunaechst mehr Redundanz bei den Bestellkopf-Daten wie Kundenname oder Bestelldatum, aber diese Redundanz wird in den naechsten Schritten der Normalisierung systematisch aufgeloest. Wichtig ist, 1NF nicht mit "keine Wiederholung von Werten" zu verwechseln: es geht ausschliesslich um Struktur, nicht darum, dass derselbe Kundenname in mehreren Zeilen vorkommen darf.

-- BEFORE 1NF: repeating group in a single column, not atomic
CREATE TABLE orders_raw (
    order_id     INT PRIMARY KEY,
    customer_name VARCHAR(100),
    customer_city VARCHAR(100),
    products      VARCHAR(500)  -- e.g. "Keyboard:2, Monitor:1, Mouse:3"
);

-- AFTER 1NF: one row per order line, atomic values, no repeating group
CREATE TABLE order_lines_1nf (
    order_id      INT,
    customer_name VARCHAR(100),
    customer_city VARCHAR(100),
    product_name  VARCHAR(100),
    quantity      INT,
    PRIMARY KEY (order_id, product_name)
);

INSERT INTO order_lines_1nf VALUES
    (1001, 'Anna Berger', 'Leipzig', 'Keyboard', 2),
    (1001, 'Anna Berger', 'Leipzig', 'Monitor',  1),
    (1001, 'Anna Berger', 'Leipzig', 'Mouse',    3);

3. Zweite Normalform (2NF): volle funktionale Abhaengigkeit

Die zweite Normalform baut auf der ersten auf und fordert zusaetzlich, dass jede Nicht-Schluessel-Spalte vom vollstaendigen Primaerschluessel abhaengt, nicht nur von einem Teil davon. Das Problem tritt ausschliesslich bei zusammengesetzten Primaerschluesseln auf. In der Tabelle aus dem vorigen Abschnitt besteht der Schluessel aus order_id und product_name. customer_name und customer_city haengen aber nur von order_id ab, nicht vom Produktnamen: Egal welches Produkt in der Zeile steht, der Kunde bleibt derselbe. Diese partielle Abhaengigkeit ist genau das, was 2NF verbietet.

Die Aufloesung erfolgt, indem man die partiell abhaengigen Spalten in eine eigene Tabelle auslagert, die nur vom Teil-Schluessel abhaengt, auf den sie sich tatsaechlich beziehen. Kundendaten wandern in eine orders-Tabelle mit order_id als alleinigem Schluessel, waehrend order_lines nur noch Bestellposition-spezifische Daten wie Menge und Produktname enthaelt. Nach diesem Schritt der Normalisierung ist jede Spalte vom gesamten Schluessel ihrer Tabelle abhaengig, kein Teil-Schluessel reicht mehr aus, um sie eindeutig zu bestimmen.

-- AFTER 2NF: split into orders (depends on order_id only)
-- and order_lines (depends on the full composite key)
CREATE TABLE orders_2nf (
    order_id      INT PRIMARY KEY,
    customer_name VARCHAR(100),
    customer_city VARCHAR(100),
    order_date    DATE
);

CREATE TABLE order_lines_2nf (
    order_id     INT,
    product_name VARCHAR(100),
    quantity     INT,
    PRIMARY KEY (order_id, product_name),
    FOREIGN KEY (order_id) REFERENCES orders_2nf(order_id)
);

-- customer_name and customer_city no longer repeat per product line
INSERT INTO orders_2nf VALUES (1001, 'Anna Berger', 'Leipzig', '2026-07-01');
INSERT INTO order_lines_2nf VALUES
    (1001, 'Keyboard', 2),
    (1001, 'Monitor',  1);

4. Dritte Normalform (3NF): transitive Abhaengigkeiten entfernen

Die dritte Normalform verlangt, dass jede Nicht-Schluessel-Spalte ausschliesslich direkt vom Primaerschluessel abhaengt und nicht ueber eine andere Nicht-Schluessel-Spalte transitiv. In unserer orders_2nf-Tabelle haengt customer_city eigentlich nicht direkt von order_id ab, sondern indirekt ueber den Kunden: order_id bestimmt customer_name, und customer_name bestimmt customer_city. Diese Kette, order_id zu customer_name zu customer_city, ist eine transitive Abhaengigkeit und genau das, was die dritte Normalform der Normalisierung beseitigt.

Die Loesung ist erneut eine Aufteilung: Kundendaten wandern in eine eigene customers-Tabelle mit customer_id als Schluessel, und orders referenziert nur noch customer_id per Fremdschluessel. Jetzt haengt customer_city direkt vom Schluessel seiner eigenen Tabelle ab, customers.customer_id, und nicht mehr transitiv ueber eine Bestellung. Ab 3NF gilt die Faustregel: "Jede Nicht-Schluessel-Spalte haengt vom Schluessel ab, vom ganzen Schluessel und von nichts als dem Schluessel." Diese Formulierung fasst 1NF, 2NF und 3NF in einem Satz zusammen und ist in der Praxis der schnellste Test, ob ein Tabellenentwurf sauber normalisiert ist.

-- AFTER 3NF: customer attributes moved out of orders entirely
CREATE TABLE customers_3nf (
    customer_id   INT PRIMARY KEY AUTO_INCREMENT,
    customer_name VARCHAR(100) NOT NULL,
    customer_city VARCHAR(100) NOT NULL
);

CREATE TABLE orders_3nf (
    order_id    INT PRIMARY KEY,
    customer_id INT NOT NULL,
    order_date  DATE NOT NULL,
    FOREIGN KEY (customer_id) REFERENCES customers_3nf(customer_id)
);

-- customer_city now depends only on customer_id, no transitive chain
INSERT INTO customers_3nf (customer_name, customer_city)
    VALUES ('Anna Berger', 'Leipzig');
INSERT INTO orders_3nf (order_id, customer_id, order_date)
    VALUES (1001, 1, '2026-07-01');

5. Das komplette Beispiel: von der Rohtabelle zum Zielschema

Wenn man alle drei Schritte der Normalisierung zusammenfuegt, entsteht aus einer einzigen breiten orders_raw-Tabelle ein Schema aus vier sauber getrennten Tabellen: customers, orders, order_lines und, wenn Produktdaten wie Preis oder Beschreibung dazukommen, zusaetzlich products. Jede dieser Tabellen hat einen eigenen Primaerschluessel, jede Nicht-Schluessel-Spalte in jeder Tabelle haengt vollstaendig und ausschliesslich vom jeweiligen Schluessel ab. Der Weg von der Rohtabelle zum Zielschema ist immer derselbe: zuerst atomare Werte und keine Wiederholungsgruppen (1NF), dann volle Abhaengigkeit vom gesamten Schluessel (2NF), dann keine transitiven Abhaengigkeiten mehr (3NF).

Der praktische Vorteil zeigt sich sofort bei realistischen Abfragen. Eine Frage wie "Wie viele Bestellungen kamen aus Leipzig" erfordert im normalisierten Schema nur einen JOIN zwischen orders und customers mit einer WHERE-Bedingung auf customer_city, waehrend die Antwort im unnormalisierten Rohformat eine Textsuche in einer verschachtelten Spalte oder eine fehleranfaellige String-Parsing-Logik verlangt haette. Normalisierung macht Daten nicht nur konsistenter, sie macht sie auch mit Standard-SQL zuverlaessig abfragbar.

-- Complete target schema after full normalization to 3NF
CREATE TABLE customers (
    customer_id   INT PRIMARY KEY AUTO_INCREMENT,
    customer_name VARCHAR(100) NOT NULL,
    customer_city VARCHAR(100) NOT NULL
);

CREATE TABLE products (
    product_id   INT PRIMARY KEY AUTO_INCREMENT,
    product_name VARCHAR(100) NOT NULL,
    unit_price   DECIMAL(10,2) NOT NULL
);

CREATE TABLE orders (
    order_id    INT PRIMARY KEY,
    customer_id INT NOT NULL,
    order_date  DATE NOT NULL,
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);

CREATE TABLE order_lines (
    order_id   INT NOT NULL,
    product_id INT NOT NULL,
    quantity   INT NOT NULL,
    PRIMARY KEY (order_id, product_id),
    FOREIGN KEY (order_id) REFERENCES orders(order_id),
    FOREIGN KEY (product_id) REFERENCES products(product_id)
);

Mit diesem Schema wird die eingangs genannte Beispielfrage zu einer einzigen, klaren Abfrage. Der Optimierer kann die Fremdschluessel-Indizes nutzen, statt eine ganze Tabelle nach Teilstrings zu durchsuchen. Genau dieser Unterschied, ein indexierter JOIN gegen eine String-Suche in einer unstrukturierten Spalte, ist der messbare Performance-Effekt konsequenter Normalisierung in Reporting-Abfragen.

-- Query enabled by the normalized schema: no string parsing needed
SELECT c.customer_name, COUNT(*) AS order_count
FROM orders AS o
JOIN customers AS c ON c.customer_id = o.customer_id
WHERE c.customer_city = 'Leipzig'
GROUP BY c.customer_name
ORDER BY order_count DESC;
Normalform Regel Beseitigte Anomalie Typisches Symptom davor
1NF Atomare Werte, keine Wiederholungsgruppen Suche und Aggregation in Listen-Spalten unmoeglich produkt_1, produkt_2, produkt_3 oder CSV-Feld
2NF Volle Abhaengigkeit vom gesamten Schluessel Partielle Abhaengigkeit bei zusammengesetztem Schluessel Kundenname wiederholt sich pro Bestellposition
3NF Keine transitive Abhaengigkeit ueber Nicht-Schluessel Transitive Abhaengigkeit ueber ein anderes Attribut Stadt haengt am Kundennamen statt am Schluessel
BCNF Jede Determinante ist ein Kandidatenschluessel Seltene Anomalien bei mehreren ueberlappenden Schluesseln In der Praxis nur bei komplexen Mehrfachschluesseln relevant

6. Update-Anomalien im Detail

Eine Update-Anomalie entsteht, wenn dieselbe Information redundant an mehreren Stellen gespeichert ist und eine Aenderung deshalb an mehreren Zeilen gleichzeitig nachgezogen werden muss. In der unnormalisierten orders_raw-Tabelle, in der customer_city direkt neben jeder Bestellposition steht, muesste ein Umzug eines Kunden nach Muenchen theoretisch in jeder einzelnen Zeile aktualisiert werden, in der dieser Kunde vorkommt. Vergisst man auch nur eine Zeile, enthaelt die Datenbank zwei widerspruechliche Antworten auf dieselbe Frage: In welcher Stadt wohnt dieser Kunde eigentlich.

Nach der Normalisierung in 3NF existiert customer_city genau einmal, in der customers-Tabelle, referenziert ueber customer_id. Ein Update ist ein einzelnes UPDATE-Statement auf genau einer Zeile, und jede Abfrage, die per JOIN auf diese Zeile zugreift, sieht sofort den neuen Wert. Update-Anomalien sind damit nicht nur seltener, sie sind strukturell ausgeschlossen, weil es keine zweite Kopie mehr gibt, die veraltet sein koennte.

7. Insert-Anomalien im Detail

Eine Insert-Anomalie tritt auf, wenn man eine Information nicht speichern kann, ohne gleichzeitig eine andere, eigentlich unabhaengige Information mitliefern zu muessen. Wenn Kundendaten nur ueber Bestellzeilen existieren, wie es in einer unnormalisierten Struktur oft der Fall ist, kann ein neuer Interessent, der noch keine Bestellung aufgegeben hat, gar nicht in der Datenbank angelegt werden. Sein Name und seine Stadt haben schlicht keinen Platz, an dem sie ohne eine Bestellnummer existieren duerften.

Sobald customers als eigene Tabelle mit eigenem Primaerschluessel existiert, laesst sich ein Kunde unabhaengig von jeder Bestellung anlegen. Das ist einer der unterschaetzten Vorteile der Normalisierung: Sie entkoppelt Entitaeten voneinander, sodass jede fuer sich existieren kann. Ein Newsletter-Interessent, ein Produkt ohne Lagerbestand oder ein Kunde, der noch nicht bestellt hat, sind in einem normalisierten Schema alle problemlos abbildbar, ohne Platzhalterzeilen oder NULL-Werte zu erzwingen.

8. Delete-Anomalien im Detail

Eine Delete-Anomalie beschreibt den Fall, dass das Loeschen einer Information ungewollt eine andere, eigentlich unabhaengige Information mit sich reisst. Wird in der unnormalisierten Tabelle die letzte Bestellung eines Kunden storniert und die zugehoerige Zeile geloescht, verschwinden mit dieser einen Zeile auch der Kundenname und die Stadt, obwohl der Kunde als Person weiterhin existiert und vielleicht naechste Woche erneut bestellt. Die Information "dieser Kunde existiert" war faelschlich an die Existenz einer Bestellzeile gekoppelt.

Nach der Normalisierung ist customers vollstaendig unabhaengig von orders. Loescht man eine Bestellung, bleibt der Kunde in der customers-Tabelle unveraendert bestehen, weil die Fremdschluesselbeziehung nur in eine Richtung zeigt: orders referenziert customers, nicht umgekehrt. Delete-Anomalien lassen sich so gezielt vermeiden, indem man Entitaeten, die unabhaengig voneinander existieren sollen, konsequent in getrennte Tabellen legt und die Beziehung ausschliesslich ueber Fremdschluessel abbildet.

9. Wann man bewusst von 3NF abweicht

3NF ist in der Praxis der Zielwert fuer die meisten transaktionalen Schemas, weil sie ein gutes Verhaeltnis aus Konsistenzschutz und Abfragekomplexitaet bietet. Hoehere Normalformen wie BCNF, 4NF oder 5NF loesen theoretisch noch feinere Anomalien, sind aber in der taeglichen Anwendungsentwicklung selten relevant, weil die Faelle, die sie adressieren, meist konstruiert oder extrem selten sind. Wichtiger als das Erreichen der hoechstmoeglichen Normalform ist, dass jede Abweichung von 3NF eine bewusste, dokumentierte Entscheidung ist und kein Zufallsprodukt aus fehlendem Datenmodellierungs-Wissen.

In leseintensiven Reporting-Szenarien wird gelegentlich gezielt denormalisiert, etwa indem eine berechnete Summenspalte redundant vorgehalten wird, um teure Aggregationen zu vermeiden. Das ist kein Widerspruch zur Normalisierung, sondern ein nachgelagerter, bewusster Tradeoff, der auf einem bereits normalisierten Schema aufsetzt: Man normalisiert zuerst korrekt und denormalisiert danach gezielt dort, wo Messungen einen echten Performance-Gewinn belegen, nicht aus Bequemlichkeit beim ersten Tabellenentwurf.

Mironsoft

Datenbankdesign, Schema-Reviews und Datenmodellierung

Datenbankschema mit Anomalien oder unklarer Struktur?

Wir pruefen bestehende Schemas auf Normalisierungsluecken, decken Update-, Insert- und Delete-Anomalien auf und liefern ein sauber normalisiertes Zielschema mit vollstaendigen DDL-Skripten.

Schema-Review

Bestehende Tabellen auf 1NF, 2NF und 3NF pruefen

Migration

Schrittweise Migration ohne Datenverlust planen

Dokumentation

ER-Diagramme und Abhaengigkeiten sauber dokumentieren

10. Zusammenfassung

Die drei praktisch wichtigsten Normalformen der Normalisierung loesen jede fuer sich ein konkretes Problem: 1NF fordert atomare Werte und keine Wiederholungsgruppen, 2NF fordert volle Abhaengigkeit vom gesamten Primaerschluessel bei zusammengesetzten Schluesseln, 3NF entfernt transitive Abhaengigkeiten ueber andere Nicht-Schluessel-Spalten. Zusammen verhindern sie Update-, Insert- und Delete-Anomalien, weil jede Information nach Abschluss der Normalisierung genau einmal existiert und nur an einer einzigen Stelle geaendert werden muss.

Der schnellste praktische Test bleibt die Faustregel "der Schluessel, der ganze Schluessel und nichts als der Schluessel". Wer eine Tabelle mit dieser Frage prueft, findet die meisten Normalisierungsluecken innerhalb weniger Minuten, ohne die formale Definition der funktionalen Abhaengigkeit im Detail durchrechnen zu muessen. Bewusste Ausnahmen von 3NF, etwa fuer Reporting-Zwecke, bleiben moeglich, sollten aber immer auf einem bereits korrekt normalisierten Schema aufsetzen und dokumentiert sein.

Normalisierung von 1NF bis 3NF: Das Wichtigste auf einen Blick

1NF: Atomare Werte

Keine Listen in Spalten, keine Wiederholungsgruppen. Jede Bestellposition wird zur eigenen Zeile.

2NF: Volle Abhaengigkeit

Bei zusammengesetzten Schluesseln muss jede Spalte vom gesamten Schluessel abhaengen, nicht von einem Teil.

3NF: Keine transitiven Ketten

Attribute duerfen nur direkt vom Schluessel abhaengen, nicht ueber ein anderes Nicht-Schluessel-Attribut.

Ergebnis

Update-, Insert- und Delete-Anomalien strukturell ausgeschlossen, weil jede Information genau einmal existiert.

11. FAQ: Normalisierung 1NF bis 3NF

1Was ist Normalisierung in einem Satz?
Tabellen so aufteilen, dass jede Information genau einmal gespeichert wird und Anomalien strukturell ausgeschlossen sind.
2Was fordert 1NF konkret?
Atomare Werte pro Spalte, keine Wiederholungsgruppen. Jede Wiederholung wird zu einer eigenen Zeile.
3Unterschied 2NF und 3NF?
2NF: volle Abhaengigkeit vom gesamten Schluessel. 3NF: zusaetzlich keine transitiven Abhaengigkeiten ueber andere Spalten.
4Was ist eine funktionale Abhaengigkeit?
Zu jedem Wert von A gehoert genau ein Wert von B. Eine Kundennummer bestimmt eindeutig den Kundennamen.
5Was ist eine Update-Anomalie?
Redundante Kopien einer Information muessen bei einer Aenderung alle gleichzeitig aktualisiert werden, sonst entsteht ein Widerspruch.
6Was ist eine Insert-Anomalie?
Eine Information kann nicht gespeichert werden, ohne eine andere, eigentlich unabhaengige Information zwingend mitzuliefern.
7Was ist eine Delete-Anomalie?
Beim Loeschen einer Zeile geht ungewollt auch eine andere, eigentlich unabhaengige Information verloren.
8Muss jede Tabelle 3NF erreichen?
3NF ist der sinnvolle Standard. Bewusste, dokumentierte Abweichungen fuer Reporting sind moeglich.
9Unterschied 3NF und BCNF?
BCNF ist strenger und verlangt, dass jede Determinante ein Kandidatenschluessel ist. Relevant bei mehreren ueberlappenden Schluesseln.
10Schneller Test fuer Normalisierung?
Der Schluessel, der ganze Schluessel und nichts als der Schluessel. Trifft das auf jede Spalte zu, ist die Tabelle in 3NF.