[Datenbank] Modellierung einer 1:n:m-Beziehung

DelphiKing

King with a crown
ID: 46719
L
20 April 2006
6.554
729
Aloha,

ich entwickle gerade ein Projekt, wo Anbieter Dienstleistungen auf einer Webplattform anbieten können.
Dabei sollen sie bestimmte, selbst wählbare Preiskategorien angeben können.
Diese Preiskategorien sollen von der PLZ des (potentiellen) Kunden abhängen, der Anbieter soll also einer Preiskategorie PLZ (beliebig viele) zuordnen können.
Die PLZ können einzelne Zahlen oder ganze Ranges sein (z.B. "1234, 2345, 3000-4000").

Wie modelliere ich das am besten/hübschesten in einer Datenbank (MySQL)?

Entspräche ja einer 1:n -> n:m Beziehung.

Letztenendes soll übrigens nach PLZ gesucht werden können, aber evtl. auch mit einer simplen Umkreissuche (Suche nach PLZ "1234" findet ggf auch PLZ im Bereich von [1230...1238]).

Bisher hätte ich es so gemacht:
Code:
<tabelle Anbieter>
int anbieterID
...
<tabelle Preiskategorien>
int preiskategorieID
int anbieterID
...
<tabelle PLZ>
int plz-von
int plz-bis
int preiskategorieID

Aber das kommt mir alles nicht so wirklich toll vor.
Hat jemand eine bessere Idee?


Grüßle,flo
 
Zuletzt bearbeitet:
Soweit, ich das blick (überarbeite den Post mal, du hast dich da etwas vercopy&pastet ;)), stehen Anbieter und Preiskategorie in Beziehung "erstellt", wobei die Preiskategorie dem Anbieter "gehört", d.h. 1:N
Die PLZ sind jedoch nicht eigenständig und gehören zur Preiskategorie als Attribute rein.

ER-Diagramm:


So versteh ich zumindest den Text. Wenn wir uns darüber einig sind, kann man sich an das Mapping machen.
 
Argh, was ist da los!
Hab schon in der Vorschau gesehen dass da was verkackt war (die andere Hälfte von meinem Post war ganz unten nochmal angehängt), aber das obere nicht bemerkt ... dabei hab ich eigentlich gar nix gecopypasted :/

Du hast das soweit richtig verstanden (Preiskategorie gehört dem Anbieter), aber es kann durchaus mehrere PLZ-Ranges pro Preiskategorie geben .. also z.B.
Code:
Preiskategorie 1      1000-1500, 1600, 1602, 1605-1610
Preiskategorie 2      1000-2000, 2020

Dafür müsste ich dann ja 4x "Preiskateogrie 1" erstellen und zweimal "Preiskateogrie 2", weil ja nur immer eine Range als Attribut angegeben werden kann ...


PS: Ich wusste, dass du als erster antworten würdest 8)
 
aber es kann durchaus mehrere PLZ-Ranges pro Preiskategorie geben .. also z.B.
Dann wären wir bei
.
PS: Ich wusste, dass du als erster antworten würdest 8)
Ich hab ein Semester lang an der Universität die Übungen für Konzeptionelle Modellierung gehalten. Ich muss mich da also auskennen :LOL: 8) Hab aber nicht gedacht, dass ich es als erster schaffe, da ich für Dia erst meinen Linux-Rechner hochfahren musste.

P.S. S*x ohne Kondom@similar threads 8O :ugly:
 
Dann wären wir bei
.
Ich hab ein Semester lang an der Universität die Übungen für Konzeptionelle Modellierung gehalten.
hmhm, ich habe ER-Diagramme zuletzt in Info in der Oberstufe behandelt ..... was stellt der Doppelkringel doch gleich nochmal dar?
(ich kriege "Endzustand eines endlichen Automaten" nicht aus dem Kopf :wall: )

P.S. S*x ohne Kondom@similar threads 8O :ugly:
o_O
Kann vllt auch Probleme in Beziehungs-Geflechten verursachen :shifty:
 
hmhm, ich habe ER-Diagramme zuletzt in Info in der Oberstufe behandelt ..... was stellt der Doppelkringel doch gleich nochmal dar?
Sei froh. Mein "Informatik"-Unterricht in der Schule hatte null mit Informatik zu tun.

Doppelkringel = multivalued, das Attribut kommt mehrfach vor. Eigentlich nur eine Modellierungsformalität. Beim Mapping wird daraus eh eine schwache Entität:


Hier sind jetzt alle die totalen Teilnahmen mit drin, die vorhin noch gefehlt haben:
Ich vermute, es gibt Anbieter, die keine (N) Preiskategorie erstellt haben, sehr wohl muss aber jede Preiskategorie genau einem (1) Anbieter zugeordnet sein.
Die Preiskategorie ist einem oder mehreren PLZ-Ranges zugeordnet. Im ER-Diagramm ist die Teilnahme noch partiell, d.h. es gäbe Preiskategorien ohne PLZ-Range. Muss du dir überlegen, ob du das brauchst. Falls nicht, muss die Teilnahme hier auch total sein.
Ein PLZ-Range ist abhängig von seiner identifizierenden Preiskategorie (weak nimmt immer total teil).

(DB-Design, aber keine ER-Diagramme können? *pfui* :p)
 
@theHacker:

hab grad nen ähnliches Problem .-)

in deinem Diagramm würde die Tabelle plz-range ja so aussehen:

pk | preiskategorie_fk | plz_von | plz_bis

wie wird dann eine einzelne plz eingetragen? wird dann plz_bis leer gelassen oder sind plz_von und plz_bis gleich? in dem bsp. hier kann es ja einzelne plz geben oder eben auch ranges.
 
wie wird dann eine einzelne plz eingetragen?
Wie es spezifiziert is ;) - das interessiert die DB nicht und wird auch nicht im ER-Diagramm modelliert. In SQL kannst du sowas als CHECK-Bedingung angeben, wird aber nicht von jeder Datenbank beachtet. MySQL afaik prüft lediglich die Syntax, kümmert sich aber nicht weiter darum.

Was mir spontan so für Möglichkeiten einfallen

  • ein Bereich ist ein Bereich und enthält somit immer mindestens 2 PLZ, d.h.
    Code:
    [FONT=Courier New]... [B][COLOR=#9932cc]CHECK[/COLOR][/B] (plz_von > plz_bis) ...[/FONT]
    (je nach Anwendungsfall, so...)

  • eine einzelne PLZ wird auch als Bereich aufgefasst, d.h.
    Code:
    [FONT=Courier New]... [B][COLOR=#9932cc]CHECK[/COLOR][/B] (plz_von >= plz_bis) ...[/FONT]
    Damit wäre es dann möglich den Bereich (12345, 12345) hinzuzufügen, der somit auch nur genau eine PLZ enthält.
    (...oder so machen)

  • Man spezifiziert eine Sonderbedeutung der PLZ 0 im Attribut bis
    Code:
    [FONT=Courier New]... [B][COLOR=#9932cc]CHECK[/COLOR][/B] ((plz_von > plz_bis) [B][COLOR=#9932cc]OR[/COLOR][/B] (plz_von != 0 [B][COLOR=#9932cc]AND[/COLOR][/B] plz_bis = 0))...[/FONT]
    (würd ich nicht tun)

  • Man verwendet MySQL's NULL-Wert, um die PLZ 0 nicht zu verlieren
    Code:
    [FONT=Courier New]...[B][COLOR=#9932cc]CHECK[/COLOR][/B] ((plz_von > plz_bis) [B][COLOR=#9932cc]OR[/COLOR][/B] (plz_von [B][COLOR=#9932cc]IS[/COLOR][/B] [B][COLOR=#9932cc]NOT[/COLOR][/B] [B][COLOR=#9932cc]NULL[/COLOR][/B] [B][COLOR=#9932cc]AND[/COLOR][/B] plz_bis [B][COLOR=#9932cc]IS[/COLOR][/B] [B][COLOR=#9932cc]NULL[/COLOR][/B]))...[/FONT]
    (würd ich noch weniger tun, da schon fast sinnlos, die 0 zu "retten")
 
hi...

ok, dann is es also eher ne sache vom skript wie ich die werte eintrage. entweder als 2 gleiche werte oder ich lasse den 2 wert NULL und prüfe dann wie du es schon geschrieben hast
 
Ein 0- oder NULL-Wert ist immer problematisch, weil dann im Code Fallunterscheidungen nötig werden. Bei der obersten Lösung entfällt dieser ganze Overhead und der Code wird wesentlich einfacher.
 
also du meinst den fall, das eine einzelne plz als ein bereich aufgefasst wird, also in beide spalten die gleiche?
 
So hab ichs auch gemacht, in etwa aus den von Hackern genannten Gründen... so kann ich immer ganz bequem einfach ne Abfrage ala
SELECT * FROM plz WHERE 12345 BETWEEN plz_von AND plz_bis
machen, um alle Einträge zu bekommen, die die PLZ 12345 beinhalten. Ohne Fallunterscheidung oder ähnliches ...
 
ok :)
aber im script muss man trotzfem noch ne unterscheidung machen, also so hab ichs gemacht...

Code:
$plz_bis = $_POST['plz_bis'] == '' ? $_POST['plz_von'] : $_POST['plz_bis']

natürlich werden die Werte vorher validiert.
 
also die eine Fallunterscheidung beim Eintragen ist ja wohl vernachlässigbar im Gegensatz zu den Unterscheidungen wenn man eines auf 0/NULL setzen würde oder ?
 
@baserider:
Das is aber sicherlich nicht alles, was du prüfst. Was is, wenn ich ein " " eintragen will? Was is, wenn ich "foo" eintragen will? Was is, wenn $_POST['plz_bis'] überhaupt nicht gesetzt ist?

Eine PLZ muss
matchen. Du prüfst immer erst die Existenz des Parameters, dann die Gültigkeit. Existiert der Wert nicht, kann er auch nicht gültig sein.

natürlich werden die Werte vorher validiert
Danach bringt dein geposteter Code auch nix mehr. Der beruht ja drauf, dass in $_POST['plz_bis'] schon ungültig is ;)

Ich würde das so machen:
PHP:
// RegExp für PLZ:
$regexp = '/^[0-9]{5}$/';
/* bin mir selber nicht sicher, wie eine PLZ aufgebaut is. Da kann man
   schnell ne führende Null oder sowas verbieten, ohne alles umändern
   zu müssen */

if(!isset($_POST['plz_von'])) // Existenz von
  die("no input");

$von = $_POST['plz_von']; // hier ist sichergestellt, dass die Var existiert

if(!preg_match($regexp, $von)) // Gültigkeit von
  die("invalid plz von");

if(!isset($_POST['plz_bis'])) // Existenz bis
  $bis = $von; // keine gesetzt => von übernehmen
else
{
  $bis = $_POST['plz_bis']; // hier ist sichergestellt, dass die Var existiert
  if(empty($bis))
    $bis = $von; // leer => von übernehmen
  else
  {
    if(!preg_match($regexp, $bis)) // Gültigkeit bis
      die("invalid plz bis");

    // jemand, der C++ programmiert, würde mir aufs Dach steigen:
    if($von > $bis) // Intervall mathematisch korrekt
    {
      //die("invalid interval"); // böse sein, oder mitdenken
      swap($von, $bis); // muss ich nicht erklären
    }
  }
}

// assert([$von, $bis] ist gültiges PLZ-Intervall);
 
Zuletzt bearbeitet:
hi theHacker,

ich wollt auch nur kurz anreißen wie ich es vom prinzip her mache...
aber danke für den ausführlichen beitrag, denn genau das meinte ich auch mit validierung.

jedoch muss das die() ja nicht unbedingt sein, das script soll ja nicht bei jedem fehler abgebrochen werden. ne fehlermeldung an den user ist da besser
 
Zuletzt bearbeitet von einem Moderator: