dedlfix: mysql, Abfrage über zwei Tabellen, Ausgabe verschiedener Titel aus der Tabelle

Beitrag lesen

Tach!

Ja ich denke das ich das gleiche meine, aber genau das ist mein Poblem.

SELECT titel,
(SELECT b.titel FROM Tabelle1 a, Tabelle2 b WHERE b.id = a.zu1) AS ausgabe
FROM Tabelle1
LIMIT 10

Die Subquery benötigt die Tabelle1 (mit Alias a) nicht. Das wäre eine zur Tabelle1 der Hauptquery unabhängige Datenmenge. Sie synchronisiert sich auch nicht derart, dass ein Zugriff auf das Feld a.zu1 dasselbe ist, wie der aktuelle Datensatz der Hauptquery. Stattdessen ermittelt diese Subquery sämtliche Datensätze aus der Tabelle1 und joint dazu die jeweiligen Datensätze der Tabelle 2. Aber eigentlich muss lediglich aus der Hauptquery die ID in zu1 hereingereicht werden. Correlated Subquery nennt man das. Aber mal von vorn:

SELECT title, $zu1, $zu2 FROM ... Das ist der Pseudocode, der erstmal grob darstellt, was du möchtest. Wenn du das in richtiges SQL übersetzt, musst du die beiden Teile $zu1 und $zu2 weglassen. Die kommen später da rein und repräsentieren hier nicht die beiden Felder sondern sind Platzhalter für den jeweiligen Titel.

Nun baust du zunächst den Teil $zu1. Das muss eine Query werden, die für eine zu übergebende ID den Titel aus der Tabelle2 holt. Sehr einfaches SQL. Und du kannst es ausführen, gibst dazu eine händisch eingetragene ID an, und stellst fest, dass das einwandfrei so für sich allein betrachtet arbeitet. Für $zu2 ist das haargenau dieselbe Query - bis jetzt jedenfalls.

Und nun baust du das alles zusammen als Correlated Subquery. Das heißt, statt der händischen ID kommt nun eine Referenz auf die Hauptquery, denn die ID soll aus dem aktuellen Datensatz und dem dortigen Feld zu1 genommen werden. Und genau dasselbe kommt noch für zu2 dazu.

SELECT 
  title,
  (SELECT title FROM Tabelle2 WHERE id = t1.zu1),
  (SELECT title FROM Tabelle2 WHERE id = t1.zu2)
FROM Tabelle1 t1

Der Alias t1 ist hier nur zur Verdeutlichung aber eigentlich überflüssig, weil die Feldnamen zu1 und zu2 bereits eindeutig auf Tabelle1 verweisen.

Der Trick bei anscheinend komplexen Abfragen ist, jeden Teil für sich aufzubauen und nicht zusammenmixen, was nicht zusammengehört. Ziel ist erstmal eine funktionierende Abfrage zu bekommen. Performance-Tricks kann man später auch noch einbauen, wenn dazu Bedarf besteht.

Du siehst hier, dass Tabelle2 zweimal verwendet wurde, jeweils in einer Subquery. Und zwei Verwendungen brauchst du auch, wenn du die Lösung mit Joins bauen möchtest. Man kann nicht aus einer Tabelle einen Wert aus einem Datensatz und gleichzeitig einen anderen Wert aus einem anderen Datensatz in eine Ergebnismenge bringen. Dazu braucht es zwei Referenzen auf diese Tabelle, je eine für je einen Wert. Das sieht dann im Prinzip so aus:

SELECT title, t2zu1.title, t2zu2.title 
FROM Tabelle1 t1
JOIN Tabelle2 t2zu1 ON t1.zu1 = t2zu1.id
JOIN Tabelle2 t2zu2 ON t1.zu2 = t2zu2.id

Durch Joins entstehen verknüpfte Ergebnismengen, die man eigentlich gar nicht haben möchte, und die man deswegen mit geeigneten Bedingungen einzudampfen versucht. Bei Subquerys hingegen entstehen im Prinzip nur genau die Ergebnisse, die man haben möchte. Wenn man genauer hinschaut, dann entsteht da auch erstmal eine größere Menge, die man mit geeignetem WHERE auf einen Datensatz eindampft. Der Unterschied zum Join ist, dass diese Datenmengen (Hauptquery und Subquery(s)) für sich allein entstehen und nicht ein großes kartesisches Produkt bilden. Zumindest theoretisch entsteht dieses Produkt, in der Praxis sorgt hoffentlich der Optimizer dafür, dass es nicht auch noch physikalisch im Speicher angelegt wird.

denn ich bekomme hier die Meldung

Warning: mysqli_query(): (21000/1242): Subquery returns more than 1 row

Ja klar, eine Subquery im SELECT-Teil darf nur ein einzelnes Ergebnis liefern.

dedlfix.