Dada uma tabela hierárquica como esta:
CREATE TABLE [dbo].[btree]
(
id INT PRIMARY KEY
, parent_id INT REFERENCES [dbo].[btree] ([id])
, name NVARCHAR(20)
);
Eu gostaria de obter toda a estrutura da árvore.
Por exemplo, usando esses dados:
INSERT INTO [btree] VALUES (1, null, '1 Root');
INSERT INTO [btree] VALUES (2, 1, '1.1 Group');
INSERT INTO [btree] VALUES (3, 1, '1.2 Group');
INSERT INTO [btree] VALUES (4, 2, '1.1.1 Group');
INSERT INTO [btree] VALUES (5, 2, '1.1.2 Group');
INSERT INTO [btree] VALUES (6, 3, '1.2.1 Group');
INSERT INTO [btree] VALUES (7, 3, '1.2.2 Group');
INSERT INTO [btree] VALUES (8, 4, '1.1.1.1 Items');
INSERT INTO [btree] VALUES (9, 4, '1.1.1.2 Items');
INSERT INTO [btree] VALUES (10, 5, '1.1.2.1 Items');
INSERT INTO [btree] VALUES (11, 5, '1.1.1.2 Items');
INSERT INTO [btree] VALUES (12, 6, '1.2.1.1 Items');
INSERT INTO [btree] VALUES (13, 6, '1.2.1.2 Items');
INSERT INTO [btree] VALUES (14, 7, '1.2.2.1 Items');
gostaria de obter:
+----+-----------+---------------------+
| id | parent_id | description |
+----+-----------+---------------------+
| 1 | NULL | 1 Root |
| 2 | 1 | 1.1 Group |
| 4 | 2 | 1.1.1 Group |
| 8 | 4 | 1.1.1.1 Items |
| 9 | 4 | 1.1.1.2 Items |
| 5 | 2 | 1.1.2 Group |
| 10 | 5 | 1.1.2.1 Items |
| 11 | 5 | 1.1.2.2 Items |
| 3 | 1 | 1.2 Group |
| 6 | 3 | 1.2.1 Group |
| 12 | 6 | 1.2.1.1 Items |
| 13 | 6 | 1.2.1.2 Items |
| 7 | 3 | 1.2.2 Group |
| 14 | 7 | 1.2.2.1 Items |
+----+-----------+---------------------+
Estou buscando registros usando uma consulta recursiva como esta:
;WITH tree AS
(
SELECT c1.id, c1.parent_id, c1.name, [level] = 1
FROM dbo.[btree] c1
WHERE c1.parent_id IS NULL
UNION ALL
SELECT c2.id, c2.parent_id, c2.name, [level] = tree.[level] + 1
FROM dbo.[btree] c2 INNER JOIN tree ON tree.id = c2.parent_id
)
SELECT tree.level, tree.id, parent_id, REPLICATE(' ', tree.level - 1) + tree.name AS description
FROM tree
OPTION (MAXRECURSION 0)
;
E este é o resultado atual:
+----+-----------+---------------------+
| id | parent_id | description |
| 1 | NULL | 1 Root |
| 2 | 1 | 1.1 Group |
| 3 | 1 | 1.2 Group |
| 6 | 3 | 1.2.1 Group |
| 7 | 3 | 1.2.2 Group |
| 14 | 7 | 1.2.2.1 Items |
| 12 | 6 | 1.2.1.1 Items |
| 13 | 6 | 1.2.1.2 Items |
| 4 | 2 | 1.1.1 Group |
| 5 | 2 | 1.1.2 Group |
| 10 | 5 | 1.1.2.1 Items |
| 11 | 5 | 1.1.1.2 Items |
| 8 | 4 | 1.1.1.1 Items |
| 9 | 4 | 1.1.1.2 Items |
+----+-----------+---------------------+
Não consigo descobrir como ordená-lo por níveis.
Existe uma maneira de definir uma classificação para cada subnível?
Eu configurei umRextester
Adicione um campo "caminho" e classifique por semelhante a um caminho de arquivo. Como o ypercube mencionou, a classificação é excessivamente simplista neste exemplo e simplesmente funciona, mas, para simplificar, deixarei como está. Na maioria das vezes, quando uso esse padrão, classifico por nome em vez de ID.
aqui um rextester
Trapaça, só um pouquinho ;) Olha ma, sem recursão!
Testado em rextester.com
Claro que o acima é bastante limitado. Ele funciona apenas sob as suposições:
name
coluna armazenou (na primeira parte) o "caminho" real.CAST .. AS int
é necessário apenas se as partes forem números.Explicação: O código funciona usando a função
PARSENAME()
que tem como objetivo principal dividir um nome de objeto em suas 4 partes:Note que a ordem é inversa. Como exemplo,
PARSENAME('dbo.btree', 2)
nos dará'dbo'
como resultado. Com 3, obteremos NULL (é por isso que oREVERSE()
é usado duas vezes no código. Caso contrário, obteríamos os nulos no início. O'1.2'
seria analisadonull, null, 1, 2
enquanto queremos1, 2, null, null
. )Conclusão: depois de tudo isso, devo acrescentar que a resposta de Bob Campbel é o caminho a seguir, pois é mais geral e produz (na coluna "path" no resultado) a hierarquia do caminho, que pode ser usada para o arquivo
ORDER BY
.Outras opções que você pode considerar - se o tamanho da tabela aumentar e a solução recursiva se tornar lenta - é armazenar o caminho em uma coluna separada (em um formato bom para ordenação, ou seja, com preenchimento) ou usar o fornecido
HierarchyID
tipo que é exatamente para este caso de uso, dados hierárquicos.