Вычисляемое поле SQL Server — данные из родительской записи

Я пытаюсь понять, могу ли я получить значение из родительского отношения в той же таблице.

В приведенном ниже примере Parent_ID является отношением к родителю. RouteName в идеале должно быть вычисляемым полем, которое выбирает имя маршрута прямого родителя (или имя, если оно равно нулю).

Таким образом, я мог бы создать полный маршрут, выбрав только прямого родителя, и сохранил бы итерацию или CTE для всех записей. Это возможно?

+----+------------------+-------------------------------------+-----------+
| ID | Name             | RouteName                           | Parent_ID |
+----+------------------+-------------------------------------+-----------+
| 1  | Parent           | NULL                                |           |
+----+------------------+-------------------------------------+-----------+
| 2  | Child 1          | Parent - Child 1                    | 1         |
+----+------------------+-------------------------------------+-----------+
| 3  | Child of Child 1 | Parent - Child 1 - Child of Child 1 | 2         |
+----+------------------+-------------------------------------+-----------+

person ExternalUse    schedule 01.12.2016    source источник
comment
Сколько уровней отцовства вы ожидаете? Если не предопределено, рекурсия была бы единственным разумным решением.   -  person FDavidov    schedule 01.12.2016
comment
У меня есть ограничение в три - почти так же, как указано выше.   -  person ExternalUse    schedule 01.12.2016
comment
Если бы я мог получить имя прямого родителя в вычисляемом поле, куда я мог бы объединить настоящее имя, моя проблема была бы решена. Псевдо: если Parent_ID не равен нулю, выберите Parent.Name + ' | ' + это.имя   -  person ExternalUse    schedule 01.12.2016
comment
ЕСЛИ вы ожидаете не более трех уровней, вы можете либо создать иерархический запрос, либо эквивалентное ему соединение. Я лично предпочитаю первое.   -  person FDavidov    schedule 01.12.2016
comment
Не могли бы вы уточнить, как бы вы сделали это в вычисляемом поле? Конечная цель состоит в том, чтобы иметь возможность выбирать записи, при этом RouteName содержит объединенное имя.   -  person ExternalUse    schedule 01.12.2016
comment
Просто для уточнения: для моих запросов и т. д. я использую иерархический запрос CTE. Чего я хотел бы добиться здесь, так это иметь возможность запрашивать Child of Child 1 (ID3) и видеть полный маршрут к нему.   -  person ExternalUse    schedule 01.12.2016
comment
Понятно... скажем, предоставить два идентификатора и, если между ними есть родительский путь, отобразить его (или обновить поле одного из них в таблице). Я правильно тебя понял?   -  person FDavidov    schedule 01.12.2016
comment
Допустим, вы вставляете ID 4, Name Child 2 из Child 1, Parent_ID 2. Затем (сохраняющийся) столбец autocompute будет искать RouteName ID2 и объединять имя ID 4 с ним. Результатом будет Родительский - Дочерний 1 - Дочерний 2 дочернего элемента 1. Тот же процесс произошел бы, когда ID 2 Дочерний элемент 1 был вставлен - он искал имя своего собственного родителя и создавал свое RouteName с помощью того же процесса. Я просто не знаю, смогу ли я получить это в вычисляемый столбец.   -  person ExternalUse    schedule 01.12.2016
comment
Понятно... Я меняю свое предложение. Я бы просто создал триггер ON INSERT и развернул правильное значение вместе с новыми (предоставленными) значениями.   -  person FDavidov    schedule 01.12.2016
comment
Я надеялся избежать триггера, но я полагаю, что другого варианта может и не быть. Спасибо за вашу помощь!   -  person ExternalUse    schedule 01.12.2016
comment
Да, есть и другие варианты, но этот самый простой. Кстати, если мои комментарии помогли вам, вы можете проголосовать за них.   -  person FDavidov    schedule 01.12.2016


Ответы (1)


Вы можете использовать функцию для вычисляемого столбца

drop table MyTable
drop function dbo.fn_CalculateRouteName

create table MyTable
(
    ID int,
    Name varchar(100),  
    Parent_ID int
)
go

create function dbo.fn_CalculateRouteName(@ID int)
returns varchar(max)
begin
declare @rtn varchar(max);

with cte (ID, Name) as (
    select Parent_ID, convert(varchar(max), Name) From MyTable where ID = @ID
    union all
    select MyTable.Parent_ID, convert(varchar(max), MyTable.Name + ' - ' + cte.Name )
    from cte
    inner join MyTable on cte.Id = MyTable.ID 
)
select @rtn = max(Name)
from cte

return @rtn
end
go

alter table MyTable add RouteName AS dbo.fn_CalculateRouteName(ID);

insert into MyTable(ID, Name, Parent_ID) values(1, 'Parent', null);
insert into MyTable(ID, Name, Parent_ID) values(2, 'Child 1', 1);
insert into MyTable(ID, Name, Parent_ID) values(3, 'Child of Child 1', 2);

select * from MyTable
person James Casey    schedule 01.12.2016
comment
Спасибо, Джеймс, я попробую это. Если я сохраню этот столбец, я думаю, накладные расходы на производительность могут быть не слишком значительными? Я все еще обдумываю триггерное решение, предложенное Ф.Давыдовым, но постараюсь и доложу. Я приму ответ после тестирования, если все в порядке. - person ExternalUse; 04.12.2016