Join-Problem
werbeklaus
- datenbank
1 Cheatah0 Ilja0 werbeklaus
1 Ilja0 werbeklaus0 Ilja0 werbeklaus0 Ilja
1 Axel Richter0 werbeklaus0 Axel Richter0 Rouven
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 :-)
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
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
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
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
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
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
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
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
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 | 11Den 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
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
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
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
Hallo!
Oh, danke dir! Endlich mal eine richtig gescheite Erklärung zu diesem Thema!
werbeklaus