Имеется иерархическая таблица, подобная этой:
CREATE TABLE [dbo].[btree]
(
id INT PRIMARY KEY
, parent_id INT REFERENCES [dbo].[btree] ([id])
, name NVARCHAR(20)
);
Я хотел бы получить всю древовидную структуру.
Например, используя эти данные:
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');
Я хотел бы получить:
+----+-----------+---------------------+
| 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 |
+----+-----------+---------------------+
Я выбираю записи, используя рекурсивный запрос, подобный этому:
;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)
;
И это текущий результат:
+----+-----------+---------------------+
| 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 |
+----+-----------+---------------------+
Я не могу понять, как заказать его по уровням.
Есть ли способ установить ранг для каждого подуровня?
Я создал Rextester
t-sql
sql-server-2014
hierarchy
McNets
источник
источник
c2.id
заменить row_number и дополнить его слева, чтобы все части имели одинаковую длину. В противном случае это не сработает для всех данных. Просто замените 2 на 55 в данных и порядок изменитсяPath
с небольшой поправкой, чтобы добавить отступы.Обман, только немного;) Смотри, мам, нет рекурсии!
Проверено на rextester.com
Конечно, вышесказанное довольно ограничено. Работает только при допущениях:
name
столбец сохраняется (в первой части) фактического «пути».CAST .. AS int
нужно только если части номер.Объяснение: Код работает с использованием функции
PARSENAME()
, основной целью которой является разбиение имени объекта на 4 части:Обратите внимание, что порядок обратный. Как пример,
PARSENAME('dbo.btree', 2)
даст нам'dbo'
в результате. С 3 мы получим NULL (вот почемуREVERSE()
в коде используется дважды. В противном случае мы получили бы нулевые значения в начале. Они'1.2'
будут проанализированы,null, null, 1, 2
когда мы захотим1, 2, null, null
. )Вывод: после всего этого я должен добавить, что ответ Боба Кэмпбела - это путь, поскольку он более общий и создает (в столбце «путь» в результате) иерархию путей, которую затем можно использовать для
ORDER BY
.Другие варианты, которые вы можете рассмотреть - если размер таблицы увеличивается, а рекурсивное решение становится медленным, - это фактически сохранить путь в отдельном столбце (в формате, который удобен для упорядочения, то есть с отступом) или использовать предоставленный
HierarchyID
тип, который именно для этого варианта использования, иерархические данные.источник
name
не может быть использовано в этом случае. Мне понадобится вся ночь, чтобы расшифровать его, могу ли я дать какое-нибудь объяснение?name
он хранит путь (с текстом), например'order173.palletA27.box9'.bag3A
, вы все равно можете использовать код (просто удалите приведения к int). В любом случае, запрос от BenCambell - это общий путь.