mySQL: LEFT JOIN
André Laugks
- datenbank
0 André Laugks0 Antje Hofmann0 Bio0 André Laugks0 Bio
Hallo!
Ich wollte zwei Tabellen http://www.kombinat-laugks.de/extern/selfhtml_sql_16_07_20001.txt folgendermaßen ausgeben.
1.Bsp:
tab1.id tab1.name tab2.info
1 André 123
1 NULL 145
1 NULL 156
2 Swen 222
2 NULL 333
.
.
usw.
2. Bsp(noch besser ;-)):
tab1.id tab1.name tab2.info
1 André NULL
1 NULL 123
1 NULL 145
1 NULL 156
2 Swen Null
2 NULL 222
2 NULL 333
.
.
usw.
Mit "SELECT tab1.*, tab2.* FROM tab2 LEFT JOIN tab1 ON tab1.id=tab2.id;" habe ich es (siehe Link) "ungefähr" geschaft. Problem ist, "André" werden die falschen Infonummern(tab2.info) zugewiesen.
Mit ORDER BY konnte ich nichts hinbekommen.
Ist das mit mySQL überhaupt möglich oder muß ich zwei SELECTs absetzen?
Danke und MfG, André Laugks
ReHallo!
Total vergessen, wenn jemand Lust auf ein mySQL-Dump mit diesen Tabellen hat!
http://www.kombinat-laugks.de/extern/leftjoin.sql
MfG, André Laugks
Hallo Andre
ein typisches Beispiel für eine UNION-Abfrage. Das kann allerdings mysql nicht.
- Bsp(noch besser ;-)):
tab1.id tab1.name tab2.info
1 André NULL
1 NULL 123
1 NULL 145
1 NULL 156
2 Swen Null
2 NULL 222
2 NULL 333
.
.
usw.
Auf der Console klappt folgendes:
create temporary table test.tmp (id INT not null, name VARCHAR (100), info VARCHAR (100));insert into test.tmp select test.tab1.id,Name,'' as info from test.tab1;insert into test.tmp select test.tab2.tab1_id,'' as Name, test.tab2.info as info from test.tab1 left join test.tab2 on test.tab1.id=test.tab2.ta
b1_id;SELECT * from test.tmp order by id;drop table test.tmp;
über php geht das nicht in einem Arbeitsgang. Da benötigst du mehrere Zugriffe:
create temporary table test.tmp (id INT not null, name VARCHAR (100), info VARCHAR (100));
insert into test.tmp select test.tab1.id,Name,'' as info from test.tab1;
insert into test.tmp select test.tab2.tab1_id,'' as Name, test.tab2.info as info from test.tab1 left join test.tab2 on test.tab1.id=test.tab2.ta
b1_id;
SELECT * from test.tmp order by id;drop table test.tmp;
An sich kann man schon mit dem Createbefehl ein select auf die auszulesende Tabelle ausführen.
z.B. so:
create temporary table test.tmp select test.tab1.id,Name,'NULL' as info from test.tab1;insert into test.tmp select test.tab2.tab1_id,'NULL' as Name, test.tab2.info as info from test.tab1 left join test.tab2 on test.tab1.id=test.tab2.tab1_id;SELECT * from test.tmp order by id;drop table test.tmp;
Zu beachten ist, im ersten Select müssen alle verwendeten Felder angelegt werden. Nullwerte werden da nicht akzeptiert. Auch ist die Feldlänge der temporären Tabelle immer abhängig vom ersten Select.
Persönlich würde ich mich in diesem Fall jedoch für folgende Variante entscheiden:
select tab1.id,Name,info from tab1 left join tab2 on tab1_id=tab1.id order by id
Hier erhälst du zwar keine Nullzellen, aber gleiche Name erfüllen ja prinzipiell den gleichen Effekt. Werte die einen Eintrag in der Tab1 haben und keinen Eintrag in Tab2 werden ja sowieso zurückgegeben.
Mit "SELECT tab1.*, tab2.* FROM tab2 LEFT JOIN tab1 ON
tab1.id=tab2.id;"
^^^^^^^^^^^^^^^^
habe ich es (siehe Link) "ungefähr" geschaft. Problem ist, "André" werden die falschen Infonummern(tab2.info) zugewiesen.
Du hattest hier nur falsch verknüpft.
Viele Grüße
Antje
Hallo!
ein typisches Beispiel für eine UNION-Abfrage. Das kann allerdings mysql nicht.
Schade! So einiges vermisse ich in letzter Zeit an mySQL. Aber einem geschenkten Pferd, schaut man nichts ins Maul, oder selbst eine Datenbank programmieren oder sich für eine andere(viel Geld) entscheiden. :-)
create temporary table test.tmp (id INT not null, name VARCHAR (100), info VARCHAR (100));insert into test.tmp select test.tab1.id,Name,'' as info from test.tab1;insert into test.tmp select test.tab2.tab1_id,'' as Name, test.tab2.info as info from test.tab1 left join test.tab2 on test.tab1.id=test.tab2.ta
b1_id;SELECT * from test.tmp order by id;drop table test.tmp;
Problem ist, mehrere Statements arbeitet mySQL IMHO nach einander ab, also wie nach einander abgesetzt Statments.
select tab1.id,Name,info from tab1 left join tab2 on tab1_id=tab1.id order by id
Hier erhälst du zwar keine Nullzellen, aber gleiche Name erfüllen ja prinzipiell den gleichen Effekt. Werte die einen Eintrag in der Tab1 haben und keinen Eintrag in Tab2 werden ja sowieso zurückgegeben.
Jaein! Ich wollte als erstes den Namen schreiben, dann alle Fotos(tab2.info) dann den nächsten Namen usw.. Mit NULL hätte ich das schön abfragen können.
if(is_null($name))
{
Name
}
else
{
Foto
}
Aber man kann das sicherlich was basteln! Ich werde es auf alle Fälle man austesten.
Mit zwei SELECTs kann ich auch leben, zuerst
die Namen dann die Fotos.
Du hattest hier nur falsch verknüpft.
Werde ich doch mal gleich probieren.
Danke und MfG, André Laugks
Hallo Andre
Schade! So einiges vermisse ich in letzter Zeit an mySQL. Aber einem geschenkten Pferd, schaut man nichts ins Maul, oder selbst eine Datenbank programmieren oder sich für eine andere(viel Geld) entscheiden. :-)
:-) naja, ich arbeite zur Zeit viel mit Oracle, da vermisse ich auch einiges gegenüber mysql. Es hebt sich eben irgendwo auf.
Problem ist, mehrere Statements arbeitet mySQL IMHO nach einander ab, also wie nach einander abgesetzt Statments.
dachte ich mir
select tab1.id,Name,info from tab1 left join tab2 on tab1_id=tab1.id order by id
Jaein! Ich wollte als erstes den Namen schreiben, dann alle Fotos(tab2.info) dann den nächsten Namen usw.. Mit NULL hätte ich das schön abfragen können.
Da ich eh sehr gern diese Bereiche trenne, würde ich das über assoziative Arrays lösen.
Also unmittelbar nach dem Datenbankzugriff ein Array aufbauen. Etwa so:
(Ich spare mir jetzt den DB-Syntax. Wenn du z.B. die MySQL-Klasse der PHP-Lib verwendest, ist das eh kein Problem.)
$foto=array();
if (!isset($foto[$name])) $foto[$name]=array();
$foto[$name][]=$info;
while (list($key,$value)=each($foto))
{
echo $key; //der Name
for ($i=0;$i<count($value);$i++)
{
echo $value[$i]; //die Informationen
}
}
Diese Form nehme ich so ziemlich häufig. Vielleicht nutzt sie dir auch was.
Mit zwei SELECTs kann ich auch leben, zuerst
die Namen dann die Fotos.
In kleinen Projekten ist das kein Problem. Bei größeren Projekten oder einer größeren Serverlast kann jeder zusätzliche Select sehr viel Ballast sein.
Viele Grüße
Antje
Hallo Antje!
:-) naja, ich arbeite zur Zeit viel mit Oracle, da vermisse ich auch einiges gegenüber mysql. Es hebt sich eben irgendwo auf.
Würde ich auch mal gern! Aber viele große Projekte beweisen, daß es auch mit mySQL geht. Man muß eben ein paar mehr Sachen "ausserhalb" der DB machen, was man bei Qracle, DB2 etc. "intern" lösen kann, ... so etwas wie Fremdschlüßel etc.
Wenn ich eine Person lösche, muß ich das eben gleich in 3 Tabellen machen, in der Daten von der Person liegen.
Für eine Tabelle muß ich i.d.R. 5 INSERTs auswühren...! Wäre nicht schlecht wenn man das in einem Rutsch machen könnte.
Da ich eh sehr gern diese Bereiche trenne, würde ich das über assoziative Arrays lösen.
$foto=array();
if (!isset($foto[$name])) $foto[$name]=array();
$foto[$name][]=$info;
while (list($key,$value)=each($foto))
{
echo $key; //der Name
for ($i=0;$i<count($value);$i++)
{
echo $value[$i]; //die Informationen
}
}
Diese Form nehme ich so ziemlich häufig. Vielleicht nutzt sie dir auch was.
Ich habe ein Forum geschrieben, so wie das selfhtml-Forum. Hier muß ich auch zwei SELECTs absetzen. Weil ich sonst die Postings nicht richtig einordnen kann, wegen gibt "Sortierprobleme" absteigend<->aufsteigend. Ab bestimmten Zeilen muß ich verschieden sortieren. Es gibt so etwas wie SQL-Baumstrukturen, mit der man dies lösen kann. Das werde ich aber erst in Version 4 oder so umsetzen, bin jetzt gerade mal bei Version 1 ;-).
while($db->fkt_fetch())
{
if(is_null($db->fetch["vornummer"])) // --> Anfangspostings
{
$zeile_start_thread[$db->fetch["id_forum"]] = array(
$db->fetch["id_forum"],
$db->fetch["betreff"],
$db->fetch["name"],
$db->fetch["datum"]);
}
else // --> Antwortpostings
{
$zeile_antwort_thread[$db->fetch["id_forum"]] = array(
$db->fetch["id_forum"],
$db->fetch["thread"],
$db->fetch["betreff"],
$db->fetch["name"],
$db->fetch["datum"],
$db->fetch["vornummer"],
$db->fetch["ebene"]);
}
}
z.B.
while(list($id, $inneres_array) = each($zeile_start_thread))
{
list($id, $betreff, $name, $datum) = $inneres_array;
...
}
In kleinen Projekten ist das kein Problem. Bei größeren Projekten oder einer größeren Serverlast kann jeder zusätzliche Select sehr viel Ballast sein.
Bei diesem Projekt könnte ich 100 SELECTs absetzen. Die Seite wird von dem Normaluser nicht genutzt, also eine Art "B2B", mit ich denke wenig Zugriffen. Der größte Teil läuft eh inerhalb eines CMS ab.
Wenn ich so manche Scripte sehe, denke ich, arbeite ich recht sparsam. :-)
MfG, André Laugks
Hi Antje, André
Persönlich würde ich mich in diesem Fall jedoch für folgende Variante entscheiden:
select tab1.id,Name,info from tab1 left join tab2 on tab1_id=tab1.id order by id
Hier erhälst du zwar keine Nullzellen, aber gleiche Name erfüllen ja prinzipiell den gleichen Effekt. Werte die einen Eintrag in der Tab1 haben und keinen Eintrag in Tab2 werden ja sowieso zurückgegeben.
Die Frage ist hier, ob mit left joins zu arbeiten sinnvoll ist. So werden
auch Namen ausgegeben, für die es gar keine Entsprechungen in Tabelle 2 gibt.
Da MySQL in den neuen Versionen inner join kann, wäre das so besser, falls
Namen ohne Entsprechung nicht ausgegeben werden sollen.
Ein Sort auf die info von Tabelle 2 zusätzlich wäre wohl auch noch sinnvoll.
select a.id, a.name, b.info
from tab1 as a
inner join tab2 as b on (a.id = b.tab1_id)
order by a.id, b.info
IMHO ist mit selbem Name sehr einfach das nachher per PGM-Code in die
Struktur zu bringen.
Lies erste Zeile
mache mit dem namen zeile für die datenzeile
mache infozeile 1 für die datenzeile
for (alle zeilen ab erste zeile) {
if (name = lastname) {
mache infozeile n
} else {
mache namenzeile
mache infozeile 1
}
}
Ob die Variante mit der temporären Tabelle nicht schneller/resourcenschonender ist, müsste man
bei grossen Datenmengen allerdings erst ausprobieren (BENCHMARK).
Gruss Daniela
Hallo!
select a.id, a.name, b.info
from tab1 as a
inner join tab2 as b on (a.id = b.tab1_id)
order by a.id, b.info
Das selbe bekomme ich auch mit diesem Statement hin, was ja nichts anderes ist als ein inner Join.
SELECT tab1.*, tab2.* FROM tab1, tab2 WHERE tab1.id=tab2.tab1_id;
for (alle zeilen ab erste zeile) {
if (name = lastname) {
mache infozeile n
} else {
mache namenzeile
mache infozeile 1
}
}
Solch ein ähnlich Konstrukt hatte ich mir schon zusammen gefrickelt.
MfG, André Laugks
Hi
SELECT tab1.*, tab2.* FROM tab1, tab2 WHERE tab1.id=tab2.tab1_id;
Das stellt zumindest bei älteren MySQL Versionen einen grossen Performanceverlust dar.
Damit wurde (ob immernoch ist mir nicht bekannt) erst jeder Eintrag von
Tabelle 1 mit jedem Eintrag von Tabelle 2 verknüpft und erst dann alle
unpassenden rausgefiltert.
Auch Select * (auch tab.*) ist nicht ideal, die Gründe stehen im Archiv und auch im
MySQL Manual. Im einfachsten Fall kriegst du nur überflüssige Spalten (Performance)
im schlimmsten Fall kann es je nach zugehöriger Pgmiersprache sogar Abstürze
geben.
Gruss Daniela
Hallo!
Das stellt zumindest bei älteren MySQL Versionen einen grossen Performanceverlust dar.
Damit wurde (ob immernoch ist mir nicht bekannt) erst jeder Eintrag von
Tabelle 1 mit jedem Eintrag von Tabelle 2 verknüpft und erst dann alle
unpassenden rausgefiltert.
Aha! Gut zu wissen!
Auch Select * (auch tab.*) ist nicht ideal, die Gründe stehen im Archiv und auch im
MySQL Manual.
Das Sternchen verwende ich so gut wie nie, da ich nie alle Spalten hole oder Spalten schon mit SQL-Funktionen formatiert ausgebe bzw. mir bereit lege. Wenn ich alle Werte hole, in der Regel Tabellen mit 2-3 Spalten, dann verwende ich ein Sternchen.
Bei meine "Arbeiten" liegen die Datensätze pro Tabelle im Extremfall unter 10.000, für mySQL was die Performance angeht, ehr eine ganz kleine Zwischenmahlzeit. Alle Datensätze aus Spalten mit dem Type wie BLOB oder TEXT holt man sich i.d.R so und so nicht aufeinmal.
Aber es ist ja so, schlechte Gewohnheiten, gewöhnt man sich lagsam ab!
MfG, André Laugks
Sup!
Warum benutzt Du nicht Oracle, PostGreSQL oder Interbase?
;-)
Gruesse,
Bio
Hallo!
Warum benutzt Du nicht Oracle, PostGreSQL oder Interbase?
Gebe mir das Geld für Oracle oder Interbase :-)! PostGreSQL ist doch OpenSource...!? Da ich nicht in einer klassischen Onlineagentur arbeite, sondern alleine in einer TV-Firma mich um die firmeneigenen Onlineprojekte kümmere, bekomme ich ein Schlachtschiff wie Oracle oder Interbase nicht durch. Die Projekte haben einfach nicht die Größe. Vielleicht mal in einem Jahr |-).
Mal schauen, was mySQL4 bringt!
MfG, André Laugks
Sup!
Also, wir haben ein ganz kleines Projekt mit PostGreSQL, es laeuft ganz gut, PostGreSQL hat eine aehnliche Syntax wie Oracle, constraints, Fremdschluessel (kaskadierendes Löschen etc.), outer joins, Transaktionen, ist umsonst.
Und Interbase soll angeblich auch umsonst zu haben sein neuerdings... habe da unten noch so einen Thread gesehen, xwolf sagte, er benutzt Interbase.
Gruesse,
Bio