Kalle_: LEFT JOIN erzeugt zusätzliche Zeilen

Hallöle,

brüte und probiere seit Stunden und komme nicht drauf. Folgende MySQL- Anweisung erzeugt 71 Zeilen:
SELECT    kon.aussteller_id, adr.bezeichnung ausst, adr1.bezeichnung besu, kon.prio_1, kon.prio_2
FROM      bfp_kontakte kon
LEFT JOIN bfp_adressen adr  ON adr.id=kon.aussteller_id
LEFT JOIN bfp_adressen adr1 ON adr1.id=kon.besucher_id
#LEFT JOIN bfp_kontakte kon1 ON kon1.aussteller_id=kon.aussteller_id AND kon1.prio_1=1
WHERE kon.owner=2 and ( kon.prio_1=1 OR kon.prio_2=1 )
ORDER BY ausst, besu

Nun möchte ich zu diesen Zeilen weitere Spalten, aber mit dem zusätzlichen LEFT JOIN ergeben sich 158 Zeilen, einige davon mehrfach:
SELECT    kon.aussteller_id, adr.bezeichnung ausst, adr1.bezeichnung besu, kon.prio_1, kon.prio_2, kon1.prio_1
FROM      bfp_kontakte kon
LEFT JOIN bfp_adressen adr  ON adr.id=kon.aussteller_id
LEFT JOIN bfp_adressen adr1 ON adr1.id=kon.besucher_id
LEFT JOIN bfp_kontakte kon1 ON kon1.aussteller_id=kon.aussteller_id AND kon1.prio_1=1
WHERE kon.owner=2 and ( kon.prio_1=1 OR kon.prio_2=1 )
ORDER BY ausst, besu

Ich möchte doch nur Spalten zu vorhandenen Zeilen hinzufügen. Was mache ich falsch?

LG Kalle

  1. Hallo,

    was möchtest du denn durch die Abfrage eigentlich erreichen, ich kann mir leider unter "Spalten zu vorhandenen Zeilen hinzufügen" nichts vorstellen. Wenn du einen LEFT-JOIN machst, passiert folgendes: Die Datenbank nimmt sich alle Sätze in Tabelle 1 und alle Datensätze in Tabelle 2. Nun führt sie die beiden so zusammen, dass
    (1) Alle Sätze von Tabelle 1 erhalten bleiben
    (2) Wann immer einer zum "ON"-Kriterium passender Satz in Tabelle 2 gefunden, wird dieser als Spalten angehängt, andernfalls werden die Spalten mit NULL befüllt.

    Damit passiert bei dir folgendes:
    1xLEFT JOIN ergibt 71 Zeilen. Die kommen nach einem weiteren LEFT-JOIN auf jeden Fall wieder raus. Nun wage ich zu behaupten, dass bei diesem erneuten JOIN zu den 71 nicht 71 oder weniger passende Sätze gefunden werden, sondern offensichtlich so viele, dass am Ende 158 rauskommen. Aber ohne zu wissen, was dein JOIN da produziert ist das schwer zu diagnostizieren.

    MfG
    Rouven

    --
    -------------------
    ss:) zu:) ls:& fo:) de:< va:{ ch:? sh:) n4:( rl:? br:$ js:| ie:) fl:(
  2. Moin!

    SELECT    kon.aussteller_id, adr.bezeichnung ausst, adr1.bezeichnung besu, kon.prio_1, kon.prio_2
    FROM      bfp_kontakte kon
    LEFT JOIN bfp_adressen adr  ON adr.id=kon.aussteller_id
    LEFT JOIN bfp_adressen adr1 ON adr1.id=kon.besucher_id
    #LEFT JOIN bfp_kontakte kon1 ON kon1.aussteller_id=kon.aussteller_id AND kon1.prio_1=1
    WHERE kon.owner=2 and ( kon.prio_1=1 OR kon.prio_2=1 )
    ORDER BY ausst, besu

    Dieser Select fragt deine Kontakttabelle nach allen Kontakten ab, bei denen der Owner 2 und die Prios 1 oder 2  1 sind. Zugeordnet werden die Adressdaten (was für die Betrachtung des Unterschieds zum zweiten Select irrelevant ist).

    SELECT    kon.aussteller_id, adr.bezeichnung ausst, adr1.bezeichnung besu, kon.prio_1, kon.prio_2, kon1.prio_1
    FROM      bfp_kontakte kon
    LEFT JOIN bfp_adressen adr  ON adr.id=kon.aussteller_id
    LEFT JOIN bfp_adressen adr1 ON adr1.id=kon.besucher_id
    LEFT JOIN bfp_kontakte kon1 ON kon1.aussteller_id=kon.aussteller_id AND kon1.prio_1=1
    WHERE kon.owner=2 and ( kon.prio_1=1 OR kon.prio_2=1 )
    ORDER BY ausst, besu

    Dieser Select fragt deine Kontakttabelle nach allen Kontakten ab wie oben, aber die Tabelle, welche durch WHERE gefiltert wird, sieht anders aus. Dein LEFT JOIN verknüpft, wenn keine Bedingung angegeben ist, alle Tabellenzeilen mit allen Tabellenzeilen. Die Bedingung "kon1.aussteller_id = kon.aussteller_id" gibt dir für jeden Aussteller, der nur einmal in der Tabelle steht, genau eine Zeile, nämlich Zeile 1 verknüpft mit Zeile 1 (dieser ID).

    Ein Aussteller mit zwei Einträgen ergibt vier Ergebnisse: Zeile 1 (aus kon) verknüpft mit Zeile 1 (aus kon1), Zeile 1 verknüpft mit Zeile 2, Zeile 2 mit Zeile 1 und Zeile 2 mit Zeile 2.

    Drei Einträge eines Ausstellers ergeben 9 Zeilen.

    Diese Multiplikation der Zeilen wird aber noch durch die Prio_1-Bedingung gefiltert, d.h. die Zuordnung findet nur statt, wenn die prio_1 des Ausstellers 1 ist. Also werden nur Aussteller auf die oben beschriebene Art vervielfacht, die prio_1=1 haben, alle anderen nicht. Die tauchen beim LEFT JOIN im Ergebnis nicht auf.

    Und auf diese verfielfältigte Tabelle läßt du jetzt deine WHERE-Bedingung los und willst alle, die owner=2 haben, und die prio_1=1 haben - das haben sie aber alle, denn wenn in kon1.prio_1 eine 1 steht, steht auch in kon.prio_1 eine 1. kon.prio_2=1 ist als Bedingung dann irrelevant.

    Und nun kommst du und erklärst mal, was du dir genau gedacht hast mit deinem Query. Wenn du die Spalte einer bereits abgefragten Tabelle wissen willst, dann nutze kon.prio_1, der JOIN selbst bringt dir, zumindest bei dieser ON-Bedingung, keinerlei Zusatzinformation, nur die Dopplungen.

    • Sven Rautenberg
    1. Hallo, Sven,

      danke für deine ausführliche Analyse. Bin jetzt nicht mehr so aufnahmefähig, schaue es mir morgen noch mal an.

      Und nun kommst du und erklärst mal, was du dir genau gedacht hast mit deinem Query. Wenn du die Spalte einer bereits abgefragten Tabelle wissen willst, dann nutze kon.prio_1, der JOIN selbst bringt dir, zumindest bei dieser ON-Bedingung, keinerlei Zusatzinformation, nur die Dopplungen.

      Tja, es soll eine Statistik werden und ich will alle Sätze zählen, die prio_1 = 1 haben und alle die, die prio_2 = 1 haben.

      Nun hatte ich aber Schwierigkeiten mit dem count, denn der zählt auch, wenn prio_1 = 0 ist.

      Durch den LEFT JOIN wollte ich erreichen, dass in der zusätzlichen Spalte NULL steht, wenn prio_1 = 0 (und für prio_2 entsprechend).

      LG Kalle

      1. Tja, es soll eine Statistik werden und ich will alle Sätze zählen, die prio_1 = 1 haben und alle die, die prio_2 = 1 haben.

        Nun hatte ich aber Schwierigkeiten mit dem count, denn der zählt auch, wenn prio_1 = 0 ist.

        Durch den LEFT JOIN wollte ich erreichen, dass in der zusätzlichen Spalte NULL steht, wenn prio_1 = 0 (und für prio_2 entsprechend).

        ohne es mir genau angesehen zu haben folgender tip:
        du kannst bereits in der on-bedingung die kriterien für die 'zwischentabelle' setzen. also die gewünschten prios 1 und 2 angeben.
        die where-bedingung filtert dann nur noch aus der 'zwischentabelle' heraus.