Pregunta

Tengo una tabla de MySQL que actúa como un conjunto anidado con el fin de contener una jerarquía de categorías. El esquema de la tabla se ve así:

CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(200) NOT NULL,
  `parent_id` int(11) default NULL,
  `lft` int(11) default NULL,
  `rgt` int(11) default NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `index_categories_on_parent_id_and_name` (`parent_id`,`name`)
)

lft y rgt definen los límites izquierdo y derecho de un nodo (la forma de un conjunto anidado funciona es que el id de cada nodo cae dentro de los límites de su matriz), y parent_id especifica el nodo padre. El índice único permite que haya múltiples categorías con el mismo nombre, siempre y cuando no tienen el mismo padre.

Estoy tratando de encontrar una forma adecuada para encontrar un nodo específico en el conjunto, basado en la jerarquía. Por ejemplo, si busco foo / bar / baz, quiero recuperar el nodo denominado Baz, cuyo padre se llama la barra, que es el padre se llama foo. Obviamente, no puedo buscar por nombre, porque puede haber múltiples categorías con el mismo nombre.

La forma en que puedo pensar en hacer esto es encontrar la categoría más alta, y luego encontrar cada categoría posterior con el nombre dado cuya ID de padre es la de la categoría anteriormente encontrado, pero esto no parece muy eficaz para mí. ¿Hay una mejor manera de buscar un conjunto anidado?

¿Fue útil?

Solución

No creo que hay una manera perfectamente limpia y eficiente de hacer esto con conjuntos anidados. Almacenar una lista de los ancestros del nodo en una columna desnormalizado proporcionaría esto de manera eficiente, pero no sugieren su aplicación.

Hay un método bien'Ish embargo, que es 1 consulta y será convenientemente golpear el índice que ya tiene. Se encuentra en el uno unen para cada nivel de profundidad del nodo de destino.

Para su ejemplo foo-bar-baz

select c3.*
from categories c1
inner join categories c2 on c2.parent_id = c1.id AND c2.name = 'bar'
inner join categories c3 on c3.parent_id = c2.id AND c2.name = 'baz'
where c1.name = 'foo'

No es el mejor, pero es probable que sea la mejor opción a menos que quiera hacer el esfuerzo de almacenar un montón de información sin normalizar. Es bastante sencillo para generar el SQL en código.

Otros consejos

TopVar = 'foo'
MidVar = 'bar'
BotVar = 'baz'

SELECT D0.*
FROM categories D0, categories D1, categories D2
WHERE D0.name = :BotVar
  AND D0.lft > D1.lft
  AND D0.rgt < D1.rgt
  AND D1.name = :MidVar
  AND D1.lft > D2.lft
  AND D1.rgt < D2.rgt
  AND D2.name = :TopVar;

-Al.

he visto esto antes en un proyecto PHP que fue entregado a mí, y uf, es sólo mal .. si se puede, dividirlo en al menos 2 tablas; tiene al menos 1 para las categorías 1 y para los artículos, por lo que puede unirse a .. De cualquier manera usted va a tener que hacer varias consultas me temo

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top