I have this tree hierarchy in table. One row for every node. I want to display count of children for every node in the tree. Result would be:
ID COUNT
100 9
129 5
439 3
450 1
501 2
602 1
134 3
133 2
Table schema:
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
Any help how to achieve this? Best in SQL server.
It is a bit complicated because you should use a recursive query and then I've used a CROSS APPLY join to count records:
I've set up next example, (before you post your data)
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);
This is my solution:
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;
And this is the result:
\norgId | tree_order | path | cnt \n----: | ---------: | :------------------- | --: \n 100 | 0 | root | 9 \n 129 | 1 | root/129 | 5 \n 134 | 1 | root/134 | 3 \n 133 | 2 | root/134/133 | 2 \n 133 | 2 | root/134/133 | 2 \n 439 | 2 | root/129/439 | 3 \n 450 | 2 | root/129/450 | 1 \n 501 | 3 | root/129/439/501 | 2 \n 602 | 4 | root/129/439/501/602 | 1 \n
dbfiddle here
If you convert your data to hierarchyid
, you could use the IsDescendantOf
method to get those. There may be a simpler way, but this was my first thought. The first part is just formatting the data for hierarchyid.
The count magic comes where I find all nodes which are descendents of the current node. By grouping on the orgid
you get the count of all descendents.
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
You might even be able to just keep a running total inside the CTE checking for descendents while simultaneously constructing the hierarchyid
path.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.