webForumDet fria alternativet

Nästlat set med rekursivitet

Databaser & SQL

1 svar · 373 visningar · startad av SPiN

Medlem sedan mars 20007 896 inlägg
Frågan#1

Hej ärade sequelare!

Jag har återigen satt mig i klister galore. Jag har ett nästlat set för att lagra kategorier i hierarki (kategori -> subkategori 1 -> subkategori 2 -> ... -> subkategori n).

Ett kort exempel:

id	name		left		right
---------------------------------------------
1	Rot		1		8
2	Cykel		4		7
3	Bil		2		3
4	Pedaler		5		6
...

Till denna hierarki med kategorier har jag ytterligare en tabell med artiklar, som inte lagrar någon hierarki - utan artiklar med relationsnycklar till sin kategori.

Exempel:

id	name			categoryId
------------------------------------------
1	Cresent			2
2	Nishiki			2
3	Saab			3
4	Cresentpedal		4
5	Cresentpedal, blå	4
6	Cresentpedal, röd	4
...

Nu har ni en överblick över min tabellstruktur - nu till problemet:

Att lagra data i ett nästlat set ger en känsla av rekursivitet i SQL, det är lätt att hantera kategorier, barnkategorier, föräldrakategorier, o.s.v. Man kan låta en kategori innehålla både barnkategorier och artiklar. Fördelarna är hur som helst många. Nu har jag ju dock en site som har snälla URL:er, så för att visa t.ex. den blå Cresentpedalen hade min URL sett ut:

http://domän.se/cykel/pedaler/cresentpedal-bla

Överlag är det fortfarande inga problem, om man hierarkiskt klickar sig vidare på sidan, med ett steg i taget (från startsidan till cykel till pedaler till blå Cresentpedal). Problemet ligger i när man ska hoppa över ett steg i hierarkin, säg att vi går in under /cykel och där ska vi inte enbart visa produkter från kategori "Cykel" - utan även från alla subkategorier. Med andra ord vill jag visa "Cresent", "Nishiki" samt "Cresentpedal", "Cresentpedal, blå" och "Cresentpedal, röd" från subkategorin "Pedaler". Inga problem så långt heller, det är bara att plocka ut de produkter med en kategori som har lft- och rgt-värden som ligger mellan dessa värden för "Cykel";

select
	articles.`name` as article
from
	articles,
	(select
		node.`id` as categoryId
	from
		categories as node,
		categories as parent
	where
		node.`lft` between parent.`lft` and parent.`rgt`
		and
		parent.`name`='Cykel') as categories
where
	articles.`categoryId`=categories.`categoryId`

Men som sagt använder jag snälla URLer, och behöver därför även få ut hela hierarkin med kategorinamn "över" produkten - så att jag kan bygga min URL.

Rent konkret behöver jag alltså få ut

Cykel / Pedaler / Cresentpedal, blå

från en SQL-fråga. Om det är lättare att få ut den relativa sökvägen tillbaka till "Cykel" går ju det likabra, men jag stöter på patrull hur jag än försöker. Någon som har några tips? Behövs mer information?

DBMS: MySQL 5+

Medlem sedan mars 20007 896 inlägg
#2

Lösningen: :)

select
    sub.`name` as product,
    group_concat(parent.`name` separator ' > ') as name
from
    categories as parent,
    categories as node,
    (select
        a.`name` as name,
        a.`categoryId` as category
    from
        categories as node,
        categories as parent,
        articles as a
    where
        parent.`id`=4 /* Kategori som agerar rot */
        and
        node.`lft` between parent.`lft` and parent.`rgt`
        and
        a.`categoryId`=node.`id`) as sub
where
    node.`lft` between parent.`lft` and parent.`rgt`
    and
    node.`id`=sub.`category`
group by
    sub.`category`
262 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2
128 ms — deklarationer (db)
0 ms — hämta statistik (cache)
131 ms — hämta tråd, inlägg och bilagor (db)
128 ms — ändringar (db)