Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

SQL Server CTE ляво външно съединение

Ако не е известно колко нива има в йерархията?

Тогава такова предизвикателство често се извършва чрез рекурсивен CTE.

Примерен фрагмент:

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

Резултат:

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

Между другото, рекурсивният CTE използва OUTER APPLY, защото MS SQL Server не позволява LEFT OUTER JOIN да се използва там.

И ако е сигурно, че има максимум 1 дълбочина на ниво за upid с бюджет?
Тогава ще свършат работа само с прости леви съединения и сливане.

Например:

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. Как да изпълня съхранена процедура веднъж за всеки ред, върнат от заявка?

  2. SQL Как да определите дали датата на месеца съдържа 29, 30 или 31

  3. Как да обработваме динамични sql параметри

  4. Как да генерирате изявление за добавяне на колона за всички таблици в база данни в SQL Server - SQL Server / T-SQL урок, част 49

  5. tsql връща таблица от функция или процедура за съхранение