# [MySQL] SELECT über 3 Tabellen



## CikoNo1 (14. April 2010)

Hallo Leute,

ich versuche die ganze Zeit schon eine Abfrage über drei Tabellen. Habe es auch schon mit LEFT JOIN....ON probiert ohne Erfolg.
Hier mal meine Tabellen.

News:
id | title
-------------------------------
1 | News 1
2 | News 2

Kategorie:
id | catName | parentID
----------------------------------
1 | Hauptcat | NULL
2 | Untercat | 1

Kategorie MM:
NewsID | CatID
-------------------------------------
1 | 2

Ich habe nun die ID der News1, die ist in einer Kategorie Untercat. Untercat gehört zur Hauptkategorie (ist child von).  Wie bekomme ich nun den ID der Hauptkategorie raus?

Das muss doch irgendwie gehen? Am besten noch in einem Ruck.

Bin über jeden Gedankenanstoss froh.

Viele Grüße


----------



## Yaslaw (15. April 2010)

Also, ich verscuh zu verstehen wie die Zusammenhänge sind.

die News haben eine ID
MM verbindet die News mit einer Unterkategorie
In Kategorie 2 willst du die parentID auslesen.


```
SELECT
	N.*,
	K.parentID
FROM
	´Kategorie MM´ AS NK
	LEFT JOIN News AS N
		ON NK.NewsID = N.id
	LEFT JOIN Kategorie AS K
		ON NK.CatID = K.id
```


----------



## ByeBye 154279 (15. April 2010)

HEy,


wenn eine News nur zur einer Kategorie gehört, 
dann kannst du die "Kategorie MM:" löschen und ein weiteres Attribut in der "
News:" benutzen.

Um die Hauptkategorie zu erhalten, musst du dies rekursiv in PHP o.ä. machen.
Rekursion gibt es in MySQL meines Wissens nach nicht.

mfg

bo


----------



## Yaslaw (15. April 2010)

bergonline hat gesagt.:


> HEy,
> Um die Hauptkategorie zu erhalten, musst du dies rekursiv in PHP o.ä. machen.
> Rekursion gibt es in MySQL meines Wissens nach nicht.


Muss ich dich enttäuschen. So ganz stimmt das nicht.
Wenn die Stufenanzahl bekannt ist, ist es kein Problem mit SQL

Bsp. für 2 Stufig (also Haubtkategoeri und unterkategorie)

```
SELECT i.id AS subID, h.*
FROM 
	Kategorie AS u
	INNER JOIN Kategorie as h
		ON u.parentID = h.id
```


----------



## CikoNo1 (15. April 2010)

Hallo,

@yaslaw: Es bestehen nur 2 Stufen, nun muss ich nur noch die WHERE Clause einbauen. Er soll mir nur die anzeigen die mit der NewsID 1 in Verbindung steht.

Vielen Dank


----------



## ByeBye 154279 (15. April 2010)

CikoNo1 hat gesagt.:


> Hallo,
> 
> @Yaslaw: Es bestehen nur 2 Stufen, nun muss ich nur noch die WHERE Clause einbauen. Er soll mir nur die anzeigen die mit der NewsID 1 in Verbindung steht.
> 
> Vielen Dank



Hey,


```
WHERE n.id = 1
```

Und das  ?

@Yaslaw:
HAst du Glück gehabt ;-P, 
dass die Anzahl bekannt ist 

mfg

bo


----------



## CikoNo1 (15. April 2010)

Hey,

wieso 


```
n.id = 1
```

n.id habe ich doch gar nicht. Ich habe folgenden den Code genommen:


```
SELECT i.id AS subID, h.*
FROM
     Kategorie AS u
         INNER JOIN Kategorie AS h
                 ON u.parentID = h.id
```

Da sollte doch jetzt am Ende WHERE news.id = 1 oder? Das läuft aber nicht, er zeigt mir alle Hauptkategorien mehrmals an


----------



## ByeBye 154279 (15. April 2010)

Aso,

entschuldige 
.
Ich habe den oberen Code von yaslaw genommen,
da du dort ja n (Alias von News) hast.

Dann setz noch ein JOIN mit News rein, dann hast du ja die News.id 

mfg

bo


----------



## Yaslaw (15. April 2010)

bergonline hat gesagt.:


> @Yaslaw:
> HAst du Glück gehabt ;-P,
> dass die Anzahl bekannt ist
> 
> ...



Und wenn schon.... ist ja einfach mit MySQL über beliebig viele Stufen die Kategorien auszulesen
Ich hab mal schnell eine Tabelle erstellt

id,parentId
1,
2,1
3,2
4,1
5,4
6,5
7,6
8,2
9,10
10,8

Mit dem folgenden SQL lese ich den ganezn Baum über alle Stufen für die id 9 aus

```
SELECT  
	@id AS id,
	@id := (SELECT parentID FROM nav WHERE id = @id) AS parentID
FROM 
	nav, 
	(SELECT @id := 9) AS vars
WHERE
	@id IS NOT NULL
```

Das Resultat sieht dann so aus

id,parentID
9,10
10,8
8,2
2,1
1, NULL

Der Baum in der richtigen Reihenfolge, alles Rückverfolgbar etc. Was wünscht man sich mehr....

PS:
Bei grösseren Tabellen ev die Zeile
	@id := (SELECT parentID FROM nav WHERE id = @id) AS parentID
durch
	@id := IF(@id IS NOT NULL, (SELECT parentID FROM nav WHERE id = @id), NULL) AS parentID
ersetzen, damit er nach gefundener Haubt-ID nicht mehr weiter einen Lookup auf die Tabelle macht


----------



## ByeBye 154279 (15. April 2010)

Hey,

igendwie habe ich noch Fragezeichen bei mir 

Es sieht gerade für mich so aus, 
als ob dein Beispiel nicht rekursiv ist.

Die Hauptkategorie von der ID 10 ist letztendlich 1

```
id,parentId
1,
2,1
3,2
4,1
5,4
6,5
7,6
8,2
9,10
10,8
```
10->8->2->1

Deine Beispiele müssten alle auf "Hauptkategorie mit der ID1" hinauslaufen.

Und so wie ich es verstanden habe, gibt es bei "CikoNo1" mehrere Hauptkategorien
Also mehrere Kategorien mit 'parentId' = NULL
Bei ihm müssten einzelne Kategorien verschiedenen Hauptkategorien haben.

mfg

bo


----------



## Yaslaw (15. April 2010)

Macht nix. Dann häng weitere Haubtkategorien an. Das Resultat bleibt dasselbe.
Das ganze wird von der gewählten Unterkategorie aus und baut sich nach oben auf, nicht von der Haubtkategorie nach unten.

Es ist nicht direkt rekursiv. Es ist eine Schleife mit einem Lookup


----------



## CikoNo1 (15. April 2010)

Danke euch beiden, hab jetzt mein Problem folgendermaßen gelöst:


```
SELECT news.title, parCat.title, cat.title, cat.parent_category FROM Kategorie_MM AS newsCat LEFT JOIN news ON newsCat.newsid = news.id LEFT JOIN Kategorie AS cat ON newsCat.catID = cat.id LEFT JOIN Kategorie AS parentNewsCat ON parentNewsCat.parentID = newsCat.catID LEFT JOIN Kategorie AS parCat ON cat.parentID = parCat.id WHERE news.id = 1
```

Trotzdem Danke für eure Hilfe


----------



## Yaslaw (15. April 2010)

@CikoNo1
Ich empfehle dir die SQLs über mehrere Zeilen zu formatieren. Es wird um einiges lesbarer

@bergonline
Wenn du natürlich eine vollständige Liste haben willst, wirds nur ein wenig komplexer

```
SELECT
		id,
		GROUP_CONCAT(iid ORDER BY rownum DESC SEPARATOR '->') AS path
FROM
	(
	SELECT  
		@rownum := @rownum+1 AS rownum,
		mylist.id AS id,
		IF(@lastl <> mylist.id, @id := mylist.id, @id) AS setVarId,
		@id AS iid,
		@lastl := mylist.id AS setVarLast,
		@id := (SELECT parentID FROM nav  WHERE id = @id) AS parentID
	FROM 
		(SELECT @id := 0, @lastl := 0, @rownum := 0) AS vars,
		(SELECT id FROM nav) AS myloop,
		(SELECT id FROM nav) AS mylist	
	) AS t
WHERE iid IS NOT NULL
GROUP BY id
```

Ergibt

```
id,path
1,1
2,1->2
3,1->2->3
4,1->4
5,1->4->5
6,1->4->5->6
7,1->4->5->6->7
8,1->2->8
9,1->2->8->10->9
10,1->2->8->10
11,11
12,11->12
13,11->13
```


----------



## ByeBye 154279 (15. April 2010)

Hey,

das ist jetzt cool 
Jetzt seh´ ichs
Muss mich unbedingt da mal weiter reinarbeiten.
Mit den "@" und :- habe ich bisher keine/wenig Übung.

Danke 

mfg

bo


----------

