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