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

Hallo meine Damen und Herren,

ich habe zwei Tabellen

Tabelle1

id!titel!zu1!zu2

1!name!1!2

Tabelle2


id!titel
1!Adam
2!Berta
3!Caesar

nun würde ich gerne die Tabelle 1 abfragen und zu1 und zu2 den jeweiligen Titel aus der 2Tabelle ausgeben.

SELECT titel,zu1,zu2 FROM Tabelle1 LIMIT 10

dann dachte ich, ich versuche es mit eine verschalteten SECELT abfrage

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

Doch leider kein Erfolg: Unterabfrage lieferte mehr als einen Datensatz zurück

mit einem netten Gruß Mike

  1. Tach!

    nun würde ich gerne die Tabelle 1 abfragen und zu1 und zu2 den jeweiligen Titel aus der 2Tabelle ausgeben.

    Genauso, aber einzeln. Das heißt, ein Subselect für zu1 und ein weiteres für zu2.

    Du brauchst sonst eine Mischmenge, die sowohl den zu1-Wert als auch den zu2-Wert in einer Zeile enthält, wenn du mit einem Join oder nur einem Subselect im From auskommen möchtest.

    dedlfix.

    1. 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
      
      

      denn ich bekomme hier die Meldung

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

      Warning: mysqli_error() expects exactly 1 parameter, 0 given in SELECT titel, (SELECT b.titel FROM Tabelle1 a, Tabelle2 b WHERE b.id = a.zu1) AS ausgabe FROM Tabelle1 LIMIT 10

      1. 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.

  2. Hi,

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

    Du fragst im inneren Select unabhängig vom titel aus dem äußeren Select ab, also erhältst Du mehrere Zeilen, nämlich eine für jede Kombination aus Tabelle 1 und Tabelle 2, für die Deine b.id = a.zu1.

    cu,
    Andreas a/k/a MudGuard