CTE немного новы для меня, поэтому я надеюсь, что кто-то может помочь со следующим, который я написал, который возьмет таблицу категорий и построит из нее иерархию для отображения. Я знаю, что подобные вещи спрашивают постоянно, но я думаю, что моя ситуация с сортировкой делает ее немного уникальной.
Я ожидаю, что ряд предложений будет использовать HierarchyID, но, к сожалению, это не вариант по длинному списку причин, которые здесь не актуальны. Решение, которое я придумала, хотя и работает и дает мне ожидаемые данные, но мне интересно, есть ли лучший / более элегантный способ сделать это.
Основные требования следующие:
- Категории могут иметь неограниченное количество детей
- Категории могут иметь неограниченное количество уровней глубины
- Категории с одним и тем же родителем будут отсортированы на основе поля «сортировка». Если он не указан (по умолчанию 0) или совпадает с другой категорией, он будет отсортирован в алфавитном порядке.
Определение таблицы:
CREATE TABLE [dbo].[TreeTest]
(
[id] [int] NOT NULL,
[parent] [int] NULL,
[title] [varchar](50) NOT NULL,
[sort] [int] NOT NULL
)
GO
ALTER TABLE [dbo].[TreeTest] ADD CONSTRAINT [DF_TreeTest_sort] DEFAULT ((0)) FOR [sort]
GO
Вставить операторы:
INSERT TreeTest(id,parent,title,sort) VALUES('1',NULL,'Parent 1','0')
INSERT TreeTest(id,parent,title,sort) VALUES('2',NULL,'Parent 2','0')
INSERT TreeTest(id,parent,title,sort) VALUES('3',NULL,'Parent 3','2')
INSERT TreeTest(id,parent,title,sort) VALUES('4',NULL,'Parent 4','1')
INSERT TreeTest(id,parent,title,sort) VALUES('5','1','Child 1a','0')
INSERT TreeTest(id,parent,title,sort) VALUES('6','2','Child 2a','0')
INSERT TreeTest(id,parent,title,sort) VALUES('7','3','Child 3a','0')
INSERT TreeTest(id,parent,title,sort) VALUES('8','1','Child 1b','1')
INSERT TreeTest(id,parent,title,sort) VALUES('9','1','Child 1c','2')
INSERT TreeTest(id,parent,title,sort) VALUES('10','1','Child 1d','1')
INSERT TreeTest(id,parent,title,sort) VALUES('11','6','Child 2a 1','0')
INSERT TreeTest(id,parent,title,sort) VALUES('12','6','Child 2a 2','1')
INSERT TreeTest(id,parent,title,sort) VALUES('13','6','Child 2a 3','0')
INSERT TreeTest(id,parent,title,sort) VALUES('14','6','Child 2a 4','2')
CTE:
WITH TreeList (id, parent, title, sort, title_path, level_id, level_id_path) as
(
SELECT p.id,
p.parent,
p.title,
p.sort,
CONVERT(nvarchar(max), p.title),
ROW_NUMBER() OVER(PARTITION BY parent ORDER BY p.sort, p.title),
CAST(ROW_NUMBER() OVER(PARTITION BY parent ORDER BY p.sort) AS varchar(max))
FROM TreeTest p
WHERE p.parent is null
UNION ALL
SELECT c.id,
c.parent,
c.title,
c.sort,
r.title_path + '/' + c.title,
ROW_NUMBER() OVER(PARTITION BY c.parent ORDER BY c.sort, c.title),
CONVERT(varchar(max), r.level_id_path + '.' + CAST(ROW_NUMBER() OVER(PARTITION BY c.parent ORDER BY c.sort, c.title) AS VARCHAR))
FROM TreeTest AS c
INNER JOIN treelist AS r
ON c.parent = r.id
)
SELECT *
FROM TreeList
ORDER BY level_id_path
Вывод (я подумал, что изображение было самым простым способом показать вывод)
Опять же, это работает в соответствии со спецификациями, которые у меня есть, но я не уверен в эффективности и в том, есть ли лучший способ сделать это. Когда я смотрю на план выполнения для этого, кажется, что самым дорогим является сканирование с сортировкой / индексированием, но это кажется ожидаемым, учитывая отсутствие индексов в этом примере. Если у кого-то есть какие-либо материалы, это будет с благодарностью.