I think this will do it:
-- Data (corrected column names):
if object_id('tempdb..#Position') is not null drop table #Position;
create table #Position
(
PosId Int,
ReportTo Int,
EmpId Int,
IsVacant Int,
LevelNo Int
);
insert into #Position values (1, 0, 123, 0, 0);
insert into #Position values (2, 1, 124, 0, 1);
insert into #Position values (3, 1, 125, 0, 1);
insert into #Position values (4, 2, 126, 0, 2);
insert into #Position values (5, 2, Null, 1, 2);
insert into #Position values (6, 2, 128, 0, 2);
insert into #Position values (7, 5, 129, 0, 3);
insert into #Position values (8, 5, 130, 0, 3);
select * from #Position;
-- Query:
;WITH PCCET AS
(
SELECT RootID = PosId,
PosId, EmpId
FROM #Position
UNION ALL
SELECT cte.RootID, d.PosId, d.EmpId
FROM PCCET cte
INNER JOIN #Position d ON d.ReportTo = cte.PosId
)
--select * from PCCET order by rootid
select P.PosId,
ISNULL(cnt.Children, 0) as PCnt
from #Position P
LEFT OUTER JOIN (
SELECT posid = RootID, Children = COUNT(*)
FROM PCCET
WHERE EmpId is not null
AND RootId <> PosId
GROUP BY RootID
) cnt ON cnt.posid = p.PosId
My results are different to yours - 2 has 4 occupied positions: 4, 6, 7 & 8 with 5 unoccupied.
I added the EmpId into the CTE, then ignored records where EmpId is NULL.
I excluded the manager by ignoring RootId = PosId instead of subtracting 1 from the count. This avoids the problem of the unoccupied manager job 5.
The LEFT JOIN instead of inner join keeps all the managers in the output.
By the way - if you provide proper data definitions you will be more likely to get help, as many people don't have the time to write it themselves...:-D