werbeklaus: Join-Problem

Hallo,
ich hab nochmal ein Problem, was ich ohne eure Hilfe nicht schaffen werde:

Ich habe 2 Tabellen in MySQL:

tab1:
id | ...
1  | ...
2  | ...
3  | ...
4  | ...
5  | ...

tab2
tab1_id | content
1       | 13
1       | 14
2       | 12
4       | 12
4       | 11

Den Einträgen aus tab1 sind in tab2 null bis viele contents zugeordnet.
Nun möchte ich - klingt eigentlich ganz leicht - alle einträge aus tab1 mit allen zugehörigen contents aus tab2.

Mit meinem wenig Join-Wissen habe ich aber schon entdeckt:
Bei einem normalen Join bekomme ich Einträge aus tab1 nur, wenn es auch einen passenden aus tab2 gibt.
Ausserdem bekomme ich den Eintrag aus tab1 sooft, wie es eine passende tab2-Zeile gibt.
Unterdrücke ich das mit group by [1] gehen ja alle contents ausser einem verloren.

Ich hoffe ihr könnt mir erklären, wie sowas geht. Ja, am besten erklären und keine Lösung vorsetzen :-)

werbeklaus

[1] Ich habe die Funktionsweise von group by nie so ganz kapiert und auch noch keine einzige Erklärung im Internet dafür gefunden. Zur Zeit denke ich, die minimiert die Ausgabe auf höchstens einen Eintrag mit der gruppierten Spalte - der Rest verfällt.
Auch hier danke für Erklärung :-)

  1. Hi,

    Bei einem normalen Join bekomme ich Einträge aus tab1 nur, wenn es auch einen passenden aus tab2 gibt.

    anders als bei einem Outer Join, richtig.

    Ausserdem bekomme ich den Eintrag aus tab1 sooft, wie es eine passende tab2-Zeile gibt.

    Natürlich. Wie sollte es auch sonst sein?

    Ich hoffe ihr könnt mir erklären, wie sowas geht.

    Möglicherweise kann ich das, wenn Du mir verrätst, was "sowas" sein soll.

    Ja, am besten erklären und keine Lösung vorsetzen :-)

    Natürlich :-)

    [1] Ich habe die Funktionsweise von group by nie so ganz kapiert

    Es werden (scheinbar) neue Tabellen erzeugt, für jedes einmalige Wertetupel der Gruppierungsspalten eine. Aus jeder dieser Tabellen wird dann genau ein Datensatz selektiert. (Daher liefern ordentliche DBMSse auch einen Fehler, wenn man neben den Gruppierungsspalten noch weitere Spalten zu selektieren versucht, anstatt nur Gruppenfunktionen. Ich werde wohl nie begreifen, wieso MySQL dies anders handhabt, bzw. wie die Logik hinter diesem ... Sonderfall sein soll.)

    Zur Zeit denke ich, die minimiert die Ausgabe auf höchstens einen Eintrag mit der gruppierten Spalte - der Rest verfällt.

    Im Grunde ja. Vor dem Verfall kannst Du den Rest noch analysieren.

    Cheatah

    --
    X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
    X-Will-Answer-Email: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. yo,

      Ich werde wohl nie begreifen, wieso MySQL dies anders handhabt, bzw. wie die Logik hinter diesem ... Sonderfall sein soll.)

      die logik ist die gleiche, wie auch bei anderen dbms. man darf keine spalten ausgeben, die bei einer gruppierung unterschiedliche werte aufweisen.

      der unterschied bei mysql ist der, dass man dazu nicht expliziet eine weitere gruppierung dafür angeben braucht, falls die werte sowieso schon alle gleich sind. der sinn dahinter ist der, dass zusätzliche gruppierungen resourcen und somit zeit kosten.

      der haken bei der sache ist, das dbms von mysql kann natürlich nicht überprüfen, ob alle werte der besagten spalte nun wirklich den gleichen wert beinhalten. dann wäre der vorteil ja wieder dahin. also überläßt es mysql dem anwender. und fangen dann auch die probleme an.....

      Ilja

    2. Hallo,

      Ich hoffe ihr könnt mir erklären, wie sowas geht.

      Möglicherweise kann ich das, wenn Du mir verrätst, was "sowas" sein soll.

      Da möchte ich auf einen Satz meines 1. Beitrags verweisen:
      "Nun möchte ich - klingt eigentlich ganz leicht - alle einträge aus tab1 mit allen zugehörigen contents aus tab2."

      Es werden (scheinbar) neue Tabellen erzeugt, für jedes einmalige Wertetupel der Gruppierungsspalten eine. Aus jeder dieser Tabellen wird dann genau ein Datensatz selektiert.

      Und wie erreiche ich nun, dass eben nicht einfach ein Datensatz selektiert wird, sondern ich _alle_ contents bekomme?

      Im Grunde ja. Vor dem Verfall kannst Du den Rest noch analysieren.

      Wie dieses _analysieren_ funktioniert - da hab ich eben leider keine Ahnung :-(

      Cheatah

      werbeklaus

  2. yo,

    den richtigen hinweis hat dir Cheatah schon gegeben. genau für dieses problem, gibt es in SQL OUTER JOINS oder wörtlich gesprochen, zeige mir alle einträge der einen tabelle und wenn vorhanden, auch die entsprechenden werte der zweiten tabelle.

    Ausserdem bekomme ich den Eintrag aus tab1 sooft, wie es eine passende tab2-Zeile gibt.

    das ist auch gut so, wäre fatal wenn es nicht so wäre. je nachdem welche infos (spalten) du alle ausgeben lassen willst, kannst du ein DISTINCT ausführne lassen, der doppelte datensätze herausfiltert. zu beachten ist dabei, dass alle werte der spaltenausgabe gleich sein müssen und nicht nur einer.

    [1] Ich habe die Funktionsweise von group by nie so ganz kapiert und auch noch keine einzige Erklärung im Internet dafür gefunden.

    hinter gruppierung versteckt sich eine ganz einfache sortierung. das dbms macht bei einer gruppierung quasi folgendes. es nimmt alle datensätze der ergebnismenge und sortiert sie nach den spalten, die in der GROUP BY klausel mit angegeben wurde. ist nur eine spalte angegeben, dann werden die datensätze auch nur nach dieser sortiert. sind zwei angegeben, dann zuerst nach der ersten sortiert und dann nach der zweiten spalte, etc.

    nach der ausführung der gruppierung hat man quasi die ergebnismenge einfach nur sortiert, dass ist alles, was hinter GROUP BY steckt. bei der ausgabe wird immer nur ein datensatz einer grupperung zurückgegeben, wobei wie gesagt eine gruppierung mehrere spalten umfassen kann.

    da die spaltenwerte, über die nicht gruppiert wurden, unterschiedliche werte innheralb einer gruppierung enthalten können, darf man sie auch nicht so einfach bei ader abfrage mit ausgeben lassen. letztlich wird ja nur ein datensatz pro gruppierung zurück gegeben. und wenn die werte unterschiedlich sind, dann kann das dbms nicht entschieden, welchen wert es nun angeben soll.

    anders liegt der fall, wenn man über diese spalte eine aggregat-funktion einsetz. damit wird sichergestellt, dass es n ur einen wert gibt, zum beispiel der größte oder der durschnittswert. deshalb gibt es die regel, nur spalten auszugeben, über die entweder gruppiert wurde oder aber eine aggregat-funktion benutzen.

    Ilja

    1. Hallo,
      Einen Großteil einer aufführung habe ich verstanden :-)
      Vielen DAnk für die Ausführliche Erklärung!!!

      da die spaltenwerte, über die nicht gruppiert wurden, unterschiedliche werte innheralb einer gruppierung enthalten können, darf man sie auch nicht so einfach bei ader abfrage mit ausgeben lassen. letztlich wird ja nur ein datensatz pro gruppierung zurück gegeben. und wenn die werte unterschiedlich sind, dann kann das dbms nicht entschieden, welchen wert es nun angeben soll.

      anders liegt der fall, wenn man über diese spalte eine aggregat-funktion einsetz. damit wird sichergestellt, dass es n ur einen wert gibt, zum beispiel der größte oder der durschnittswert. deshalb gibt es die regel, nur spalten auszugeben, über die entweder gruppiert wurde oder aber eine aggregat-funktion benutzen.

      Das Problem ist, dass ich keinen größten oder Durchschnittswert sondern _jeden_ Wert brauche!
      Was für eine Aggregat-Funktion macht denn dann noch sinn ??

      werbeklaus

      1. yo,

        Das Problem ist, dass ich keinen größten oder Durchschnittswert sondern _jeden_ Wert brauche!
        Was für eine Aggregat-Funktion macht denn dann noch sinn ??

        dafür gibt es andere wege. willst du nicht gruppierte spalten ohne aggregat-funktionen anziegen lassen, dann muss man in aller regel den weg mit unterabfragen bestreiten, insbesondere korrelierende unterabfrage sind dabei der "renner".

        dafür ist es aber besser, wenn du alle spalten mit angibst, welche du angezeigt haben willst und wie das tabellen-layout aussieht.

        Ilja

        1. Hallo,
          'tschuldigung, aber diesmal versteh ich in deinem Post fast nichts :-(

          dafür gibt es andere wege. willst du nicht gruppierte spalten ohne aggregat-funktionen anziegen lassen, dann muss man in aller regel den weg mit unterabfragen bestreiten, insbesondere korrelierende unterabfrage sind dabei der "renner".

          Unterabfragen kenn mich auch noch nicht aus. Evtl werde ich mich da wohl einarbeiten müssen....

          dafür ist es aber besser, wenn du alle spalten mit angibst, welche du angezeigt haben willst und wie das tabellen-layout aussieht.

          Meinst du jetzt dir hier angeben oder in die Abfrage *gg*

          Ist denn die "Lösung" von Axel Richter nicht ausreichend? Ich selbst käme damit auch zurecht :-)

          Danke nochmals,
          werbeklaus

          1. yo,

            Ist denn die "Lösung" von Axel Richter nicht ausreichend? Ich selbst käme damit auch zurecht :-)

            das sind zwei verschiedene dinge. axels lösung ist für dein problem sicherlich eine sehr gute lösung. wir haben uns aber über GROUP BY und deren verwendung unterhalten. wenn du den mal unterabfragen brauchst, dann kann man sich hier ja noch einmal treffen. ;-)

            Ilja

  3. Hallo,

    Ich habe 2 Tabellen in MySQL:

    tab1:
    id | ...
    1  | ...
    2  | ...
    3  | ...
    4  | ...
    5  | ...

    tab2
    tab1_id | content
    1       | 13
    1       | 14
    2       | 12
    4       | 12
    4       | 11

    Den Einträgen aus tab1 sind in tab2 null bis viele contents zugeordnet.
    Nun möchte ich - klingt eigentlich ganz leicht - alle einträge aus tab1 mit allen zugehörigen contents aus tab2.

    Mit meinem wenig Join-Wissen habe ich aber schon entdeckt:
    Bei einem normalen Join bekomme ich Einträge aus tab1 nur, wenn es auch einen passenden aus tab2 gibt.

    Ja, aber um dies zu ändern, gibt es OUTER JOINS, wie z.B. LEFT JOIN und RIGHT JOIN.

    Ausserdem bekomme ich den Eintrag aus tab1 sooft, wie es eine passende tab2-Zeile gibt.

    Ja, das ist, glaube ich, Dein Problem. Ein DBMS, wie sie heute üblich sind, speichert Daten zweidimensional in Zeilen (Datensätze) und Spalten (Felder) und es wertet sie auch so aus. Das Beste, was Du mit einem

    SELECT tab1.id, tab2.content
    FROM tab1 LEFT JOIN tab2 ON tab1.id = tab2.tab1_id;

    erhalten kannst, ist:

    tab1.id | tab2.content
    1       | 13
    1       | 14
    2       | 12
    3       | null
    4       | 12
    4       | 11
    5       | null

    Daraus:

    id | content | content
    1  | 13      | 14
    2  | 12      |
    3  |         |
    4  | 12      | 11
    5  |         |

    zu machen, muss Deine auswertende Programmlogik leisten, denn, wie Du siehst, ist das keine eindeutig zweidimensionale Darstellung mehr.

    viele Grüße

    Axel

    1. Hallo,

      Bei einem normalen Join bekomme ich Einträge aus tab1 nur, wenn es auch einen passenden aus tab2 gibt.
      Ja, aber um dies zu ändern, gibt es OUTER JOINS, wie z.B. LEFT JOIN und RIGHT JOIN.

      Okay, ist das denn die einzige Aufgabe eines LEFT JOINS?
      Nagut, aber auf jeden Fall haut das so schonmal hin.

      Das Beste, was Du mit einem

      SELECT tab1.id, tab2.content
      FROM tab1 LEFT JOIN tab2 ON tab1.id = tab2.tab1_id;

      erhalten kannst, ist:

      tab1.id | tab2.content
      1       | 13
      1       | 14
      2       | 12
      3       | null
      4       | 12
      4       | 11
      5       | null

      Das habe ich auch schon herausgefunden :-)

      Daraus
      id | content | content
      1  | 13      | 14
      2  | 12      |
      3  |         |
      4  | 12      | 11
      5  |         |

      zu machen, muss Deine auswertende Programmlogik leisten, denn, wie Du siehst, ist das keine eindeutig zweidimensionale Darstellung mehr.

      Das habe ich befürchtet....
      Nun gut, in PHP dürfte das ja nicht soo schwer sein. Wenn ich das Ergebnis durchlaufe und dann abfrage: Hat sich die ID im Vergleich zum letzten Durchlauf geändert?
      Dann kann ich ja den neuen content dem letzten Datensatz zuordnen oder eben nicht.

      Vielen Dank für die Hilfe!

      werbeklaus

      1. Hallo,

        Bei einem normalen Join bekomme ich Einträge aus tab1 nur, wenn es auch einen passenden aus tab2 gibt.
        Ja, aber um dies zu ändern, gibt es OUTER JOINS, wie z.B. LEFT JOIN und RIGHT JOIN.
        Okay, ist das denn die einzige Aufgabe eines LEFT JOINS?

        Nein, das ist die einzige Aufgabe von OUTER JOINS. Die Aufgabe eines LEFT JOINs ist es, alle Datensätze der linken (LEFT) Tabelle aufzunehmen und diese, entsprechend der JOIN-Bedingung, mit den entsprechenden Datensätze der rechten Tabelle zu verbinden (JOIN). Die Aufgabe eines RIGHT JOINs wäre es, alle Datensätze der rechten (RIGHT) Tabelle aufzunehmen und diese,  entsprechend der JOIN-Bedingung, mit den entsprechenden Datensätze der linken Tabelle zu verbinden (JOIN). Ein FULL OUTER JOIN würde alle Datensätze beider Tabellen aufnehmen und sie, entsprechend der JOIN-Bedingung, ggf. miteinander verbinden (JOIN).

        viele Grüße

        Axel

        1. Hi!

          Okay, ist das denn die einzige Aufgabe eines LEFT JOINS?
          Nein, das ist die einzige Aufgabe von OUTER JOINS. Die Aufgabe eines LEFT JOINs ist es, alle Datensätze der linken (LEFT) Tabelle aufzunehmen und diese, entsprechend der JOIN-Bedingung, mit den entsprechenden Datensätze der rechten Tabelle zu verbinden (JOIN). Die Aufgabe eines RIGHT JOINs wäre es, alle Datensätze der rechten (RIGHT) Tabelle aufzunehmen und diese,  entsprechend der JOIN-Bedingung, mit den entsprechenden Datensätze der linken Tabelle zu verbinden (JOIN). Ein FULL OUTER JOIN würde alle Datensätze beider Tabellen aufnehmen und sie, entsprechend der JOIN-Bedingung, ggf. miteinander verbinden (JOIN).

          Einführung Joins
          Fortgeschrittene Joins

          MfG
          Rouven

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

            Einführung Joins
            Fortgeschrittene Joins

            Oh, danke dir! Endlich mal eine richtig gescheite Erklärung zu diesem Thema!

            werbeklaus