2016-01-22 3 views
0

У меня есть схемы базы данных: [Id], [ParrentId], [ещё несколько таблиц]SQL получить самый низкий уровень детской и корневой узел

У меня есть иерархия, как:

1. a 
2. aa 
    3. aaa_1 
    3. aaa_2 
1. b 
2. bb 
1. c 
2. cc 
    3. ccc_1 
    4. cccc 
    3. ccc_2 

Я хочу (выберите * где X) => [X, младший ребенок]: [a, aaa_1] [a, aaa_2]; [Куб.см, сссс] и т.д.

я могу получить наименьшую ребенка с

SELECT t1.name FROM 
category AS t1 LEFT JOIN category as t2 
ON t1.category_id = t2.parent 
WHERE t2.category_id IS NULL; 

, но я не знаю, как присоединиться к нему с корневого узла.

+0

Какие СУБД вы используете? Postgres? Oracle? –

+0

Я бы предложил добавить поле, отражающее уровень иерархии. Затем используйте следующий SQL: SELECT name, max (level) FROM category WHERE parent = {category_id родителя} – ahPo

ответ

1

Дано:

  • СУБД является SQL Server;
  • Узлы верхнего уровня дерева имеют родительский = NULL;
  • Вы хотите, чтобы все нижние листья для всех уровней деревьев, а не только корни;
  • Вы хотите иметь все узлы на самом низком уровне, а не только один;

Этот запрос будет сделать это:

WITH r (category_id, name, root, depth) 
-- finds the root relationship 
AS (
    SELECT category_id, name, category_id, 0 
     FROM category 
     -- WHERE parent IS NULL -- this would only look at root nodes 
    UNION ALL 
    SELECT c.category_id, c.name, r.root, r.depth + 1 
     FROM r 
     JOIN category c 
      ON c.parent = r.category_id 
), s (category_id, name, root, window_id) 
-- finds the lowest leaves 
AS (
    SELECT category_id, name, root, RANK() OVER(partition by root order by depth DESC) 
     FROM r 
) 
SELECT c.name AS NodeName, s.Name AS DeepLeafName 
    FROM category c 
    JOIN s 
     ON c.category_id = s.root 
     WHERE s.window_id = 1; 

Вот результирующий набор:

result set

0

С SQL Server, вы можете попробовать это:

With CTE as 
(
Select ID as Child, lev = 1 
from category 
where ID = X 
UNION ALL 
Select category.ID, CTE.lev + 1 
from category 
    inner join CTE ON category.ParentID = CTE.Child 
) 

select CTE_1.Child, CTE_2.Child 
from CTE as CTE_1 
    inner join CTE as CTE_2 
where CTE_1.lev = 1 AND CTE_2.lev = (select MAX(CTE.lev) from CTE) 
Смежные вопросы