Typisk er der tre slags forespørgsler i hierarkierne, som forårsager problemer:
- Tilbagefør alle forfædre
- Returner alle efterkommere
- Returner alle børn (umiddelbare efterkommere).
Her er en lille tabel, som viser ydelsen af forskellige 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, at svaret afhænger af, om du blander metoden med adjacency list, dvs. e. lagring af parentID
i hver post.
Til din opgave har du brug for alle tre forespørgsler:
- Alle forfædre skal vise Jorden / Storbritannien / Devon tingen
- Alle børn skal vise "Destinationer i Europa" (genstandene)
- Alle efterkommere skal vise "Destinationer i Europa" (tæller)
Jeg ville gå efter materialiserede veje, da denne form for hierarki sjældent ændrer sig (kun i tilfælde af krig, oprør osv.).
Opret en varchar-kolonne kaldet path
, indekser det og udfyld det med værdien som denne:
1:234:6345:45454:
hvor tallene er primærnøgler for de relevante forældre, i korrekt rækkefølge (1
for Europa, 234
for Storbritannien osv.)
Du skal også bruge en tabel kaldet levels
for at beholde numre fra 1
til 20
(eller hvilket maksimalt indlejringsniveau du ønsker).
Sådan vælger du alle forfædre:
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ådan vælger du alle børn og antal steder inden for 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