如何使用遍历CTE生成树路径

时间:2018-07-03 17:28:39

标签: sql sql-server

假设我的数据在表中(如所附图片)没有路径列。 我想在SQL中使用遍历CTE生成一列,例如图片中的“路径”

图片示例:

enter image description here

2 个答案:

答案 0 :(得分:2)

使用recursive CTE解决此问题:

WITH recCTE
AS (
    SELECT id,
        parentid,
        id AS original_id,
        parentid AS original_parentid,
        name as original_name,
        1 AS depth,
        CAST(name AS VARCHAR(5000)) AS path
    FROM yourtable

    UNION ALL

    SELECT yourtable.id,
        yourtable.parentid, 
        recCTE.original_id,
        recCTE.original_parentID,
        recCTE.original_name,
        recCTE.depth + 1,
        CAST(recCTE.path + '-' + yourtable.name as VARCHAR(5000))
    FROM recCTE
    INNER JOIN yourtable
        ON recCTE.parentid = yourtable.id
    WHERE depth < 20 /*prevent cycling*/
    )
SELECT original_id as id, original_parentid as parentid, original_name as name, depth, path 
FROM recCTE t1
WHERE depth = (SELECT max(depth) FROM recCTE WHERE t1.original_id = recCTE.original_id)

sqlfiddle example

该CTE有两个部分:

  1. “锚成员”是表中的第一选择。定义输出(输出中包含哪些列和列类型)。
  2. 从其中包含它的CTE中选择的“递归成员”是反复执行的,直到连接失败。

在此示例中,我们通过在递归成员中一次又一次地将名称的路径串联在一起来捕获路径。我们还跟踪深度(执行了多少次递归),并跟踪当前的idparentid以及原始的id和原始的parentid,以便可以在其中选择最后的SELECT声明。

答案 1 :(得分:0)

尝试一下

;with cte(id,parentId,name,path,cnt)
AS
(
select id,parentid,name,cast(name as VARCHAR(1024)) as path, 1 as cnt from test_cte
union all
select a.id,a.parentid,a.name,CAST((a.name + '-' +path ) as VARCHAR(1024)), case when a.parentid is null then 0 else cnt + 1 end as cnt from test_cte a join cte c on c.id = a.parentid where c.cnt is not null
)

select id,parentid,name,path from (select id,parentid,name,path, row_number() over(partition by id order by cnt desc) as rank from cte) a where a.rank = 1 order by 1 asc ;