Modellierung
Grain zuerst festlegen
Vor Tabellenentwurf ein messbares Ereignis eindeutig beschreiben.
Eine Zeile = eine gebuchte Bestellposition
Schlüssel = order_id + line_id
Nicht enthalten = Zahlungsereignisse
Grain ist eine fachliche Aussage, nicht nur eine Liste technischer Schlüssel.
Modellierung
Fakttyp nach Frage wählen
Die passende zeitliche Sicht bewusst auswählen.
Ereignis: einzelne Buchung
Periodischer Snapshot: Bestand pro Tag
Akkumulierender Snapshot: Prozess mit Meilensteinen
Snapshots und Ereignisse nicht ohne Kennzeichnung in einer Faktentabelle mischen.
Modellierung
Geschäfts- und Versionsschlüssel
Historisierte Attribute eindeutig mit Fakten verbinden.
customer_id = stabiler fachlicher Bezug
customer_version_key = konkrete Dimensionsversion
Fakt → customer_version_key
Ein Surrogatschlüssel allein definiert keine fachliche Dublettenregel.
Modellierung
Schlüsselregeln ausdrücklich deklarieren
Für ein nicht historisiertes Beispiel Eindeutigkeit und Pflichtbelegung unterscheiden.
CREATE TABLE dim_customer (
customer_key bigint PRIMARY KEY,
customer_id text NOT NULL UNIQUE
);
Bei SCD2 ist customer_id über Versionen nicht eindeutig; dieses Beispiel dann anpassen.
Datenqualität
UNIQUE und NULL unterscheiden
Pflichtfeld und Eindeutigkeit als getrennte Eigenschaften prüfen.
UNIQUE(customer_id)
NOT NULL für verpflichtende customer_id separat
PostgreSQL behandelt NULL in UNIQUE standardmäßig als verschieden; kein universelles Dialektversprechen.
Modellierung
Fakt mit gültiger Version verbinden
Gültigkeit mit geschlossenen Start- und offenen Endgrenzen auflösen.
SELECT f.order_id, d.customer_version_key
FROM orders f JOIN dim_customer_history d
ON f.customer_id = d.customer_id
AND f.order_time >= d.valid_from
AND f.order_time < d.valid_to;
Endgrenze muss für aktuelle Versionen definiert sein; überlappende Intervalle separat prüfen.
Datenqualität
Überlappende Historie finden
Intervalle je Kunde auf mehrfache Gültigkeit prüfen.
WITH ranges AS (
SELECT *, MAX(valid_to) OVER (
PARTITION BY customer_id ORDER BY valid_from, version_id
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS prior_end
FROM dim_customer_history
)
SELECT customer_id, version_id FROM ranges
WHERE valid_from < prior_end;
Benötigt definierte Nicht-NULL-Endgrenzen und eindeutige Sortierung.
Modellierung
Viele-zu-viele bewusst auflösen
Mehrfachzuordnungen sichtbar statt versteckt modellieren.
Customer → CustomerAccount ← Account
Brücke: eine Zeile je erlaubtem Kunden-Konto-Paar
Eine Brücke verhindert nicht automatisch Doppelzählung; gewünschte Auswertungslogik festlegen.
Abfragen & Kennzahlen
Fakten getrennt voraggregieren
Vervielfachung beim direkten Join zweier Faktbestände vermeiden.
WITH sold AS (
SELECT customer_id, SUM(amount) AS sales FROM orders GROUP BY customer_id
), paid AS (
SELECT customer_id, SUM(amount) AS paid FROM payments GROUP BY customer_id
)
SELECT s.customer_id, s.sales, p.paid
FROM sold s LEFT JOIN paid p ON p.customer_id=s.customer_id;
Beispiel behält Kunden mit Umsatz; bei benötigter Vereinigung beider Kundenmengen Join bewusst ändern.
Abfragen & Kennzahlen
Quote aus Summen berechnen
Gewichtete Gesamtmarge statt Mittelwert einzelner Margen bestimmen.
SELECT SUM(profit) / NULLIF(SUM(revenue), 0)::numeric AS margin
FROM sales;
Bezugsmenge und Rückgaben fachlich klären; NULL-Ergebnis bewusst behandeln.
Abfragen & Kennzahlen
Bestände nicht über Tage summieren
Bestand zunächst je Stichtag aggregieren.
SELECT snapshot_date, SUM(balance) AS total_balance
FROM account_snapshot
GROUP BY snapshot_date;
Kontostände sind über Konten addierbar, über Zeit meist nicht als Summe sinnvoll.
Modellierung
Änderungsanomalie vermeiden
Kundenattribute nicht in jeder Bestellung unabhängig pflegen.
Customer(customer_id, customer_name)
Order(order_id, customer_id, order_date)
Analytische Denormalisierung ist eine bewusste andere Entscheidung mit Pflegeverantwortung.
Datenqualität
Zusammengesetzten Schlüssel testen
Vereinbarten Positions-Grain prüfen.
SELECT order_id, line_id, COUNT(*) AS n
FROM order_lines GROUP BY order_id, line_id
HAVING COUNT(*) > 1;
Zusätzlich NULL je Schlüsselkomponente prüfen. Ein Hash korrigiert keine Dubletten.
Datenqualität
Nicht zugeordnete Dimension finden
Fehlende oder ungültige Dimensionseinträge offenlegen.
SELECT f.order_id, f.customer_key FROM fct_orders f
WHERE f.customer_key IS NULL OR NOT EXISTS (
SELECT 1 FROM dim_customer d WHERE d.customer_key=f.customer_key
);
Falls Unknown-Member zulässig ist, dessen Bedeutung und Anteil separat dokumentieren.
Metadaten & Katalog
Modell als Vertrag beschreiben
Eine Tabelle so beschreiben, dass eine andere Person sie korrekt nutzen kann.
Grain → Schlüssel → Maßeinheit → Zeitbezug
NULL / Unknown → erlaubte Werte → Historie
Owner → Nachweis → Reviewtermin
Das ist eine Dokumentationsvorlage, kein automatisch durchgesetzter Datenbank-Constraint.