[SQL] Datenbankdesign

F_GXdx

Captain
Registriert
März 2006
Beiträge
4.028
Hallo Leute,

ich mache gerade ein Praktikum und soll dazu eine - eigentlich sehr simple - Datenbank modellieren, die folgendes leistet:

- Es gibt Kunden (table: customers) mit einer ID (c_id)
- Kunden haben mindestens eine Adresse (table: addresses)
- Genau eine der Adressen muss eine Primäradresse sein (table: primary_address)

So, ich habe das wie folgt gelöst:

- Ich möchte gerne die dritte Normalform einhalten
- Adresse enthält die c_id, die wiederum c_id von customers als Fremdschlüssel hat
- primary_address enthält a_id, die wiederum a_id in addresses als Fremdschlüssel hat
- primary_address enthält c_id, die wiederum c_id in addresses als Fremdschlüssel hat

Grafisch im Anhang!

Ja, das wär's. Datenbanken ist relativ lange her in meinem Studium, daher wäre ich interessiert an eurer Meinung. Was spricht eventuell gegen das Design? Was würdet ihr evtl. anders machen?

mfg
 

Anhänge

  • db.gif
    db.gif
    9,7 KB · Aufrufe: 235
Zuletzt bearbeitet:
Du könntest dir eine Tabelle sparen und die Primary Address ID in die Costumer Tabelle einbinden oder aber (und das ist die von mir bevorzugte Version) ein Feld zur Address Tabelle hinzufügen, die heißt IsPrimaryAddress vom Typ Boolean. Eine Extra Tabelle ist ein bisschen unsinnig, da du darin jeweils nur eine Adresse für einen Kunden auflisten kannst/wirst, da es ja nicht mehrere Primäradressen geben kann.
 
OK, darüber hatte ich auch schon nachgedacht, aber folgende 2 Probleme gibt es dabei:

1) Wenn der Kunde eine primary_address ID (was ein Fremdschlüssel auf Adresse.id wäre) bekommt, dann müsste die Adresse schon angelegt sein, oder nicht? Die Adresse kann nämlich erst erstellt werden, wenn der Kunde schon existiert (Adresse hat ja einen Fremdschlüssel auf Kunde.id). Irgendwie gibt das einen Zirkelschluss... oder hab ich da jetzt nen Denkfehler?

2) Bei der boolean Methode gibt es das Problem, dass man nicht ausschließen kann, dass ein Kunde mehrere Primäradressen haben könnte


andy_0 schrieb:
Eine Extra Tabelle ist ein bisschen unsinnig, da du darin jeweils nur eine Adresse für einen Kunden auflisten kannst/wirst, da es ja nicht mehrere Primäradressen geben kann.
Genau, in der Realität ist es unsinnig, und daher soll es auch in der Datenbank gar nicht erst möglich sein.

Das Problem ist nur, bei meinem jetzigen Modell ist es auch nicht optimal.
 

Anhänge

  • vis.gif
    vis.gif
    10,6 KB · Aufrufe: 157
Zuletzt bearbeitet:
Ist denn die Anforderung definitiv diese drei Tabellen zu nutzen, oder ist dir die Anzahl freigestellt?

Würde mich halt dem Vorschlag anschließen keine extra Tabelle zur Verknüpfung bei n:1 zu machen, nur weil man ein unique Attribut benötigt. Je mehr Tabellen, desto größere joins, desto langsamer (grob formuliert).
Am Ende spielt es nämlich kaum eine Rolle, ob dir die DB sagt "duplicate entry" oder deine abfragende Software vorher ein COUNT mit spezifischer WHERE-clause macht.

Und bitte auf Datentypen für die Felder achten (weiß nicht, ob das einfach nur grafische Darstellung ist), id Felder immer als unsigned integer mit A_I. Bei PLZ und Hausnummer darauf achten, dass in anderen Ländern sowohl Buchstaben vorkommen können, als auch die Reihenfolge von Bedeutung sein kann. Phone kann man auch noch in mehrere Teile aufteilen.
 
Hi! Anforderung zur Anzahl der Tabellen gibt es nicht. Die ID-Felder sollen mit generierten UUIDs belegt werden, und nicht mit Integer (ist mein Plan).

Mit unique lässt es sich ja leider nicht umsetzen mit der primäradresse und dem boolean Attribut. Ja, ich weiß schon, was du meinst mit der "überflüssigen komplexität", aber andererseits, kann man bei meiner Idee relativ leicht rausfinden, welche Kunden keine Primäradresse haben: Man muss nur bestimmen, wer zwischen customer und primary_address keinen joinpartner findet, und das sollte äußerst effizient sein. Sichergestellt, dass jeder Kunde höchstens 1 Primäradresse hat, ist nämlich auf jeden Fall.
 
andy_0 schrieb:
Du könntest dir eine Tabelle sparen und die Primary Address ID in die Costumer Tabelle einbinden oder aber (und das ist die von mir bevorzugte Version) ein Feld zur Address Tabelle hinzufügen, die heißt IsPrimaryAddress vom Typ Boolean.
Die Primary Address ID in die Costumer Tabelle einzufügen hat Vorteile, aber es kann zu Inkonsistenzen führen, wenn diese mal auf eine Adresse zeigt, die einem anderen Customer gehärt, dass muss also entsprechend gesichert sein. Ähnlich aufpassen muss man auch, wenn man das mit dem Boolean IsPrimaryAddress macht, denn dann kann es u.U. passieren, dass der bei mehr als einer Adresse des Customers TRUE ist. Das sollte zwar alles nie passieren dürfen, aber wenn doch, dann hat man einen unzufriedenen Kunden. Deshalb würde ich die Logik implizit machen und z.B. die Adressen pro Costumer durchnummerien, wobei z.B. die höchste Nummer automatisch die Primary Adresse kennzeichnet (läßt sich dann über eine View leicht abfragen). Das erfordert beim Einfügen ggf. ein paar Updates wenn die neue Adresse mal nicht die Primay ist, kann aber maximal zu dem Fehler führen keine Adresse für den Kunden zu haben.
 
F_GXdx schrieb:
Sichergestellt, dass jeder Kunde höchstens 1 Primäradresse hat, ist nämlich auf jeden Fall.
Wo der Fehler auftritt ist im Endeffekt egal. Entweder habe ich inkonsistente Daten oder mir schmiert das Programm ab, wenn der Programmierer ohne Prüfung versucht einen weiteren Datensatz anzulegen. Dann habe ich zwar konsinstente Daten, aber die Anwendung läuft eventuell garnicht mehr, wenn das Error Handling nicht greift oder gar fehlt.
Und eine Prüfung vor dem Einfügen muss in allen Fällen vorher gemacht werden.

Ich würde auch das IsPrimary-Flag verwenden.
Datenbank-Design und Normalisierung ist in der Theorie immer schön, aber man sollte bei der praktischen Umsetzung meiner Meinung nach auf unnötige Komplexität verzichten.
Alleine für den Fall, wenn man mal etwas von Hand in der Datenbank suchen oder korrigieren muss. So habe ich alles auf einen Blick und muss nicht erst noch an abhängige Tabellen denken.
 
OK. Wenn man mehr auf eine Umsetzung abzielt, bei der Kontrolle der Daten im Programm passiert, könnte ich auch einen einfacheren Primärschlüssel wählen für die Adresstabelle, zB einfach a_id?
Dann könnten Kunden zwar Duplikatadressen haben, aber könnte man ja beim insert checken?
 
Komplett auf die Programmierung musst Du Dich natürlich auch nicht verlassen ;)
Gegen eine Absicherung in der Datenbank spricht nichts, daher könntest Du den kombinierten Schlüssel auch beibehalten. (Macht aber bei unterschiedlichen Schreibweisen auch nur begrenzt Sinn (Str. <> Strasse <> Straße))

Gegen Dein Design mit der zusätzlichen Tabelle ist im Prinzip ja auch nichts einzuwenden.
Ich wollte nur den "praktischen Blickwinkel" einbringen. Mehr Tabellen machen SQL Abfragen komplexer und man hat Abhängigkeiten. Und je komplexer was ist, desto fehleranfälliger ist es auch.
Kommt aber ganz klar auch auf die Projekt-Größe an.
 
Wie wärs mit, Primary_Adress_ID(Fremdschlüssel beim Kunden, der auf die Adresse Tabelle zeigt)

dann die dritte Tabelle stattdessen, mit den zusätzliche Adressen als zwischentabelle, bei der dann jeweils eine Kunden ID und eine Adressen ID hinterlegt wird.

=> genau eine Primäradresse + beliebig viele zusätzliche...

Wenn ich die Anforerungen richtig verstanden hab
 
@ F_GXdx
Ich kann dir leider nicht genau sagen ob es zu rekursiven Problemen kommt, wenn die FK für die Adresse in der Costumer-Tabelle abgespeichert wird. Das automatische PK/FK Handling habe ich in DBs nie verwendet und immer selber dafür gesorgt, dass alles passt.

Die Boolean-Methode ist ähnlich sicher, wie die Methode mit der extra Tabelle. Sie schließt zwar aus, dass ein Kunde k über mehrere Primäradressen verfügt, jedoch nicht, dass eine Adresse für mehrere Kunden verwendet wird. Außerdem ist ein PK über Textfelder eher unsinnig. Der Geschwindigkeitsverlust ist enorm und man kann eine Straße, wie bereits von Tailtinn erwähnt, mit Str, Straße oder Strasse schreiben.

Ich persönlich habe ausschließlich ID-PKs verwendet (nicht einmal UUID, macht eher selten Sinn, nen Integer tuts auch). Wenn du die Straße zumindest grob kontrollieren möchtest, lass beim Anlegen ne Extra Suche über die DB laufen. Richtig zuverlässig wird es natürlich erst, wenn du ebenfalls Fälle wie Str, Straße, Strasse, fehlende Hausnummern, etc. berücksichtigst.

Egal für welche Methode du dich entscheidest, man kann erkennen, dass es keine garantierte/beste Methode gibt. Du musst dir immer im Klaren sein, dass du mögliche Fehler so gut wie möglich manuell abfangen musst. Mir persönlich wäre das nicht vorhanden sein einer Primärlieferadresse (alleine schon die Frage, wie die verschwunden ist, ohne das man es gemerkt hat) ein größeres Problem, als wenn der Kunde plötzlich zwei primäre Lieferadressen hat. In diesem Fall bekommt er auf alle Fälle sein Paket geliefert - mit Pech natürlich an die falsche Adresse. Beim hinzufügen von Adressen musst du beim Boolean z.B. kontrollieren ob die alte Adresse wirklich deselektiert wurde (geht mit einem COUNT(*) FROM TABELLE WHERE IsPrimary=1 AND AddressID=ID; ). Im Falle von keiner Lieferadresse wird bei schlechter Business Logic entweder gar kein Paket ausgeliefert (und niemand bekommt es mit) oder aber ein Paket ohne Adresse.

@ Holt
Das Problem mit zwei Kunden mit jeweils der selben Adresse, da sie zweimal hinzugefügt wurde, hat man immer. Die Address-Tabelle verfügt über eine ID als PK d.h. da kann man beliebig oft die selbe Anschrift hinzufügen. Natürlich ist alles andere als eine ID als PK unsinnig. Die Schreibweisenproblematik wurde ja bereits erörtert.
 
Danke für die vielen guten Meinungen.

Es wird jetzt wohl tatsächlich drauf hinauslaufen, dass ich die dritte Tabelle wieder lösche, und wie mehrmals vorgeschlagen beim customer einen verweis auf die adresstabelle setze, was dann die primäradresse anzeigt.

Eventuell auch das boolean flag, bin noch nicht ganz sicher.
 
Zuletzt bearbeitet:
Zurück
Oben