Existem outras maneiras de organizar dados hierárquicos além dos métodos mostrados no blog de Mike Hillyer. Eu gosto de usar um método que chamo de tabela de fechamento transitivo ou mesa de fechamento para breve. Neste design, você armazena cada caminho através da hierarquia, como pares ancestrais/descendentes.
create table closure (
ancestor int,
descendant int,
length int,
primary key (ancestor,descendant),
key (descendant,ancestor)
);
insert into closure values
(1,1,0),
(1,3,1),
(1,4,2),
(1,5,3),
(2,2,0),
(3,3,0),
(3,4,1),
(3,5,2),
(4,4,0),
(4,5,1),
(5,5,0);
Observe que este conjunto inclui até mesmo os "caminhos" de comprimento zero, ou seja, um item de menu é um "pai" de si mesmo.
Agora você pode juntar cada item de menu
m
para cada conjunto de ancestrais a
, juntando-se a caminhos onde m
é o descendente. A partir daí, volte ao item de menu o
que está no conjunto de ancestrais, e você pode acessar o order
. Use GROUP_CONCAT() para fazer uma string de "migalhas de pão" do
order
de cada um na cadeia de ancestrais, e isso se torna uma string pela qual você pode classificar para obter a ordem do menu desejada. SELECT m.*, GROUP_CONCAT(o.`order` ORDER BY a.length DESC) AS breadcrumbs
FROM menu AS m
INNER JOIN closure AS a ON a.descendant = m.id
INNER JOIN menu AS o ON a.ancestor = o.id
GROUP BY m.id
ORDER BY breadcrumbs;
+----+----------+-------+-------------+
| id | name | order | breadcrumbs |
+----+----------+-------+-------------+
| 1 | Father1 | 0 | 0 |
| 3 | Son | 0 | 0,0 |
| 4 | Child | 1 | 0,0,1 |
| 5 | Grandson | 2 | 0,0,1,2 |
| 2 | Father2 | 1 | 1 |
+----+----------+-------+-------------+
Observe que as migalhas de pão são classificadas como uma string, portanto, se você tiver algum
order
números com 2 ou 3 dígitos, você obterá resultados irregulares. Certifique-se de que seu order
todos os números têm o mesmo número de dígitos. Como alternativa, você pode simplesmente armazenar as strings breadcrumbs em sua tabela de menu original:
ALTER TABLE menu ADD COLUMN breadcrumbs VARCHAR(255);
UPDATE menu SET breadcrumbs = '0,0,1,2' WHERE id = 5;
etc.
Então você pode fazer uma consulta mais simples:
SELECT * FROM menu ORDER BY breadcrumbs;
Mas cabe a você recalcular manualmente todas as strings de breadcrumb afetadas, se você alterar a ordem dos itens de menu.