在分层树中查找每个组的叶节点

时间:2017-01-17 23:13:21

标签: sql sql-server

我有以下表格。表T1中的类型列遵循表T2中的层次结构。我想在表T1中列出每个名称的类型,并找到每个名称的叶子。

      T1                              T2
name      type                    type       parent
----------------                --------------------
a1      person                |  artist     person       
a1      artist                |  actor      artist
a2      person                |  athlete    person
a2      athlete               |  person       ''
a3      person                       
a3      artist                
a3      actor                 

查找每个名称的叶节点的常用查询在这里不起作用

select a.* from T1 a left join   T2 b on a.type = b.parent where b.parent is null; 
a2      athlete               
a3      actor   

但我正在寻找此输出(每个组名称的叶节点)

a1      artist                
a2      athlete               
a3      actor

换句话说我想找到每个名字的叶节点,所以在a1的情况下,[人,艺术家]之间的叶节点将是艺术家,而对于a3 [人,艺术家,演员],它将是演员。 /> 有没有办法使用GROUP BY并获得所需的输出

1 个答案:

答案 0 :(得分:1)

这是代码

WITH cte AS (
SELECT
    t1.name AS anchor_name
    , t1.type AS type
    , t2.parent
    , 0 AS level
FROM #T1 t1 JOIN #T2 t2 ON t1.type = t2.type 

UNION ALL

SELECT cte.anchor_name, cte.type, t2.parent, cte.level+1
FROM cte JOIN #T2 t2 ON cte.parent = t2.type
)
, tmp AS (
    SELECT anchor_name, MAX(cte.level) AS max_level
    FROM cte 
    GROUP BY cte.anchor_name
)
SELECT cte.anchor_name as name, cte.type
FROM tmp JOIN cte ON cte.anchor_name = tmp.anchor_name AND cte.level = tmp.max_level

这是测试代码:

CREATE TABLE #T1 (
    name VARCHAR(2)
    , type VARCHAR(MAX)
    );

CREATE TABLE #T2 (
    type VARCHAR(MAX)
    , parent VARCHAR(MAX)
    );

INSERT INTO #T1 (name, type)
VALUES
('a1', 'artist')
,('a1', 'person')
,('a2', 'person')
,('a2', 'athlete')
,('a3', 'person')
,('a3', 'artist')
,('a3', 'actor');

INSERT INTO #T2 (type, parent)
VALUES
('artist'    , 'person')
,('actor'     , 'artist')
,('athlete'   , 'person')
,('person'    ,   '');


SELECT *
FROM #T1;

SELECT *
FROM #T2;

WITH cte AS (
    SELECT
        t1.name AS anchor_name
        , t1.type AS type
        , t2.parent
        , 0 AS level
    FROM #T1 t1 JOIN #T2 t2 ON t1.type = t2.type 

    UNION ALL

    SELECT cte.anchor_name, cte.type, t2.parent, cte.level+1
    FROM cte JOIN #T2 t2 ON cte.parent = t2.type
    )
, tmp AS (
    SELECT anchor_name, MAX(cte.level) AS max_level
    FROM cte 
    GROUP BY cte.anchor_name
)
SELECT cte.anchor_name as name, cte.type
FROM tmp JOIN cte ON cte.anchor_name = tmp.anchor_name AND cte.level = tmp.max_level

http://rextester.com/TRD23741