You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SQL Server 2012中统计每个人的完整下属链人数?

统计层级SQL数据中每个人的全部下属人数问题

原帖子仅统计每个层级的直接下属人数,但实际需要统计每个人的完整下属链(所有层级的下属总数),当前使用的查询返回结果不正确。使用环境为SQL Server 2012,真实数据集约2500行(人员),包含多分支,层级约7级。


样本数据

IF OBJECT_ID (N'[tmpPeople]', N'U') IS NOT NULL
DROP TABLE [tmpPeople];

CREATE TABLE [tmpPeople]
(
    [PositionID] [float] NULL,
    [PreferredName] [varchar](max) NULL,
    [ManagerPositionID] [float] NULL
) 
GO

    
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person A', 1, 0)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person B', 2, 1)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person C', 3, 1)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person D', 4, 2)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person E', 5, 3)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person F', 6, 4)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person G', 7, 5)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person H', 8, 6)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person I', 9, 7)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person J', 10, 8)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person K', 11, 3)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person L', 12, 3)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person M', 13, 11)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person N', 14, 11)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person O', 15, 13)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person P', 16, 12)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person Q', 17, 12)
INSERT [tmpPeople] ([PreferredName], [PositionID], [ManagerPositionID]) VALUES (N'Person R', 18, 14)    

执行SELECT * FROM tmpPeople返回结果:

PositionIDPreferredNameManagerPositionID
1Person A0
2Person B1
3Person C1
4Person D2
5Person E3
6Person F4
7Person G5
8Person H6
9Person I7
10Person J8
11Person K3
12Person L3
13Person M11
14Person N11
15Person O13
16Person P12
17Person Q12
18Person R14

当前使用的CTE查询语句

;WITH ChildrenCTE AS (
   SELECT PositionID, PreferredName, ManagerPositionID, 0 AS n
     FROM tmpPeople
    WHERE PositionID NOT IN (SELECT ManagerPositionID FROM tmpPeople
                              WHERE ManagerPositionID IS NOT NULL
                            )
    UNION ALL
   SELECT d.PositionID, d.PreferredName, d.ManagerPositionID, n+1
     FROM ChildrenCTE cte
     JOIN tmpPeople d ON d.PositionID = cte.ManagerPositionID
    WHERE n < 20
 )

SELECT cte.PositionID, cte.PreferredName
     , SUM(cte.n) AS children
  FROM ChildrenCTE AS cte
 GROUP BY cte.PositionID, cte.PreferredName
 ORDER BY  positionID 

当前查询结果

PositionIDPreferredNamechildren
1Person A23
2Person B4
3Person C13
4Person D3
5Person E2
6Person F2
7Person G1
8Person H1
9Person I0
10Person J0
11Person K4
12Person L2
13Person M1
14Person N1
15Person O0
16Person P0
17Person Q0
18Person R0

问题原因

当前查询的逻辑完全错误:

  1. 遍历方向错误:从叶子节点(没有下属的员工)向上遍历经理,而非从每个员工向下遍历下属。
  2. 统计逻辑错误:SUM(cte.n)是累加每个下属的层级深度,而非统计下属的人数。例如Person A的23是所有下属的层级数之和,并非实际下属人数。

正确解决方案

使用递归CTE从每个员工开始,向下遍历所有层级的下属,最终统计每个员工的下属总数:

;WITH EmployeeHierarchy AS (
    -- 锚点成员:获取每个员工的直接下属
    SELECT 
        e.PositionID AS ManagerID,
        e.PreferredName AS ManagerName,
        c.PositionID AS SubordinateID,
        c.PreferredName AS SubordinateName
    FROM tmpPeople e
    JOIN tmpPeople c ON e.PositionID = c.ManagerPositionID
    UNION ALL
    -- 递归成员:继续获取下属的下属,遍历完整层级链
    SELECT 
        eh.ManagerID,
        eh.ManagerName,
        c.PositionID AS SubordinateID,
        c.PreferredName AS SubordinateName
    FROM EmployeeHierarchy eh
    JOIN tmpPeople c ON eh.SubordinateID = c.ManagerPositionID
)
-- 统计每个经理的全部下属数量,同时补充无下属的员工
SELECT 
    ManagerID AS PositionID,
    ManagerName AS PreferredName,
    COUNT(DISTINCT SubordinateID) AS TotalSubordinates
FROM EmployeeHierarchy
GROUP BY ManagerID, ManagerName
UNION ALL
SELECT 
    PositionID,
    PreferredName,
    0 AS TotalSubordinates
FROM tmpPeople
WHERE PositionID NOT IN (SELECT ManagerID FROM EmployeeHierarchy)
ORDER BY PositionID;

正确结果示例

PositionIDPreferredNameTotalSubordinates
1Person A17
2Person B4
3Person C10
4Person D3
5Person E2
6Person F2
7Person G1
8Person H1
9Person I0
10Person J0
11Person K4
12Person L2
13Person M1
14Person N1
15Person O0
16Person P0
17Person Q0
18Person R0

内容的提问来源于stack exchange,提问作者Maxcot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 07:03:16