Ein JOIN oder mehrere Abfragen?

  • Themenstarter Themenstarter Ronax
  • Beginndatum Beginndatum
R

Ronax

Ich benutze die 3 NF

(A)
-------------
a_id
-------------
1
2
3


(B)
-------------
b_id
-------------
1
2


(AtoB)
----------------
a_id | b_id
----------------
1 | 1
1 | 2
2 | 1
3 | 1

Daraus ergibt sich, dass
a_id 1 ist einmal b_id 1 und b_id 2 zugeordnet
a_id 2 ist b_id 1 zugeordnet
a_id 3 ist b_id 1 zugeordnet
...

Ich hatte es mal mit einem JOIN probiert:
Code:
SELECT *
FROM A, B, AtoB
WHERE AtoB.a_id = a_id 
AND b_id   = AtoB.b_id
Hierbei tat sich das Problem auf, dass ich nun 4 Zeilen erhielt, die Zeile von (A) mit a_id 1 nämlich doppelt.

Zur Zeit ist das folgendermaßen gelöst. Und zwar werden zuerst alle Zeilen aus (A) abgefragt und dann zu jeder Zeile die Zeilen aus (B).

Gibt es bei diesem Problem eine vielleicht sogar ganz einfache Lösung oder kommt man gar nicht um zwei Abfragen umher.

vielen Dank
Florian
 
Das kommt ganz darauf an, was Du haben willst. bei solchen einfachen n:m-Beziehungen geht das eigentlich immer mit nur einer Abfrage.
Deine Schreibweise (FROM A, B, AtoB) ist halt sehr unspezifisch, da liefert SQL natürlich alles was es finden kann.

Willst Du z.B. alle aus A mit den zugehörigen aus B dann schreib:
SQL:
FROM
  `A`
LEFT JOIN
  `AtoB` ON `AtoB`.`a_id` = `A`.`a_id`
LEFT  JOIN
  `B` ON `B`.`b_id` = `AtoB`.`b_id`

Martin
 
Zuletzt bearbeitet von einem Moderator:
Der Join ist auf jeden Fall schneller (bei vielen Datensätzen in A zum Teil sehr deutlich).

Aus Deiner Beschreibung deute ich, dass Dich folgende Ausgabe vom Join stört:
Code:
a | b
1 | 1
1 | 2
2 | 1
3 | 1
Und dass Du Dir ein Darstellung, ähnlich der folgenden wünscht:
Code:
a: 1
b: 1
b: 2

a: 2
b:1

a: 3
b:1

Das kannst Du auch mit dem Ergebnis des Joins erreichen, wenn Du Dir die Sachen entsprechend "zusammensuchst".
Kurzes Beispiel des Prinzips in PHP:
PHP:
$res = mysql_query(" ... mit join oder left join, wie ManicMarble gezeigt hat ...");
$tempA=null;
while($row=mysql_fetch_assoc($res)) {
    if ($tempA!=$row['aId']) {
        echo '<h1>'.$row['aId'].'</h1>';
        $tempA=$row['aId'];
    }
    echo '<p>'.$row['bId'].'</p>';
}
Als Ausgabe wirst Du natürlich sicher nicht die Ids, sondern irgendeine Art von Inhalt nehmen. Mangels näherer Informationen zu den Feldern habe ich die Ids genommen. Auf dieselbe Weise könntest Du natürlich auch ein mehrdimensionales Array füllen.

Das geht natürlich auch in jeder anderen Programmiersprache, aber nicht mit der Datenbank alleine. In MySQL (ab 4.1) könntest Du Dir allerdings noch mit GROUP_CONCAT() helfen.

Gruß hpvw
 
Erstmal vielen Dank für die schnellen und mir sehr aufschlussreichen antworten. Hat mich auf jedenfall ein paar Meilen weiter getragen. :) Zunächst möchte ich noch schnell etwas nachtragen: mySQL < 4.1

So, nun etwas mehr Details:

Tabelle: artikel
--------------------------------
artikel_id
artikel_name


Tabelle: kategorien
--------------------------------
kategorien_id
kategorien_name


Tabelle: atok
--------------------------------
atok_artikel_id
atok_kategorie_id


Die Problemstellung bleibt dieselbe und das Ziel die folgende Ausgabe:
Name1 (Kategorie1, Kategorie2)
Name2 (Kategorie1)
Name3 (Kategorie1)

Mein Quelltext schaut bisweilen wie folgt aus:
PHP:
		$result = $this->SQL->query("
			SELECT *
			FROM artikel
			
			LEFT JOIN atok 
			ON atok_artikel_id = artikel_id
			
			LEFT JOIN kategorien
			ON kategorien_id = atok_kategorie_id
			
			ORDER BY artikel_datum DESC LIMIT 0,4
			");
		$oldID 			= NULL;

Problem #1:
In meinem Fall befinden sich z.B. vier Zeilen in der Tabelle Artikel, es sollen die ersten vier ausgegeben werden (doofer zufall). Ausgegeben bzw. in $result befinden sich zwar 4 Zeilen, jedoch halt Name1, Name 1, Name 2, Name 3.

die Ausgabe:
Ich bin mir nicht ganz sicher, ob das noch viel mit SQL zu tun hat. Ich arbeite mit einer Template Engine, und gebe quasi alles auf einmal aus, sprich ich brauche das Objekt 'Artikel' mit Kategorien. Gelöst habe ich dies in dem ich zunächst jede Kategorie gesammelt habe:
PHP:
			foreach( $result as $qry ){
				if ($oldID != $qry['artikel_id']){
					$oldID = $qry['artikel_id'];						
				}
				$arKategorie[$oldID][] = $qry['kategorien_name'];
			}
Dann mache ich bei der eigentlich Ausgabe nochmal eine each Schleife und arbeite jetzt halt für jede Artikel_id die Einträge unter $arKategorie[Artikel_id] ab.

Ich bin in SQL nicht all zu bewandert, aber ich nehme mal ein es gibt keine Möglichkeit ein 2 Dimensionales Array als Result zu erhalten :)

vielen Dank
Florian
 
Ronax hat gesagt.:
Ich bin in SQL nicht all zu bewandert, aber ich nehme mal ein es gibt keine Möglichkeit ein 2 Dimensionales Array als Result zu erhalten :)
Das ist richtig. Du kannst jedoch auf ähnliche Weise, wie ich oben für die Ausgabe beschrieben habe, aus dem Ergebnis ein mehrdimensionales Array machen.

Gruß hpvw
 
Zurück