Forum: PC-Programmierung Datenbank - n:m Beziehungen stets sinnvoll?


von Jan (Gast)


Lesenswert?

Hallo,

ich habe eine Frage zu n:m-Beziehungen bei Datenbanken.
Laut meinen Recherchen nutzt man diese, sobald Datensätze aus 2 Tabellen 
gegenseitig mehrfach in Beziehung zueinander stehen können. Ich frage 
mich nun, ob man n:m-Beziehungen in solchen Fällen grundsätzlich IMMER 
benutzen sollte, oder ob es durchaus Situationen gibt, in denen man gut 
darauf verzichten kann?

Als Beispiel denke ich an einen Arzt, der zu jedem Patienten die Rezepte 
inklusive der verschriebenen Medikamente speichert:
Auf einem einzelnen Rezept können verschiedene Medikamente aufgelistet 
sein, gleichzeitig kann ein einzelnes Medikament aber auch auf 
verschiedenen Rezepten vorkommen.

Mit meiner autodidaktischen Datenbank-Erfahrung würde ich vermuten, dass 
hier eine klassische n:m-Beziehung vorliegt. Aber ist diese auch immer 
sinnvoll?

Mir leuchtet ein, dass man in der Regel wohl ein Rezept eines Patienten 
aufruft, um nachzusehen, welche Medikamente man diesem verschrieben hat. 
Die andere Richtung - also ein einzelnes Medikament auszuwählen und dann 
eine Liste mit Rezepten zu erhalten, auf dem dieses vorkommt - scheint 
mir im User-Interface einer derartigen Datenbank-Anwendung kein so 
häufiger Anwendungsfall zu sein. Eventuell für den Fall, dass es eine 
Rückrufaktion für ein bestimmtes Medikament gibt und man nun alle 
betroffenen Patienten warnen möchte...wobei ich denke, dass man das auch 
über eine Select-Anweisung mit entsprechenden Bedingungen erreichen 
könnte.

Gibt es gute Gründe, IMMER eine n:m-Beziehung zu verwenden, wenn die 
realen Begebenheiten diese Möglichkeit teoretisch vorsehen?

Viele Grüße
Jan

von Georg (Gast)


Lesenswert?

Jan schrieb:
> Als Beispiel denke ich an einen Arzt, der zu jedem Patienten die Rezepte
> inklusive der verschriebenen Medikamente speichert:

Das Beispiel ist gut gewählt, weil der Zugriff über das Medikament eben 
weit weniger häufig ist, das kann man wenns doch mal sein soll über 
einen Suchlauf lösen. Dabei betrachte ich jetzt nicht die 
"Krankenkassen-Optimierungs-Strategien", die dem Arzt gegen Monatsende 
raten, mehr von dem einen und weniger von einem anderen Medikament zu 
verschreiben, das hat ja mit Medizin wenig zu tun. Ist aber wohl 
trotzdem weit verbreitet.

Anderes Beispiel: Rechnung - Kunde. Primär für die Buchhaltung ist die 
Rechnung (nach Rechnungsnummer), aber über den Kunden auf alle seine 
Rechnungen zuzugreifen (und zwar sofort) ist ebenso lebenswichtig, etwa 
bei einer Neubestellung festzustellen, ob er denn seine fälligen 
Rechnungen auch bezahlt hat.

Aber Vorsicht, was akademische Datenbanktheoretiker unbeachtet lassen: 
eine einmal ausgestellte Rechnung zu verändern ist VERBOTEN, also darf 
sich die Anschrift auf bereits vorhandenen Rechnungen nicht ändern, wenn 
im Kundendatensatz eine neue Anschrift eingetragen wird. Die Anschrift 
zum Datum der Rechnung muss mit dieser abgespeichert werden. Natürlich 
gibt es auch seriöse Gründe, Rechnungen nachträglich zu ändern, aber bei 
einer genehmigungsfähigen Buchhaltung darf dies nur durch Stornierung 
und Ausstellung einer neuen Rechnung geschehen. Egal was die 
Datenbanktheorie dazu sagt.

Georg

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Jan schrieb:
> Gibt es gute Gründe, IMMER eine n:m-Beziehung zu verwenden, wenn die
> realen Begebenheiten diese Möglichkeit teoretisch vorsehen?

Ich verstehe dein Problem nicht ganz, das liegt aber vermutlich daran 
dass ich nicht weiss wie deine Alternative aussähe (am beispiel 
Patient-medikament)

von Sascha S. (excess)


Lesenswert?

Guten Morgen Jan,

ich sehe es nicht so, dass man immer n:m Beziehungen modellieren sollte. 
N:M Beziehungen sind nach meiner Auffassung in relationalen Datenbanken 
immer mit JOIN-Tabellen verbunden, d.h. die hast zwei Tabellen mit 
"echten" Daten (z.B. Patient und Rezept) und eine Tabelle mit zwei 
Spalte, welche die beiden Tabellen verknüpft (z.B. Tabelle 
patient_rezept mit den Spalten patientId und rezeptId).

An deinem Beispiel lassen sich gut verschiedenen Beziehungstypen 
erklären. Ich sehe es so:

- Patient -> Rezept: 1:n Beziehung (ein Patient hat im Laufe seinen 
Lebens mehrere Rezepte. Ein Rezept gehört immer zu einem Patient und 
kann nicht ohne ihn existieren.)
- Rezept -> Medikament: n:m Beziehung (ein Rezept hat mehrere 
Medikamente und ein Medikament wird in vielen Rezepten gelistet.)
- Rezept -> Arzt: n:1 Beziehung (viele Rezepte werden durch einen Arzt 
ausgestellt)

In den Fällen 1:n und n:1 würde ich keine n:m Beziehung in Form ein JOIN 
Tabelle modellieren. Zusätzliche und fachlich unbegründete JOIN-Tabellen 
machen deine SQL-Abfragen und den Programmcode komplexer und wenn es 
sich um mehrere 10-100 Millionen und mehr Datensätzen handelt, auch 
langsamer.

VG, Sascha

von LeTroisDaDingsbums (Gast)


Lesenswert?

Ich verstehe deine Frage nicht so wirklich, da du diese meiner Meinung 
nach ja schon selbst beantwortest:
- Du weißt, dass eine Indextabelle die "Best Practice" ist
- Du hast erkannt, dass es in bestimmten Fällen auch anders gehen kann, 
dies jedoch mit einem "Preis" der deutlich erschwerten Abfragbarkeit in 
die "andere Richtung" kommt

=> Wie du somit bereits erkannt hast, kommt es auf den Einzelfall an, zu 
klären, ob es tatsächlich sinnvoll ist, den (geringen bis sehr geringen) 
Mehraufwand (Speicher und Ausführungszeit) für die "Best Practice" 
einzusparen, um im Zweifelsfall viel Aufwand in eine inverse Abfrage zu 
investieren. Bei Wald-und-Wiesen-Anwendungen wie einer 
Patientendatenbank beim Arzt würde ich persönlich hier nicht einmal 
einen Gedanken daran verschwenden und aus Gründen der Wartbarkeit und 
Übersichtlichkeit die "richtige" Lösung wählen, da hier die Anzahl der 
SELECTs pro Sekunde eher überschaubar sein sollte, und den eingesparten 
Entwicklungsaufwand lieber in das richtige Definieren der Schlüssel 
investieren.
Und wenn es um hocheffiziente Anwendungen wie z. B. den Newsfeed auf den 
Profilseiten bei Facebook, Twitter o. ä. geht, greift man i. A. zu 
Pufferstrategien, basierend auf Key-Value-Speichern wie memcached, einer 
zusätzlichen NoSQL-DB etc., und optimiert nicht extrem an der SQL-DB 
durch besonders trickreiche Abfragen herum.

von LeTroisDaDingsbums (Gast)


Lesenswert?

Ich vergaß: Eine zusätzliche Tabelle schafft natürlich ein zusätzliches 
Inkonsistenzrisiko; aber da - keine Frage! - jeder DB-Entwickler 
ausführlich mit Transaktionen arbeitet und alle möglichen 
Fehlerbedingungen korrekt behandelt und die inkonsistenten Zustände 
rollbacked, gibt es hier keine Probleme ;-)

von Hans (Gast)


Lesenswert?

Jan schrieb:
> Gibt es gute Gründe, IMMER eine n:m-Beziehung zu verwenden, wenn die
> realen Begebenheiten diese Möglichkeit teoretisch vorsehen?

Die Frage ist, was wäre denn die Alternative?

Bei einer n:m-Beziehung in SQL hast Du drei Tabellen:

Rezept
Rezept_ID Patient_ID Kommentar
123       37         Erkältung
124       99         Grippe
125       42         Hypochonder
...

Medikament
Medikament_ID Name
3             Paracetamol
4             Schleimlöser
5             Zuckerkugeln
...

Rezept_Medikament
Rezept_ID Medikament_ID
123       4
124       3
124       4
125       5
...

Wenn Du auf die Zuordnungstabelle "Rezept_Medikament" verzichten willst, 
bräuchtest Du entweder in Tabelle "Rezept" eine Spalte "Medikament_ID" 
oder in "Medikament" eine Spalte "Rezept_ID". In die Spalte passt aber 
zu einem Eintrag nur ein Wert. Also könnte ein Rezept nur ein Medikament 
enthalten bzw. ein Medikament nur auf einem Rezept verschrieben werden. 
Das entspricht nicht der Realität.

Du müsstest also Umwege finden, z.B. in der Rezept-Tabelle mehrmals das 
gleiche Rezept mit unterschiedlicher Medikament_ID eintragen. Oder in 
der Medikament-Tabelle jedes Medikament duplizieren, wenn es einem 
Rezept zugeordnet wird. Das kann man machen, sollte dafür aber sehr gute 
Gründe (Performance) haben, denn es macht das Datenbankschema NICHT 
einfacher, nur weil weniger Tabellen vorhanden sind. Beim Erstellen von 
anderen Abfragen als dem Hauptanwendungsfall fällt einem das schnell 
wieder auf die Füße.

Man könnte theoretisch auch für die ID-Felder einen anderen Datentyp 
nehmen, in dem sich mehrere IDs speichern lassen (z.B. als Text oder 
Blob). Dann kann man allerdings einen Großteil der Vorteile einer 
Datenbank (SQL, Indizes, Konsistenz, ...) nicht mehr sinnvoll nutzen. 
Mir fällt kein Anwendungsfall ein, in dem das Vorteile bringen könnte.

von perpendicular (Gast)


Lesenswert?

Kurze Antwort: jein.
Ja: Man ist flexibler, vor allem wenn weitere Anforderungen hinzukommen.
Nein: Wenn du weisst dass deine Anforderungen fix bleiben, dann kannst 
du die ein oder andere Beziehung auch 'hart' abbilden.

Hängt auch von den Fähigkeiten deiner DB ab, da kann man dann u.U. auch 
vieles mit entspr. speziellen Datenstrukturen die DB anbietet erschlagen 
ohne sich in den Fuss zu schiessen wenn weiter Anforderungen kommen.
Ist auch Erfahrungssache wann man auf eine weitere n:m Beziehung 
verzichtet und das einfach 'hart' abbildet.

Faustregel ist: Gewisse Entitäten die evt. noch mit anderen Entitäten in 
Beziehung stehen könnten (obwohl das erst mal laut Anforderungen gar 
nicht gefordert ist) bildet man so flexibel wie möglich ab, 'spezielle' 
Entitäten die auch bei weiteren Anforderungen zu nichts anderem in 
Beziehung stehen werden bildet man dann eben 'fest' ab, dann bleibt es 
übersichtlicher.

von Sascha S. (excess)


Lesenswert?

Ich muss mich auch nochmal zu Worte melden. :-)

Ob eine Relationstabelle / JOIN-Tabelle generell zwischen zwei Entitäten 
immer "Best Practice" und "die richtige Lösung" bezweifle ich. Gerade 
wenn es starke Bindungen sind, wie bei einer Komposition / 
Part-of-Beziehung, ist eine Relationstabelle aus meiner Sicht nicht 
sinnvoll. Die Beziehung Rechnung und Rechnungszeile würde ich als solche 
einstufen.

Man sollte beachten, dass man bei n:m Beziehung nicht so einfach mit 
cascade delete arbeiten kann, wenn die m-Seite mit gelöscht werden soll 
(owned). Löscht man ein Element (mit SQL) aus der n-Seite, so kann man 
mittels cascade-delete zwar die Einträge in der Relationstabelle 
löschen, aber die Entität auf der m-Seite bleibt bestehen. Hier braucht 
man dann entweder Code in der Anwendung, der sicherstellt, dass auch die 
Entitäten der m-Seite gelöscht werden oder Datenbank Triggers. Das macht 
die Sache unnötig komplex. OK, wenn man OR-Mapping Tools verwendet, 
braucht man sich darum nicht kümmern. :-)

Ich würde auch referenzielle Integrität nicht mit Transaktionen in einen 
Topf werfen. Zur Sicherstellung, dass bestimmte ID-Spalten nicht ins 
Nirvana zeigen, gibt es Fremdschlüssel - sofern deine DB-Engine das 
kann. Transaktionen dienen m.M. nach dazu, die fachliche Korrektheit 
sicherzustellen (mehrerer DB-Operationen atomar durchführen). Ein 
Beispiel ist hier eine Überweisung einer Bank bestehend aus den 
Operationen Abbuchen und Raufbuchen.


Just my 2 cents,
Sascha

: Bearbeitet durch User
von Noch einer (Gast)


Lesenswert?

> Wenn Du auf die Zuordnungstabelle "Rezept_Medikament" verzichten willst

Umgekehrt. Du verzichtest auf die Tabelle "Medikament" und schreibst in 
die Tabelle "Rezept_Medikament" den Namen statt die ID.

Da muss man abschätzen, in welche Richtung sich das Programm entwickelt.

Möglicherweise kommt noch eine Spalte Unverträglichkeit dazu. Zunächst 
einfach ein unstrukturierter Text. Bei jedem Rezept wird redundant der 
aktuelle Warntext abgespeichert. Dann verkaufen die Vertriebler ein 
Modul zur Beratung über Unverträglichkeit mit früheren Rezepten...

von Wilhelm S. (wilhelmdk4tj)


Lesenswert?

Hallo zusammen.

Vorab - bevor es Haue gibr - ich kann kein SQL.

> das richtige Definieren der Schlüssel

wie oben beschrieben ist die Sache.

Es muss ja nun mal erst eine Stammdatei geben.
Wenn diese dann die entsprechenden, nötigen Schlüssel enthält,
ist es doch kein Problem, die weiteren Verknüpfungen darzustellen.
Es ist wichtig, sich vorher Gedanken darum zu machen, was diese
Datenbank machen soll. Sie soll doch eine Arbeit vereinfachen,
schneller und besser machen. Dazu gehört, sich den Arbeitsablauf
klar zu machen.

Ich will 1., 2., 3., .....

Das Beispiel mit den Patienten, Rezepten und Medikamenten ist
eigentlich ganz treffend.
Auch den Hinweis, das man manche Dinge hart (sprich Feld) oder
besser weich (Verknüpfung) sollte man beachten.
Es gibt sinnvolle Verknüpfungen und weniger sinnvolle.
Wenn das ganze System aber sinnvoll angelegt ist (richtige Schlüssel),
ist es auch kein Problem, spätere Erweiterungen anzuhängen.

Ich selber habe für eine Apotheke ein Programm für die Verwaltung
der Betäubungsmittel (BTM; Opium ... uiii...) geschrieben. Der Standard 
war eine Kartei auf Karteikarten.  Ich war die Schreiberei satt.

Für die 'elektronische Kartei' gibt es eine Stammdatei, eine
für die BTMs, eine für den Patienten, eine für den Lieferanten und
eine für den verordnenden Arzt.
In der Stammdatei gibt es Felder für die Verknüpfung zu den anderen
Datenbanken.

Arbeitsgang Eingabe:
Datum, Lieferant, BTM und MengeEin

Arbeitsgang Abgabe:
Datum, BTM, Patient, Arzt, MengeAus

Vom Gesetzgeber gefordert ist ein monatlicher Ausdruck, was
im jeweiligen Monat passiert ist. Also werden beim Drucken die 
erforderlichen Verknüpfungen erstellt und das ganze zu
Papier gebracht.
Ich habe es nur verkürzt  beschrieben, aber das ist der
Grundarbeitsgang.

JOIN Tabellen habe ich nie gebraucht.

Nicht zu vergessen: zum Schluss aufräumen!
Allen Schutt löschen, den man zwischendurch erzeugt hat!

Ich kann nicht Windooffs. Der ganze Kram funktioniert seit 9 Jahren
unter dBase/Clipper


73
Wilhelm

von Noch einer (Gast)


Lesenswert?

> Es gibt sinnvolle Verknüpfungen und weniger sinnvolle.

Dummerweise haben da Vertriebler, Verschriftenerfinder, Anwender und 
Entwickler vollkommen unterschiedliche Ansichten.

Die für zukünftige Erweiterungen erforderlichen Verknüpfungen kannst du 
nur vorhersehen, wenn du keinen Vertrieb hast und selbst mit deinem 
Programm arbeitest. Und wenn dich die Vorschriftenerfinder in Ruhe 
lassen.

von Georg (Gast)


Lesenswert?

Wilhelm Schürings schrieb:
> Vom Gesetzgeber gefordert ist ein monatlicher Ausdruck, was
> im jeweiligen Monat passiert ist. Also werden beim Drucken die
> erforderlichen Verknüpfungen erstellt und das ganze zu
> Papier gebracht.

Da fangen dann die parktischen Probleme an, im Gegensatz zur 
Datenbank-Theorie: wenn seit der Ausgabe an den Stammdaten von Arzt oder 
Patient was geändert wurde, wird ein Ausdruck erzeugt, der nicht mit dem 
am Tag der Ausgabe übereinstimmt. Ich fürchte, das ist bei so einem 
Thema wie Betäubungsmitteln nicht zulässig. Von Fragen nach dem Löschen 
von Datensätzen usw. mal ganz abgesehen, sonst ermöglicht es das 
Programm, kiloweise Heroin an der Aufsicht vorbeizuschleusen.

Georg

von Noch einer (Gast)


Lesenswert?

Wo ist das Problem?

Du hast eine 1:n Beziehung zwischen Patient und Stammdaten. Die 
Stammdaten haben als Primärschlüssel Patientenid und Datum. Nach 
Datenbanktheorie ganz einfach. Ausgabebeleg soll Patientenid und Datum 
als Fremdschlüssel haben.

Probleme entstehen doch eher, weil so etwas meist nicht nach Theorie 
modelliert wird. Weil da irgendwas mit Stammdaten.Datum <= 
Ausgabebeleg.Datum zurecht getrickst wird.

von Wilhelm S. (wilhelmdk4tj)


Lesenswert?

Hallo zusammen, Hallo Georg.

Das hast du absolut recht. Ich habe in meinem Programm auch keine
Routine, in der man die ursprünglichen Daten des Arztes oder
Patienten ändern kann.

Ich habe solche Zeitgenossen, die in all den Jahren mehrmals
umgezogen sind. Also existieren diese Patienten auch entsprechend oft.

Auf der anderen Seite relativiert sich die Sache dadurch, dass man den
'Papierkrieg' sprich Ausdrucke nur 3 Jahre aufbewahren muss.
Also ist alles älter als 3 Jahre eigentlich nicht mehr wichtig.
Auf der anderen Seite: die paar Datensätze zu verwahren, tut auch
nicht weh.

Jeden Monat ausdrucken und vom Chef zu unterschreiben, so steht
es in der Betäubungsmittelverschreibungsverordnung. Ja, so
heisst dieses Teil.
Für den Amtsapotheker ist auch nur das 'Papier' wichtig.
Er wirft einen Blick drauf, und wenn ihm das plausibel erscheint, wird
es abgenickt. Man selber hat natürlich den Stress, die Bestände müssen
stimmen. Eigentlich sind es immer falsche Eingaben, aber die Fehler
muss man dann finden.

Diese Art der DB hat natürlich den Nachteil, dass man z.B. nach
3 Jahren die alten Datensätze nicht löschen kann, weil dann ja
alle Bezüge verloren gehen.
Ich könnte z. B auch noch die Daten von früheren Jahren zu Papier
bringen, obwohl sie nicht mehr relevant (Papiere weg) sind.

Ich gebe es zu, es sind noch so einige Eseleien im Programm.
Eigentlich müsste ich es nochmal neu schreiben.
Da ich! meistens damit arbeite, ist es für mich nicht schwierig,
Fehler händig mit dBase zu korrigieren.
Das ist aber ja eigentlich nicht der Sinn einer professionell
genutzten Software.
Meine Chefin har grenzloses Vertrauen zu mir -:)


Oh, sorry, ich wollte nicht den Thread von Jan kapern...


73
Wihelm

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.