Si vous ne savez pas combien de niveaux il y a dans la hiérarchie ?
Ensuite, un tel défi est souvent effectué via un CTE récursif.
Exemple d'extrait :
--
-- Using table variables for testing reasons
--
declare @customertest table (cid int primary key, upid int);
declare @conftest table (cid int, confname varchar(6) default 'budget', confvalue int);
--
-- Sample data
--
insert into @customertest (cid, upid) values
(1,0), (2,1), (3,1), (4,2), (5,2), (6,3),
(7,5), (8,5), (9,8), (10,9);
insert into @conftest (cid, confvalue) values
(1,1000), (2,700), (3,300), (4,100), (5,200), (6,300);
-- The customer that has his own budget, or not.
declare @customerID int = 10;
;with RCTE AS
(
--
-- the recursive CTE starts from here. The seed records, as one could call it.
--
select cup.cid as orig_cid, 0 as lvl, cup.cid, cup.upid, budget.confvalue
from @customertest as cup
left join @conftest budget on (budget.cid = cup.cid and budget.confname = 'budget')
where cup.cid = @customerID -- This is where we limit on the customer
union all
--
-- This is where the Recursive CTE loops till it finds nothing new
--
select RCTE.orig_cid, RCTE.lvl+1, cup.cid, cup.upid, budget.confvalue
from RCTE
join @customertest as cup on (cup.cid = RCTE.upid)
outer apply (select b.confvalue from @conftest b where b.cid = cup.cid and b.confname = 'budget') as budget
where RCTE.confvalue is null -- Loop till a budget is found
)
select
orig_cid as cid,
confvalue
from RCTE
where confvalue is not null;
Résultat :
cid confvalue
--- ---------
10 200
Au fait, le CTE récursif utilise OUTER APPLY car MS SQL Server n'autorise pas l'utilisation d'un LEFT OUTER JOIN.
Et s'il est certain qu'il y a une profondeur maximale d'un niveau pour l'upid avec un budget ?
Ensuite, de simples jointures à gauche et une fusion suffiraient.
Par exemple :
select cup.cid, coalesce(cBudget.confvalue, upBudget.confvalue) as confvalue
from @customertest as cup
left join @conftest cBudget on (cBudget.cid = cup.cid and cBudget.confname = 'budget')
left join @conftest upBudget on (upBudget.cid = cup.upid and upBudget.confname = 'budget')
where cup.cid = 8;