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
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
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)
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
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.
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 ;-)
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.
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.
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
> 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...
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
> 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.
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
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.
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