Mailinglisten-Archive |
On Wed, Sep 13, 2000 at 09:41:43PM +0200, Jan Kunzmann wrote:
> Hi Jens,
Moin. Mein Gott, so eine ausführliche Antwort habe ich gar nicht erwartet.
Danke, danke :-))
> Jens Benecke wrote:
> > ich muss eine relativ grosse Abfrage über drei Tabellen realisieren, ohne
> > daß mir mein Provider wegen Ressourcen aufs Kreuz steigt. Gibt es zu
> > folgendem Code eine Alternative, die _nicht_ erst eine komplette temporäre
> > Tabelle mit allen möglichen Kombinationen anlegt und dann anfängt zu
> > filtern?
> Ja. Schon mal was von einem JOIN gehört :)) ? Steht auch im Manual,
Hm, ich bin jetzt naiverweise immer davon ausgegangen, daß das das gleiche
wäre wie untiges, weil es im Manual immer nebeneinander erwähnt wird. ;)
> sowohl im mySQL-Manual als auch in _jedem_ SQL-Manual, da es sich um die
> grundlegende Eigenschaft von Datenbanken handelt, Tabellen in Abfragen
> sinnvoll verknüpfen zu können.
Daß es Joins gibt, wußte ich. Aber dass sie hierfür viel besser geeignet
sind, nicht. Danke.
> Dazu ein bisschen Datenbanktheorie:
> Ein SELECT * FROM A, B macht ein karthesisches Produkt dieser beiden
> Tabellen, verknüpft also zu jeder Zeile in A alle Zeilen in B. Heraus
So sah das mir auch aus. und das ist nicht akzeptabel.
> kommt eine Tabelle mit Count(A) * Count(B) Elementen, die erst danach
> von einer eventuellen WHERE-Klausel wieder geleert wird.
> Mit einem JOIN legst du fest, dass zu jedem Datensatz in A nur die
> Zeilen aus B dazugenommen werden, bei denen eine bestimmte Spalte mit
> einem bestimmten Feld des A-Datensatzes übereinstimmt.
d.h. es wird vorher gefiltert, richtig? Genau das suche ich.
> > Diese Lösung kommt mir als ziemlicher Ressourcenfresser vor. Jedenfalls
> > erzeugt sie mit BIG_TABLES eine Temporärdatei von ca. 1.5GB Grösse ...
> >
> > ---------------------------------------------------------------------------
> > SELECT h.id, h.stadt1, h.stadt2, h.stadt3, s.id, s.name, ss.id, ss.name,
> > sss.id, sss.name from h, staedte as s, staedte as ss, staedte as sss
> > WHERE (.......) AND s.id=h.stadt1 AND ss.id=h.stadt2 AND sss.id=h.stadt3
> > ORDER BY {je nachdem s.name, ss.name oder sss.name} ;
> > ---------------------------------------------------------------------------
>
> Wie wäre es mit:
> SELECT h.id, h.stadt1, h.stadt2, h.stadt3, s1.id, s1.name, s2.id,
> s2.name, s3.id, s3.name FROM ((h INNER JOIN stadt AS s1 ON
> h.stadt1=s1.id) INNER JOIN stadt AS s2 ON h.stadt2=s2.id) INNER JOIN
> stadt AS s3 ON h.stadt3=s3.id WHERE (........) ORDER BY (....);
wenn es das gleiche Ergebnis zurückliefert, bin ich mehr als zufrieden.
> Bevor die WHERE-Klausel zur Anwendung kommt, enthält die temporäre
> Tabelle jetzt genauso viele Datensätze wie h zuvor, denn der JOIN geht
> jeweils auf das ID-Feld der Stadt-Tabelle (und das sollte ja nur einen
> Datensatz ergeben), also ist PRO Zeile in A mit 1 * 1 * 1 = 1 Datensätzen
> zu rechnen.
Super.
> Beachte, dass die INNER JOINs nur dann eine Zeile zurückliefern, wenn
> h.stadt1 und h.stadt2 und h.stadt3 gültige IDs aus der Tabelle stadt
> enthalten! Sollte in einer Zeile von h das Feld s3 einen Wert enthalten,
Das ist gewährleistet, denn die Datenbank wird mit HTML Forms gefüllt und
die Auswahlmöglichkeiten für die <SELECT> Tags kommen ebenfalls aus der DB,
zusätzlich wird nach dem Submit noch mal eine "Gegendarstellung" zur DB
gemacht.
> der nicht in stadt.id auftaucht, dann liefert die Abfrage für _diese_
> Zeile von h genau 1 * 1 * 0 = 0 Datensätze zurück. Keine Angst, die
d.h. Datensätze, die eine falsche Stadt-id enthalten, werden _garnicht_
zurückgeliefert, richtig? Damit kann ich leben.
> Um diese Problematik zu umgehen, gibt es den LEFT JOIN, den du statt dem
> INNER JOIN verwenden kannst. Im eben genannten Beispiel würde bei einem
> LEFT JOIN die Werte von s3.id und s3.name auf NULL gesetzt, daher ergäbe
> sich für diese Zeile in h wieder 1 x 1 x 1 = 1 Datensätze, und die
> resultierende Tabelle hat wieder genau h Zeilen.
Noch besser. Jetzt muss ich mir dann nur noch einfallen lassen, wie ich
dann mit solchen Datensätzen umgehe, den gerade weil sie nie auftreten
_dürften_, werden sie es garantiert tun. ;))
Nochmals vielen Dank für Deine Hilfe!
--
`Man sollte dem Verantwortlichen für ILOVEYOU alles http://www.linuxfaq.de
mögliche antun, aber wahrscheinlich wird bloß http://www.hitchhikers.de
seine Firma zweigeteilt." -- Usenet http://www.pinguin.conetix.de
php::bar PHP Wiki - Listenarchive