[mysql] Tabelle mit mehreren Untertabellen

Hallo zusammen,

aktuell bin ich dabei, einen "kleinen" Onlineshop zu schreiben.
Beim Erstellen der (mysql)Datenbank habe ich aktuell aber ein Problem.
Um es nicht allzu ausführlich zu machen, vereinfache ich das Ganze und schreib nur das Wesentlichste.

Und zwar:
Ich habe folgende Tabellen
Arbeitsspeicher (ArtNr, Bez, Takt, Preis, Größe, ...)
Grafikkarte (ArtNr, Bez, Chip, Preis, Speicher, ...)
Bestellungen (BestNr, ArtNr, ...)

Jetzt möchte ich in der Tabelle "Bestellungen" mit der ArtNr an "Arbeitsspeicher" bzw. "Grafikkarte" verweisen.
Wenn ich dazu einen Fremdschlüssel auf die beiden Artikeltabellen setze, muss die ArtNr die in "Bestellungen" eingetragen wird in beiden Tabellen vorhanden sein. Das ist aber nicht immer der Fall, da ich z.B. 2 Datensätze in Arbeitsspeicher und 3 in Grafikkarte habe.

Um das ganze mal Beispielhafter zu machen, wie ich es am Ende haben will:
Code:
Arbeitsspeicher          Grafikkarte                   Bestellungen
ArtNr|Bez|...            ArtNr|Bez|...                 BestID|ArtNr
A1   |Kingston |...      G1   |nVidia|...             1       | A1
A2   |Corsair  |...      G2   |ATI   |...             2       | G1
A3   |Kingston |...                                   3       | G2
Hier meckert die mySQL-Workbench immer und sagt: "A1 ist nicht in 'Grafikkarte' vorhanden", was ja auch logisch ist.

Irgendwie komme ich hier jetzt aber nicht weiter. Die SuFu(hier und google) habe ich schon genutzt, bin aber zu keinem Ergebnis gekommen.

Die einzige Möglichkeit die mir einfällt ist die, dass ich einfach keine Fremdschlüssel in "Bestellungen" festleg.
Was ich aber total unschön find, weil dann ja die Beziehung fehlt....
Alternativ könnte natürlich eine allgemeine "Artikel"-Tabelle verwendet werden, was aber auf Grund der vielen einzigartigen Eigenschaften von "Arbeitsspeicher" etc nicht möglich ist.

Kann mir jemand von Euch vllt. weiterhelfen?

Vielen Dank schon mal :)

Gruß
Darkholylein
 
Warum verwendest du keine View, die in einer Tabelle nur die Dinge darstellt, die du aus den anderen Tabellen für den Bestellungsdatensatz brauchst? Dann kannst du in der Bestellungen-Tabelle einfach auf die View verweisen.
 
Hallo bitmuncher,

Danke schon mal für Deine Antwort.

Ich habe mich grade mal in Views eingelesen und ein bisschen mit Views rumgespielt.
Bisher habe ich keine Möglichkeit gefunden, eine Spalte im View mit mehreren Tabellen zu verknüpfen.

Ich bekomm immer nur eine Verknüpfung von V.Spalte1 auf Arbeitsspeicher.ArtNr und V.Spalte2 auf Grafikkarte.ArtNr hin. Lässt sich auch V.Spalte1 mit Arbeitsspeicher.ArtNr UND Grafikkarte.ArtNr verknüpfen?
Und wenn ja: Wie? Ich find da irgendwie nix dazu, oder such nach dem falschen Stichwort...

Gruß
Darkholylein
 
Stichwort: mapping-tables.

Wenn ich dich richtig verstanden habe brauchst du eine Many-to-Many Beziehung zwischen "Bestellung" und deinen Artikeltypen. Das sieht dann in etwa so aus:

Code:
Bestellungen
------------
id: int, pk


Grafikkarten       map_Bestellung_Grafikkarte
------------       --------------------------
id: int, pk        id_bestellung: int
name: varchar      id_grafikkarte: int
...


Arbeitsspeicher    map_Bestellung_Arbeitsspeicher
---------------    ------------------------------
id: int, pk        id_bestellung: int
name: varchar      id_arbeitsspeicher: int
...

Wie du siehst, brauchst du für einen Artikeltyp jeweils zwei Tabellen. Eine Tabelle, die die Daten des jeweiligen Typs beinhaltet und eine zweite, welche die Beziehung zu deinen Bestellungen managed.

Mit einem solchem Schema fährst du ohne Redundanz. (Normalisiert.) Die Abfragen werden dementsprechend etwas komplizierter, aber durchaus zu bewerkstelligen. :) Ein Grund weshalb ich ausschliesslich auf das hervorragende Datenbankabstraktionsframework Doctrine setze.
 
Hi,

du könntest eine View über Arbeitsspeicher und Grafikkarten mit union bzw. union all erstellen.

Allerdings möchte ich dir den Tipp geben, dein DB Design nochmal zu überdenken und einen abstrakteren Ansatz zu wählen. Die Union View mag eventuell mit 2 Tabellen noch funktionieren, aber was willst du machen, wenn du irgendwann noch Drucker, Monitore, Telefone und Autozubehör aufnehmen willst?

Ich würde vorschlagen, du machst dein Design der DB etwas anders. Du könntest eine Tabelle Artikel machen, dann eine Tabelle Artikel-Optionen, die du dann in einer Tabelle Artikel-Optionen-Values zusammenführst.

Grüße
DerHesse
 
Ich glaub ich hab dein Problem noch nicht ganz verstanden, aber ich rate mal.

Du könntest einen union-Select meinen, sprich du selektierst Daten aus Grafikkarte und Arbeitsspeicher anhand der ArtNr aus Bestellungen.

Vereinfacht dargestellt könnte das dann in etwa so aussehen:

Code:
select as.ArtNr, as.Bez
from Arbeitsspeicher as
where as.ArtNr in (select bs.ArtNr from Bestellungen bs where bs.BestID = 1)
union all
select gk.ArtNr, gk.Bez
from Grafikkarte gk
where gk.ArtNr in (select bs.ArtNr from Bestellungen bs where bs.BestID = 1)

Ob sowas natürlich funktioniert hängt davon welche Spalten du selektieren willst bzw. deren Datentypen. Die Spaltenanzahl und die Datentypen müssen bei beiden Selects gleich sein. Näheres dazu verrät dir aber mit Sicherheit auch Google.

Edit: Ne Sekunde zu langsam, fu :)
 
An die union-select-Vertreter hier:

  1. Das funktioniert nur, wenn keine zwei gleiche Keys in den jeweiligen Artikeltyptabellen vorkommen. Ansonsten besteht die Gefahr Grafikkarten sowie als auch Rambausteine zu selektieren!
  2. Unter der Annahme, dass auf jedem Fall FK's verwendet werden sollen funktionieren die genannten union-selects nicht.

Ich rate daher dringend vor Unions ab.
Btw: Union selects deuten meist (!!) auf eine nicht sauber normalisierte Datenbankstruktur hin. :)
 
Ich rate daher dringend vor Unions ab.
Btw: Union selects deuten meist (!!) auf eine nicht sauber normalisierte Datenbankstruktur hin. :)

Bin ganz deiner Meinung. Manchmal hat man nur blöderweise keinen Einfluss auf die DB Struktur und muss sich dann solche Krücken mit Union zurechtbasteln um an seine Daten zu kommen.
 
Danke she3p, danach habe ich gesucht...

So funktioniert die Datenbank so wie sie soll.

Mit den Abfragen steh ich jetzt auch etwas auf dem Schlauch. Ich möchte mir in einer Liste alle Artikel,die zu einer BestellID gehören in folgendem Format ausgeben lassen:
BestellID, ArtNr,ArtBez, ...

Ich bekomme aber mit SELECTS oder JOINS immer nur hin,dass ich mir:
BestellID, arbeitsspeicher.ArtNr, arbeitsspeicher.Bez, grafikkarte.ArtNr, grafikkarte.Bez
ausgeben lasse...So kann ich es meinem "kunde" ja aber nicht an den Kopf werfen.

Habt ihr da vllt. noch einen Tipp für mich?
Sonst kann ichs nur in einem String-Array speichern und mühsam auseinanderklamüsern,was ich nicht sehr elegant fände.

Danke für eure Hilfe!
 
Ich bekomme aber mit SELECTS oder JOINS immer nur hin,dass ich mir:
BestellID, arbeitsspeicher.ArtNr, arbeitsspeicher.Bez, grafikkarte.ArtNr, grafikkarte.Bez
ausgeben lasse...So kann ich es meinem "kunde" ja aber nicht an den Kopf werfen.

Und hiermit kommen wir zum Nachteil eines solchen Aufbaus. Das Problem ist, dass sich die Artikeltypen in der Theorie beliebig unterscheiden können. So ist es zum Beispiel nicht unbedingt gegeben, dass ein Artikeltyp eine Bezeichnung haben muss. Was soll da ausgegeben werden?

Sofern sich deine Artikeltypen in gewissen Dingen ähnlich sind (sprich: gemeinsame Felder aufweisen), so können diese mit einem UNION-SELECT selektiert werden. Der Nachteil dieser Variante liegen auf der Hand: Felder, die nur für einen Artikel definiert wurden, lassen sich nicht in eine einzige Query einbinden. Die zweite Möglichkeit wäre ein wenig aufwändiger (und m.E. unschöner): Du selektierst für jeden Artikeltypen alle bestellten Artikel. (In einer eigenen Query). Ist unflexibel und bedeutet einen ziemlich hohen Aufwand, falls ein neuer Artikeltyp hinzukommt. Und dann gibt es da noch die Möglichkeit, die Doctrine fährt.

Das eigentliche Problem liegt hier nicht im Aufbau des Schemas, sondern stellt eine Einschränkung dar, die die Verwendung von relationalen Datenbanken mit sich bringt.

Relational databases don't support inheritance, so when mapping from objects to databases we have to consider how to represent our nice inheritance struc-tures in relational tables.
Source: P of EAA

Ich weiss, dass in die Verwendung von Table Inheritance in Doctrine emuliert wird.

Per Zufall hab ich auch gleich ein Projekt in Arbeit, dass eine ähnliche Sache implementiert: Ich habe einen Typ "Gallery", in welchem ich verschiedene "Media" speichern will. Ein solches Medium ist beispielsweise ein "Image" oder ein "Video". Im abstrakten Typ "Media" muss ich, damit Doctrine mein Anliegen versteht, eine sogenannte Discriminator-Map definieren. Sie enhält das Mapping von Type-Strings zu Tabellen (oder in meinem Fall Entitäten). Die Map sieht in diesem Fall so aus:

Code:
 * @ORM\DiscriminatorMap({
 *     "image" = "Namespace\Entity\Media\Image",
 *     "video" = "Namespace\Entity\Media\Video",
 * })

Selektiere ich nun die "Gallery" mit der ID 1 führt er mir folgende Query aus:

Code:
SELECT 
  t0.id AS id1, 
  t0.created AS created2, 
  t0.updated AS updated3, 
  t0.discriminator, 
  t4.caption AS caption5, 
  t4.path AS path6 
  t7.url AS url7
FROM 
  media t0 
LEFT JOIN 
  media_images t4 ON t0.id = t4.id 
LEFT JOIN 
  media_videos t7 ON t0.id = t7.id 
INNER JOIN 
  map_gallery_media ON t0.id = map_post_media.media_id 
WHERE 
  map_gallery_media.gallery_id = 1

Er LEFT-JOIN'd also alle, in der Diskrimator-Map vorkommenden Tabellen in einem grossen Select, und bereitet mir anschliessend das Ganze softwaretechnisch wieder auf. (Er retourniert eine ArrayCollection mit Objekten vom abtrakten Obertyp "Media").

Dies ist allerdings nur die JOIN-Strategie. Weitere sind in der offiziellen Dokumentation zu Inheritance Mapping zu finden.

tl;dr: Du wirst um ein wenig Arbeit auf Seiten deiner Software-Lösung leider nicht herumkommen, da relationale Datenbanken Table-Inheritance nicht von Haus aus unterstützen. Was rate ich dir?

  1. Sieh dir Doctrine an, und nutze die eingebaute Unterstützung für Table-Inheritance.
  2. Es gibt natürlich noch das weite Feld der nicht relationalen Datenbanken (noSQL). Da stellt sich dieses Problem nicht. (Von der Entwicklung von Hydrators/Proxies mal abgesehen :)) Ich habe bisher erst mit MongoDB gearbeitet und kann dir daher keine repräsentative Vergleiche ziehen.
  3. Entwickle das ganze nach der zweiten Möglichkeit, die ich eingangs erwähnt habe: Alle Artikeltypen nacheinandern selektieren. :)

Das ganze Problem übrigens sauber aufgearbeitet findet sich u.a. hier: Product Catalog — MongoDB Manual
 
Zuletzt bearbeitet:
Hey she3p,
dickes Danke für den vielen Text und deine Hilfe.

Sobald ich deine Möglichkeiten testen konnte, melde ich mich wieder über Erfolg/Misserfolg.

Gruß Darkholylein
 
Zuletzt bearbeitet:
Zurück
Oben