Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

SQL Server CTE lewe sprzężenie zewnętrzne

Jeśli nie wiadomo, ile jest poziomów w hierarchii?

Wtedy takie wyzwanie jest często wykonywane za pomocą rekurencyjnego CTE.

Przykładowy fragment:

--
-- 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;    

Wynik :

cid confvalue
--- ---------
 10       200

Btw, rekurencyjne CTE używa OUTER APPLY, ponieważ MS SQL Server nie zezwala na użycie LEFT OUTER JOIN.

A jeśli jest pewne, że istnieje maksymalnie 1 poziom głębokości dla upid z budżetem?
W takim razie wystarczy proste lewe złączenia i połączenie.

Na przykład:

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;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zapytanie o zawartość procedur składowanych na serwerze SQL

  2. Jak uwzględnić wyniki związane z ostatnim miejscem podczas używania klauzuli TOP w SQL Server?

  3. wyzwalacz aktualizacji do aktualizacji rekordów w innej tabeli

  4. obliczyć zamykającą ilość zapasów, cenę i wartość według FIFO

  5. Jak obliczyć procent za pomocą instrukcji SQL