Vanligtvis finns det tre typer av frågor i hierarkierna som orsakar problem:
- Tillbaka alla förfäder
- Tillbaka alla ättlingar
- Tillbaka alla barn (direkta ättlingar).
Här är en liten tabell som visar prestanda för olika metoder i MySQL
:
Ancestors Descendants Children Maintainability InnoDB
Adjacency list Good Decent Excellent Easy Yes
Nested sets (classic) Poor Excellent Poor/Excellent Very hard Yes
Nested sets (spatial) Excellent Very good Poor/Excellent Very hard No
Materialized path Excellent Very good Poor/Excellent Hard Yes
I children
, poor/excellent
betyder att svaret beror på om du blandar metoden med adjacency list, dvs. e. lagra parentID
i varje post.
För din uppgift behöver du alla tre frågorna:
- Alla förfäder för att visa Earth / UK / Devon-grejen
- Alla barn ska visa "Destinationer i Europa" (objekten)
- Alla ättlingar ska visa "Destinationer i Europa" (antalerna)
Jag skulle gå för materialiserade vägar, eftersom denna typ av hierarki sällan förändras (endast vid krig, revolt etc).
Skapa en varchar-kolumn som heter path
, indexera det och fyll det med värdet så här:
1:234:6345:45454:
där siffrorna är primärnycklar för lämpliga föräldrar, i korrekt ordning (1
för Europa, 234
för Storbritannien etc.)
Du behöver också en tabell som heter levels
för att behålla nummer från 1
till 20
(eller vilken maximal häckningsnivå du vill ha).
Så här väljer du alla förfäder:
SELECT pa.*
FROM places p
JOIN levels l
ON SUBSTRING_INDEX(p.path, ':', l.level) <> p.path
JOIN places pa
ON pa.path = CONCAT(SUBSTRING_INDEX(p.path, ':', l.level), ':')
WHERE p.id = @id_of_place_in_devon
Så här väljer du alla barn och antal platser inom dem:
SELECT pc.*, COUNT(pp.id)
FROM places p
JOIN places pc
ON pc.parentId = p.id
JOIN places pp
ON pp.path BETWEEN pc.path AND CONCAT(pc.path, ':')
AND pp.id NOT IN
(
SELECT parentId
FROM places
)
WHERE p.id = @id_of_europe
GROUP BY
pc.id