如何在SQL中为每个节点计算树状结构中的数据

时间:2018-04-03 17:40:26

标签: sql sql-server tree hierarchy

我有一棵这样的树: enter image description here

我在表格中有这个树层次结构。每个节点一行。 我想显示树中每个节点的子计数。 结果将是:

ID COUNT
100 9
129 5
439 3
450 1
501 2
602 1
134 3
133 2

表架构:

Table - Organization_structure
orgID
parentID

Table - Organization_detail
RID (PK)
OrganizationID
ParentOrganizationID

data:
orgID parrent ID
602   501
501   439
450   129
439   129
129   100
133   134
134   100

RID OrganizationID ParentOrganizationID
1   100            top
2   129            100
3   439            129
4   450            129
5   501            439
6   602            501
7   134            100
8   133            134
9   133            134

任何帮助如何实现这一目标?最好的SQL服务器。

2 个答案:

答案 0 :(得分:0)

这有点复杂,因为您应该使用递归查询,然后我使用了CROSS APPLY联接来计算记录:

我已经设置了下一个示例,(在您发布数据之前)

CREATE TABLE Organization_structure (orgID int, parentID int);

INSERT INTO Organization_structure VALUES
(100, NULL),
(129, 100),
(134, 100),
(439, 129),
(450, 129),
(133, 134),
(133, 134),
(501, 439),
(602, 501);

这是我的解决方案:

with tree as
(
    select orgId, parentId,0 as tree_order, path = cast('root' as varchar(100)) 
    from   Organization_structure 
    where  parentID is null
    union all
    select os.orgId, os.parentId, 1 + tree_order as tree_order,
           path = cast(tree.path + '/' + right(('000000000' + os.orgId), 10) as varchar(100))
    from   Organization_structure os
    join   tree 
    on     tree.orgId = os.parentId
)
select orgId, tree_order, path, t2.cnt 
from tree
cross apply (select count(*) cnt from tree t1 where t1.path like tree.path + '%') t2
order by tree_order;

这就是结果:

orgId | tree_order | path                 | cnt
----: | ---------: | :------------------- | --:
  100 |          0 | root                 |   9
  129 |          1 | root/129             |   5
  134 |          1 | root/134             |   3
  133 |          2 | root/134/133         |   2
  133 |          2 | root/134/133         |   2
  439 |          2 | root/129/439         |   3
  450 |          2 | root/129/450         |   1
  501 |          3 | root/129/439/501     |   2
  602 |          4 | root/129/439/501/602 |   1

dbfiddle here

答案 1 :(得分:0)

如果您将数据转换为hierarchyid,则可以使用IsDescendantOf方法获取这些数据。可能有一种更简单的方法,但这是我的第一个想法。第一部分是格式化hierarchyid的数据。

计数魔法出现在我找到所有节点的地方,这些节点是当前节点的后代。通过对orgid进行分组,您可以获得所有后代的计数。

with data (OrgId, ParentOrgId) as
(
    select 100, null union all
    select 129, 100 union all
    select 134, 100 union all
    select 133, 134 union all
    select 135, 134 union all
    select 439, 129 union all
    select 450, 129 union all
    select 501, 439 union all
    select 602, 501 
), cte as
(
    select 
        sPath = cast(concat('/', OrgId, '/') as varchar(max)),
        Path = hierarchyid::Parse(concat('/', OrgId, '/')),
        PreviousPath = hierarchyid::GetRoot(),
        OrgId,
        ParentOrgId
    from data
    where ParentOrgId is null
    union all
    select 
        sPath = cast(concat(c.sPath, s.OrgId, '/') as varchar(max)),
        Path = hierarchyid::Parse(concat(c.sPath, s.OrgId, '/')),
        PreviousPath = c.Path,
        OrgId = s.OrgId,
        ParentOrgId = s.ParentOrgId
    from cte c
    inner join data s
        on c.OrgId = s.ParentOrgId
)
select a.OrgId, NumChildren = count(1)
from cte a
inner join cte b
    on b.Path.IsDescendantOf(a.Path) = 1
group by a.OrgId

在构建hierarchyid路径的同时,您甚至可以在CTE中检查后代中的运行总计。