Re: MySQL Tabelle richtig auslesen
- From: Dominik Echterbruch <news_de@xxxxxxxxxxxxx>
- Date: Tue, 25 Aug 2009 01:29:20 +0200
Sebastian Neubert wrote:
Leider habe ich neben folgender Syntax
noch andere Tabellen, die ich dazupacken muss. Inzwischen ist es ein
richtiges Monster, welches ich nicht mehr gebändigt bekomme:
Gewöhn dich dran. Damit wirst du jetzt arbeiten müssen.Ich hoffe, du hast schon gefrühstückt, sonst wird dir beim Lesen vermutlich ein wenig schlecht ;)
FROM nml_articlecontent a, nml_article article, nml_articlerev arev
LEFT JOIN nml_articlecontent b ON b.nlac_arevid = a.nlac_arevid AND
b.nlac_ctid = 6
Den Hinweis hierzu hat Christian ja bereits wiederholt.
Fehlermeldung:
ERROR: #1054 - Unknown column 'a.nlac_arevid' in 'on clause'
Versteh ich nicht, da die Syntax IMHO richtig ist und es die Spalte
"nlac_arevid" in der Tabelle A wirklich gibt.
Ja und nein. Ja, in der Tabelle, von der du redest, gibt es die Spalte tatsächlich. Und nein, MySQL weiß das noch nicht, weil die Tabelle noch gar nicht hinzugejoint wurde. Das ist diese dumme Geschichte mit dem JOIN und dem Kommaoperator.
AND.article.nla_visibility = 1^^^^^^^
Wenn du an dieser Stelle den Fehler behebst (Hinweis: da ist ein Punkt zu viel), sollte das Statement an sich funktionieren. Allerdings wird das Ergebnis nicht deinen Vorstellungen entsprechen, weil einige Zeilen fehlen.
Ich werde mir wohl erstmal etwas bessere Literatur zu Gemüte führen
muessen um das mit den LEFT JOINs zu verstehen.
OK, ganz kurz gesagt. Dieses hier:
FROM t1, t2 WHERE t2.id = t1.id
entspricht im Prinzip diesem:
FROM t1 INNER JOIN t2 ON t2.id = t1.id
Unterschied ist eigentlich nur, dass letzterer Ausdruck bevorzugt ausgewertet wird und dass er eine nette Abwandlung erlaubt, die ich gleich erkläre. Aber vorweg ein kleiner Ausflug mit dem Hinweis, dass t1 "linke Tabelle" heißt, weil sie in der Notation weiter links steht und t2 aus dem gleichen Grund "rechte Tabelle" heißt.
Man kann sich das Vorgehen von MySQL bei den beiden oben stehenden Ausdrücken etwa so vorstellen:
Nimm aus der linken Tabelle (also t1) den ersten Datensatz und guck in der rechten Tabelle (also t2), ob es einen Datensatz gibt, bei dem die ID mit der des linken Datensatzes übereinstimmt. Findest du rechts keinen Datensatz, verwirf den linken Datensatz. Findest du rechts mehrere solche Datensätze, dupliziere den linken so oft, bis alle Vorkommen in der rechten Tabelle zugeordnet sind.
Dann nimm aus der linken Tabelle den zweiten Datensatz und beginne das Spiel von vorne.
Der wichtige Unterschied zwischen dem INNER JOIN und dem LEFT (OUTER) JOIN ist nun, dass der linke Datensatz nicht verworfen wird, wenn rechts kein passendes Element gefunden wird. Das bedeutet, die Datensätze der linken Tabelle werden immer alle zurück gegeben. Wenn es einen oder mehrere passende Sätze in der rechten Tabelle gibt, wird links wie beim INNER JOIN gearbeitet.
Ist doch etwas länger geworden. Aber nichts im Vergleich zu dem, was sich in Büchern zu dem Thema findet. Aber wenn ich schon dabei bin, hier noch ein kleines Beispiel:
mysql> SELECT * FROM t1;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
mysql> SELECT * FROM t2;
+----+
| id |
+----+
| 2 |
| 4 |
| 6 |
+----+
INNER JOIN ohne Bedingung:
mysql> SELECT * FROM t1, t2;
oder
mysql> SELECT * FROM t1 INNER JOIN t2;
+----+----+
| id | id |
+----+----+
| 1 | 2 |
| 2 | 2 |
| 3 | 2 |
| 1 | 4 |
| 2 | 4 |
| 3 | 4 |
| 1 | 6 |
| 2 | 6 |
| 3 | 6 |
+----+----+
INNER JOIN mit übereinstimmenden IDs:
mysql> SELECT * FROM t1 INNER JOIN t2 ON t2.id = t1.id;
+----+----+
| id | id |
+----+----+
| 2 | 2 |
+----+----+
LEFT JOIN mit übereinstimmenden IDs:
mysql> SELECT * FROM t1 LEFT JOIN t2 ON t2.id = t1.id;
+----+------+
| id | id |
+----+------+
| 1 | NULL |
| 2 | 2 |
| 3 | NULL |
+----+------+
Soooooo, ich hoffe, das hast du nun verstanden. Es gibt noch ein paar mehr JOIN-Typen. Aber dazu tust du dir wirklich besser ein Stück Literatur an. Das füllt quasi ganze Bücher...
Also wieder zurück zu deinem Problem:
Du hast eine Tabelle, in der es Überschriften, Kurztexte und Langtexte gibt. Sowas kann man dann halt mal eben schnell zusammen joinen und gut ist es. Das Problm ist aber, dass es nicht immer alle Elemente gibt. Deshalb geht ein INNER JOIN nicht, weil sonst das Fehlen eines Kurztextes den gesamten Datensatz raus werfen würde. Also ein klarer Fall für einen OUTER JOIN. Ich habe mich aus Gewohnheit - und weil es das Hirn nicht so verrenkt - für den LEFT JOIN entschieden.
Die Abfrage
SELECT a.`text` headline, b.`text` `shorttext`
FROM tabelle a
LEFT JOIN tabelle b ON b.refid = a.refid AND b.type = "shorttext"
WHERE a.type = "headline"
macht also nichts anderes, als alle Datensäätze aus der linken Tabelle (a) zu holen, die vom Typ "headline" sind. Dazu werden dann die passenden Datensätze aus der rechten Tabelle geholt (also die, die die gleiche refid haben und vom Typ "shorttext" sind). Gibt es rechts keinen passenden Satz, wird mit NULL aufgefüllt und fertig.
Angewendet auf dein komplexeres Beispiel kommt folgendes heraus. Es ist ungetestet, ich habe hier und da etwas dazu geraten und es insgesamt nicht komplett verstanden. Also drück die Daumen...
SELECT ac1.nlac_arevid id, a.nla_crdate crdate,
ac1.nlac_text headline, ac2.nlac_text `shorttext`,
ac3.nlac_text leadtext, ac4.nlac_text `text`
FROM nml_article a
INNER JOIN nml_articlerev r ON r.nlar_articleid = a.nla_id
LEFT JOIN nml_articlecontent ac1 ON ac1.nlac_arevid = r.nlar_id
LEFT JOIN nml_contenttype t1 ON t1.nlct_id = ac1.nlac_ctid
AND t1.nlct_type = "headline"
LEFT JOIN nml_articlecontent ac2 ON ac2.nlac_arevid = r.nlar_id
LEFT JOIN nml_contenttype t2 ON t2.nlct_id = ac2.nlac_ctid
AND t2.nlct_type = "leadtext"
LEFT JOIN nml_articlecontent ac3 ON ac3.nlac_arevid = r.nlar_id
LEFT JOIN nml_contenttype t3 ON t3.nlct_id = ac3.nlac_ctid
AND t3.nlct_type = "shorttext"
LEFT JOIN nml_articlecontent ac4 ON ac4.nlac_arevid = r.nlar_id
LEFT JOIN nml_contenttype t4 ON t4.nlct_id = ac4.nlac_ctid
AND t4.nlct_type = "text"
WHERE a.nla_visibility = 1
AND r.nlar_state >= 0
So, da ich schon die Fragezeichen über deinem Kopf vorhersehe, eine kleine Erläuterung dazu.
Zunächst mal interessieren uns generell alle Artikel. Daher steht diese Tabelle im FROM-Teil. Allerdings bitteschön nur diejenigen, die auch freigegeben und sichtbar sind. Daher der INNER JOIN, der die ünnützen Zeilen aus der linken Tabelle entfernt und die beiden Bedingungen im WHERE-Teil.
Jetzt möchten wir gerne die Inhaltselemente. Allerdings soll dabei der Artikel auch dann erhalten bleiben, wenn es in der rechten Tabelle keinen passenden Datensatz gibt. Daher der LEFT JOIN.
Dummerweise steht aber in der Inhaltstabelle nicht der Typ der Daten drin, sondern nur eine Referenz darauf. Um nun nicht den ganzen Artikel zu verlieren, falls es das Inhaltselement nicht gibt, auch hier einen LEFT JOIN auf die Typen-Tabelle. Dabei die Einschränkung auf den richtigen Typ und den Artikel nicht vergessen (beides im ON-Teil des jeweiligen JOINs).
Und weil der Typ bei jeder der Inhaltselemente unterschiedlich ist, muss die Typentabelle jedes Mal neu dazu gejoint werden.
Ich werde das jetzt mal überschlafen, während du beim Kaffee versuchst, dem ganzen Geschreibsel zu folgen.
Grüße,
Dominik
--
Wo kämen wir hin, wenn alle sagten, wo kämen wir hin, und niemand
ginge, um einmal zu schauen, wohin man käme, wenn man ginge.
Autor: Kurt Marti (http://de.wikiquote.org/wiki/Kurt_Marti)
.
- Follow-Ups:
- Re: MySQL Tabelle richtig auslesen
- From: Sebastian Neubert
- Re: MySQL Tabelle richtig auslesen
- References:
- MySQL Tabelle richtig auslesen
- From: Sebastian Neubert
- Re: MySQL Tabelle richtig auslesen
- From: Dominik Echterbruch
- Re: MySQL Tabelle richtig auslesen
- From: Sebastian Neubert
- Re: MySQL Tabelle richtig auslesen
- From: Dominik Echterbruch
- Re: MySQL Tabelle richtig auslesen
- From: Sebastian Neubert
- MySQL Tabelle richtig auslesen
- Prev by Date: Re: MySQL Tabelle richtig auslesen
- Next by Date: Re: MySQL Tabelle richtig auslesen
- Previous by thread: Re: MySQL Tabelle richtig auslesen
- Next by thread: Re: MySQL Tabelle richtig auslesen
- Index(es):
Relevant Pages
|