递归查询 - 仅选择叶节点表示活动数据的节点

时间:2010-03-02 21:56:15

标签: sql sql-server sql-server-2005 hierarchy

给出以下递归查询:

WITH DepartmentHierarchy (DepartmentID, Name, IsInactive, IsSpecial, ParentId, HierarchyLevel) AS
(
   -- Base case
   SELECT
      DepartmentId,
      Name,
      IsInactive,
      IsSpecial,
      ParentId,
      1 as HierarchyLevel
   FROM StoreDepartment
   WHERE ParentId IS NULL

   UNION ALL

   -- Recursive step
   SELECT
      d.DepartmentId,
       d.Name,
      d.IsInactive,
      d.IsSpecial,
      d.ParentId,
      dh.HierarchyLevel + 1 AS HierarchyLevel
   FROM StoreDepartment d
      INNER JOIN DepartmentHierarchy dh ON
         d.ParentId = dh.DepartmentId
) SELECT * FROM DepartmentHierarchy 

我可以选择看起来像这样的数据:

DepartmentId, Name, IsInactive, IsSpecial, ParentId, HeirarchyLevel
1, Store, 0, 0, NULL, 1
2, Main Department 1, 0, 1, 2
3, Main Department 2, 0, 1, 2
4, Sub For Main 1, 0, 2, 3

此外,假设存在DepartmentId和ItemId的表(例如:DepartmentItemRelationship)。部门层次结构中的叶节点与此处的项目配对。

我希望我的递归查询只返回在其下面至少有一个叶子节点并且在department / item关系表中匹配的节点(在任何级别)。这些节点可能是6或7级,所以我不确定如何修改我的查询以确保包含这些。

谢谢, 凯尔

2 个答案:

答案 0 :(得分:3)

您可以创建一个跟踪层次结构的路径列。然后,您只能在DepartmentItemRelationship表中添加具有匹配项的子节点。最后只获得至少有孩子的节点。

尝试这样的事情:

    WITH DepartmentHierarchy (DepartmentID, Name, IsInactive, IsSpecial, ParentId, HierarchyLevel) AS
(
   -- Base case
   SELECT
      '/'+cast( DepartmentId as varchar(max)) as [path]
      DepartmentId,
      Name,
      IsInactive,
      IsSpecial,
      ParentId,
      1 as HierarchyLevel
   FROM StoreDepartment
   WHERE ParentId IS NULL

   UNION ALL

   -- Recursive step
   SELECT
      dh.[path] +'/'+ cast( d.DepartmentId as varchar(max)) as [path]
      d.DepartmentId,
      d.Name,
      d.IsInactive,
      d.IsSpecial,
      d.ParentId,
      dh.HierarchyLevel + 1 AS HierarchyLevel
   FROM StoreDepartment d
      INNER JOIN DepartmentHierarchy dh ON
         d.ParentId = dh.DepartmentId
   where exists ( select top 1 1 
                  from DepartmentItemRelationship di
                  where di.DepartmentId = d.DepartmentId )
) 
SELECT * 
FROM DepartmentHierarchy dh
where exists ( select top 1 1 
               from DepartmentHierarchy 
               where charindex('/'+dh.DepartmentID+'/',[path]) > 0) 

答案 1 :(得分:1)

如果我理解正确,您希望所有节点都高于叶级别一级?

您实际上并不需要递归查询。您所需要的只是首先找到叶子节点,然后选择所有父节点。

WITH LeafNodeParents AS
(
    SELECT DISTINCT ParentId
    FROM StoreDepartment
    WHERE DepartmentId NOT IN
    (
        SELECT DISTINCT ParentId FROM StoreDepartment
    )
)
SELECT d.DepartmentId, d.Name, d.IsInactive, d.IsSpecial, d.ParentId
FROM LeafNodeParents p
INNER JOIN StoreDepartment d
    ON d.DepartmentId = p.ParentId

唯一不会告诉你的是关卡。我不确定你需要多么糟糕。如果不这样做,这应该比递归版本更好;如果你这样做,看起来Jose的查询就可以了(通过快速浏览判断)。