Aber wenn man erstmal 7 Joins durchführen muss, um sowas triviales wie Personenstammdaten zusammenzubekommen, dann schätzt man die "unnormale" Form sehr.
Versuchs mal mit
Gemütlichkeit Views.
Deine (produktiv-)
DB ist fast vollständig 3NF. An die Tabellen will eh keine Sau ran, wegen der 7 Joins. Also basteln wir uns Views, die die ganzen FK-Verknüpfungen kapseln. Wupps, habe ich meine Kunden-View, die mir alles sehr schön darstellt und die 23 Untertabellen wunderbar verbirgt.
Das jetzt noch mit der Auftrags-View verknüpfen, die auch wieder meine Untertabellen und FKs kapselt und -schawuppel- habe ich meine Auftragsübersicht mit einem
Code:
select *
from Aufträge a
join Kunden k on a.KundenID = k.KundenID
where a.AuftragsDatum between :DateFrom and :DateTo
Ist doch sauber, oder?
Normalerweise transferiert man ja historische Daten aus der Produktiv-
DB in eine Reporting-
DB, wobei man die 3NF zugunsten einfacher Tabellen (star design vs. snowflake) aufgibt. Bei kleineren DBs lohnt sich das nicht, da verwendet man eben Views zur Darstellung. Und -natürlich- wenn das von der Performance nicht hinhaut, dann hat man (ich jedenfalls) eine redundante Tabelle (also eine Art materialized view), die per Trigger auf dem Stand gehalten wird. Das musste ich mal machen, weil die Auftragsübersicht dann doch in Echtzeit verfügbar sein musste (alle 5 Sekunden ein neuer Auftrag rein, ein bestehender abgearbeitet usw.) Aber das ist dann eine *zusätzliche* und redundante Tabelle.
Beim Programmieren kapselst Du ja das rumgefriemele mit dieser blöden Schnittstelle auch in einer Klasse, damit sich der Anwender damit nicht rumschlagen muss. Wieso machst Du das nicht auch in deiner Datenbank?