После преодоления всех препятствий с помощью индексированных представлений (самосоединение, cte, доступ к данным в формате udf и т. Д.) Я предлагаю использовать приведенное ниже решение.
Создать функцию поддержки
На основе максимальной глубины 4 от корня (всего 5). Или используйте CTE
CREATE FUNCTION dbo.GetHierPath(@hier_id int) returns varchar(max)
WITH SCHEMABINDING
as
begin
return (
select FullPath =
isnull(H5.Name+'/','') +
isnull(H4.Name+'/','') +
isnull(H3.Name+'/','') +
isnull(H2.Name+'/','') +
H1.Name
+
':'
+
isnull(STUFF(
isnull(','+A1.abbreviation,'') +
isnull(','+A2.abbreviation,'') +
isnull(','+A3.abbreviation,'') +
isnull(','+A4.abbreviation,'') +
isnull(','+A5.abbreviation,''),1,1,''),'')
from dbo.HIER H1
left join dbo.ABBR A1 on A1.hier_id = H1.Id
left join dbo.HIER H2 on H1.ParentId = H2.Id
left join dbo.ABBR A2 on A2.hier_id = H2.Id
left join dbo.HIER H3 on H2.ParentId = H3.Id
left join dbo.ABBR A3 on A3.hier_id = H3.Id
left join dbo.HIER H4 on H3.ParentId = H4.Id
left join dbo.ABBR A4 on A4.hier_id = H4.Id
left join dbo.HIER H5 on H4.ParentId = H5.Id
left join dbo.ABBR A5 on A5.hier_id = H5.Id
where H1.id = @hier_id)
end
GO
Добавление столбцов в саму таблицу
Например, столбец полного пути, если вам нужно, добавьте два других столбца в CTE, разделив результат dbo.GetHierPath на ':' (left=>path, right=>abbreviations)
-- index maximum key length is 900, based on your data, 400 is enough
ALTER TABLE HIER ADD FullPath VARCHAR(400)
Поддерживать столбцы
Из-за иерархической природы запись X может быть удалена, что влияет на потомок Y и Z предка, что довольно трудно идентифицировать в триггерах INSTEAD OF или AFTER. Таким образом, альтернативный подход основан на условиях
- если данные изменяются в любой из таблиц, к которой присоединяется представление, то представление должно обновляться само.
- Неиндексированное представление с использованием CTE занимает 3-5 секунд, что слишком долго для моих нужд
Мы обслуживаем данные просто, снова просматривая всю таблицу, занимая 3-5 секунд на обновление (или быстрее, если запрос с 5 объединениями работает лучше).
CREATE TRIGGER TG_HIER
ON HIER
AFTER INSERT, UPDATE, DELETE
AS
UPDATE HIER
SET FullPath = dbo.GetHierPath(HIER.Id)
Наконец, индексируйте новый столбец (столбцы) на самой таблице
create index ix_hier_fullpath on HIER(FullPath)
Если вы намеревались получить доступ к данным пути через идентификатор, то они уже находятся в самой таблице без добавления дополнительного индекса.
Приведенный выше TSQL ссылается на эти объекты
Измените имена таблиц и столбцов в соответствии с вашей схемой.
CREATE TABLE dbo.HIER (Id INT Primary Key Clustered, [Name] VARCHAR(20) ,ParentId INT)
;
INSERT dbo.HIER( Id, Name, ParentId ) VALUES
(1, 'Europe', NULL)
,(2, 'Asia', NULL)
,(3, 'Germany', 1)
,(4, 'UK', 1)
,(5, 'China', 2)
,(6, 'India', 2)
,(7, 'Scotland', 4)
,(8, 'Edinburgh', 7)
,(9, 'Leith', 8)
,(10, 'Antartica', NULL)
;
CREATE TABLE dbo.ABBR (id int primary key clustered, abbreviation varchar(10), hier_id int)
;
INSERT dbo.ABBR( Id, Abbreviation, hier_id ) VALUES
(100, 'EU', 1)
,(101, 'AS', 2)
,(102, 'DE', 3)
,(103, 'CN', 5)
GO
РЕДАКТИРОВАТЬ - Возможно, более быстрая альтернатива
Учитывая, что все записи пересчитываются каждый раз, нет реальной необходимости в функции, которая возвращает FullPath
для одного HIER.ID. Запрос в support function
можно использовать без фильтра where H1.id = @hier_id
в конце. Кроме того, выражение для FullPath
может быть разбито на PathOnly
и Abbreviation
легко посередине. Или просто используйте оригинальный CTE, в зависимости от того, что быстрее.