Sql server SQL Server CTE递归-将树追溯到每个节点的特定树级别

Sql server SQL Server CTE递归-将树追溯到每个节点的特定树级别,sql-server,parent-child,common-table-expression,Sql Server,Parent Child,Common Table Expression,我有两个表,Item(ItemID,CatID,Name)和Category(CatID,ParentID,Name,CatLevel)Category是一个目录树层次结构,项目可以位于其中。该表还跟踪每个节点所处的类别级别。下面是一个例子: 1. Animal (CatLevel = 1) 2. Dog (CatLevel = 2) 3. Beagle (CatLevel = 3) 4. Labrador (CatLevel = 3)

我有两个表,Item(ItemID,CatID,Name)和Category(CatID,ParentID,Name,CatLevel)Category是一个目录树层次结构,项目可以位于其中。该表还跟踪每个节点所处的类别级别。下面是一个例子:

1. Animal (CatLevel = 1)
    2. Dog (CatLevel = 2)
        3. Beagle (CatLevel = 3)
        4. Labrador (CatLevel = 3)
            5. Yellow (CatLevel = 4)
            6. Chocolate (CatLevel = 4)
            7. Black (CatLevel = 4)
    8. Cat (CatLevel = 2)
        9. Tabby (CatLevel = 3)
    10. Horse (CatLevel = 2)
        11. Stallion (CatLevel = 3)
我正在尝试提出一个查询,该查询将为我提供一个项目列表,其中包含常规CatID和我指定级别(例如,级别2)的CatID。示例输出:

Item      CatID    LevelTwoCatID
______    _____    _____________
Dog       2        2
Beagle    3        2
Labrador  4        2
Yellow    5        2
Chocolate 6        2
Black     7        2
Cat       8        8
Tabby     9        8
Horse     10       10
Stallion  11       10
我知道如何追溯到单个节点的类别,但我不知道如何进行更通用的查询,为每个节点提供“LevelTwoCatID”。以下是我如何做到这一点的:

WITH Tree AS
(
    SELECT * FROM Category WHERE CatID = 6 -- Chocolate lab, change for some other

    UNION ALL

    SELECT * FROM Category AS a
    INNER JOIN Tree t ON a.CatID = t.ParentID
)
SELECT * FROM Tree WHERE CatLevel = 2
如何获取所有节点/叶的CatLevel=2节点ID


谢谢

我知道这篇文章很老了,但我是这样写的

在我的表中有几个根类别,因此我使用@RootId来指定我要查找的根类别。根类别的ParentID设置为NULL

如果类别表中没有CatLevel列,cte树将为您创建该列。如果要经常使用查询,最好将其添加到表中(更新代码最后会被注释)

如果您希望拥有动态列数(不是像我的情况那样固定为5),请为其进行动态SQL查询

DECLARE @RootId INT, @SearchId INT
SET @RootId = 0 
SET @SearchId = 0

--SELECT it.Id, it.ParentId, it.Name, it.RootId FROM ItemTree it 
--WHERE (@RootId = 0 OR it.RootId = @RootId) AND (@SearchId = 0 OR it.Id = @SearchId)

;WITH Tree AS --gets category levels
(
  SELECT 1 as CatLevel, it.Id, it.ParentId, it.Name, it.RootId
  FROM ItemTree it WHERE it.ParentId IS NULL AND (@RootId = 0 OR it.RootId = @RootId) AND (@SearchId = 0 OR it.Id = @SearchId)

  UNION ALL

  SELECT t.CatLevel + 1 as CatLevel, it.Id, it.ParentId, it.Name, it.RootId
  FROM ItemTree it
  INNER JOIN Tree t ON it.ParentId = t.Id
  WHERE (@RootId = 0 OR it.RootId = @RootId) AND (@SearchId = 0 OR it.Id = @SearchId)

  ----if CatLevel already exists in the table, just use it instead for better performance
  --SELECT it.CatLevel, it.Id, it.ParentId, it.Name FROM ItemTree it 
  --WHERE (@RootId = 0 OR it.RootId = @RootId) AND (@SearchId = 0 OR it.Id = @SearchId)
)
, LeafIds AS --use it to show only leaf categories
(
  SELECT DISTINCT Id FROM ItemTree it WHERE (@RootId = 0 OR it.RootId = @RootId)
  EXCEPT
  SELECT DISTINCT ParentId FROM ItemTree it WHERE (@RootId = 0 OR it.RootId = @RootId)
)
, LeafTree AS --prepare data for pivots
(
  SELECT t.CatLevel, t.Id, t.ParentId, t.Name, Id AS LeafId
  FROM Tree t --WHERE Id IN (SELECT Id FROM LeafIds)

  UNION ALL

  SELECT t.CatLevel, t.Id, t.ParentId, t.Name, lt.LeafId
  FROM Tree t
  INNER JOIN LeafTree lt ON lt.ParentId = t.Id
)
, TreeFinal AS --make pivots for Id and Name over same leafIds
(
  SELECT t.*, pt1.[1] AS ID_1, pt1.[2] AS ID_2, pt1.[3] AS ID_3, pt1.[4] AS ID_4, pt1.[5] AS ID_5
  , pt2.[1] AS Name_1, pt2.[2] AS Name_2, pt2.[3] AS Name_3, pt2.[4] AS Name_4, pt2.[5] AS Name_5
  , ISNULL(pt2.[1], '') + ISNULL(' - ' + pt2.[2], '') + ISNULL(' - ' + pt2.[3], '') + ISNULL(' - ' + pt2.[4], '') + ISNULL(' - ' + pt2.[5], '')  AS Path
  FROM Tree t

  JOIN (
    SELECT LeafId, CatLevel, Id
    FROM LeafTree
  ) source
  PIVOT ( MAX(Id) FOR CatLevel IN ([1], [2], [3], [4], [5]) ) AS pt1 ON pt1.LeafId = t.Id

  JOIN (
    SELECT LeafId, CatLevel, Name
    FROM LeafTree
  ) source
  PIVOT ( MAX(Name) FOR CatLevel IN ([1], [2], [3], [4], [5]) ) AS pt2 ON pt2.LeafId = t.Id
) 
--Use following to update CatLevel in your table, if it was not there before
--UPDATE it SET CatLevel = Tree.CatLevel FROM Tree JOIN dbo.ItemTree it ON it.Id = Tree.Id
SELECT * FROM TreeFinal ORDER BY Path

如果您提供
DECLARE@table\u var table(…)
语句和填充它们的脚本,您可能更容易得到响应。