Por lo general, hay tres tipos de consultas en las jerarquías que causan problemas:
- Devolver todos los ancestros
- Devolver todos los descendientes
- Regresar a todos los hijos (descendientes inmediatos).
Aquí hay una pequeña tabla que muestra el rendimiento de diferentes métodos en 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
En children
, poor/excellent
significa que la respuesta depende de si está mezclando el método con la lista de adyacencia, i. mi. almacenar el parentID
en cada registro.
Para su tarea, necesita las tres consultas:
- Todos los ancestros para mostrar la cosa de la Tierra/Reino Unido/Devon
- Todos los niños deben mostrar "Destinos en Europa" (los elementos)
- Todos los descendientes para mostrar "Destinos en Europa" (los condes)
Yo optaría por caminos materializados, ya que este tipo de jerarquía rara vez cambia (solo en caso de guerra, revuelta, etc.).
Cree una columna varchar llamada path
, indexarlo y llenarlo con el valor como este:
1:234:6345:45454:
donde los números son claves primarias de los padres apropiados, en el orden correcto (1
para Europa, 234
para Reino Unido, etc.)
También necesitará una tabla llamada levels
para mantener los números de 1
a 20
(o el nivel máximo de anidamiento que desee).
Para seleccionar todos los antepasados:
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
Para seleccionar todos los niños y la cantidad de lugares dentro de ellos:
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