Mailinglisten-Archive |
Hi Jens, 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, 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. 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 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. > 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 (....); 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. 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, 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 anderen Zeilen von h sind davon nicht betroffen, so dass die resultierende Tabelle dann eben h-1 Datensätze enthält (oder eben soviele weniger, bei denen der JOIN nicht geklappt hat) 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. Alle Klarheiten soweit beseitigt? :) Gruß JAn --- *** Weitere Infos zur Mailingliste und MySQL unter www.4t2.com/mysql
php::bar PHP Wiki - Listenarchive