2016-10-15 5 views
3

У меня есть запрос для идентификации узлов в дереве с родительским отношением. Что не так с этим запросом? Хотя у меня есть внутренние узлы, соответствующий регистр событий никогда не выполняется. Всегда я получаю результат как Лист или Корневые узлы. Никогда не получайте Inner на выходе. Что я могу сделать неправильно?Специфичный пример оператора SQL CASE

WITH CTE(N, P, [Level]) 
AS 
(
    SELECT N, P, 1 FROM 
    BST B 
    WHERE P IS NULL 
    UNION ALL 
    SELECT B.N, B.P, [Level] + 1 FROM 
    BST B 
    JOIN CTE ON B.P = CTE.N 
) 
SELECT N, 
CASE 
WHEN [Level] = 1 Then 'Root' 
WHEN [Level] < MAX([Level]) AND [Level] > 1 THEN 'Inner' 
WHEN [Level] = MAX([Level]) THEN 'Leaf' 
END 
FROM CTE 
GROUP BY N, [Level] 
ORDER BY N ASC; 

Пример ввода

N P 
1 2 
3 2 
6 8 
9 8 
2 5 
8 5 
5 NULL 

Пример вывода

1 Leaf 
2 Inner 
3 Leaf 
5 Root 
6 Leaf 
8 Inner 
9 Leaf 
+0

Вы можете разместить некоторые выборочные данные, а также, чтобы мы могли воспроизвести проблему? –

ответ

4

Зачем строить Фрахтователь? Просто обратите внимание, что если это иерархическая иерархия, Max (Level) не обязательно будет работать. Например, узел листа является уровень 3, но уровень Макс 6.

Declare @YourTable table (N int,P int) 
Insert Into @YourTable values 
(1, 2), 
(3, 2), 
(6, 8), 
(9, 8), 
(2, 5), 
(8, 5), 
(5, NULL) 

Select A.* 
     ,Lvl = case when A.P is null then 'Root' else case when B.P is null then 'Leaf' else 'Inner' end end 
From @YourTable A 
Left Join (Select Distinct P from @YourTable) B on A.N=B.P 

Возвращает

N P Lvl 
1 2 Leaf 
3 2 Leaf 
6 8 Leaf 
9 8 Leaf 
2 5 Inner 
8 5 Inner 
5 NULL Root 
1

Вы добавили level в Group by, так что вы не будете получать max уровня из всех записей

Вы можете сделать это с помощью Max Over() окна функции совокупного

Вот один из способов

SELECT N, 
     CASE 
     WHEN [Level] = 1 THEN 'Root' 
     WHEN [Level] < Max([Level]) over() 
       AND [Level] > 1 THEN 'Inner' 
     WHEN [Level] = Max([Level]) over() THEN 'Leaf' 
     END 
FROM CTE 
ORDER BY N ASC; 
+0

Отлично. Спасибо за объяснение. – ckv

2

Вы можете использовать следующий запрос:

WITH CTE(N, P, [Level]) 
AS 
(
    SELECT N AS Node, N AS P, 1 as Level 
    FROM BST B 
    WHERE P IS NULL 

    UNION ALL 

    -- Propagate parent to all subsequent nodes 
    SELECT B.N, CTE.P, Level = [Level] + 1 
    FROM BST B 
    JOIN CTE ON B.P = CTE.N 
) 
SELECT N, 
     CASE 
      WHEN [Level] = 1 THEN 'Root' 
      WHEN [Level] > 1 AND [Level] < MAX([Level]) OVER (PARTITION BY P) THEN 'Inner' 
      WHEN [Level] = MAX([Level]) OVER (PARTITION BY P) THEN 'Leaf' 
     END 
FROM CTE  
ORDER BY N ASC; 

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

Demo here