这种方法使用循环,但应该比较快
- 它基于作业中的级别数运行,而不是个人(因此,如果您像这里一样有 3 个级别,它会执行 3 个循环)
- 读取和计算非常高效 - 它不需要进行大量的 JOIN 和排序和表扫描(除了第一次)
在this dbfiddle 中有一些这种运行的例子,还有一些额外的报告
/* Initial data setup */
CREATE TABLE #Emps (ID int PRIMARY KEY, Job nvarchar(30), ParentID int);
INSERT INTO #Emps (ID, Job, ParentID) VALUES
(1, N'CEO', NULL),
(2, N'CFO', 1),
(3, N'CTO', 1),
(4, N'CMO', 1),
(5, N'Accounting Manager', 2),
(6, N'Payroll Manager', 2),
(7, N'Data Manager', 3),
(8, N'Software Manager', 3),
(9, N'Data Analyst', 7),
(10, N'Data Engineer ', 7);
CREATE TABLE #EmpParents (RoundNum int, ID int, ParentID int, PRIMARY KEY (RoundNum, ID));
每个“轮次”的数据(例如,循环中的迭代次数)被插入到#EmpParents 表中。
方法是
a) 首先包括基础作业和父作业
b)然后对于父工作,确定他们的父母
重复 b) 直到找不到更多父作业。
它找到“父母的父母”的方法是查看循环中的最后一个“回合”,以获取该回合中每个作业的父 ID;在下一轮中,它使用这些新父母来确定下一级父母。
请注意,我使用 WHILE 循环来完成此操作,因为我认为它更易于阅读/理解。但是,您可以使用 CURSOR 或递归 CTE 来执行此操作 - 但无论如何它们都是循环的变体。
/* Data calculations - Find parents, and parents of parents */
DECLARE @RoundNum int; -- Used for counting what iteration we're up to
DECLARE @NumInserted int; -- User for recording number of rows inserted
-- Insert initial data (own job and parent job)
INSERT INTO #EmpParents (RoundNum, ID, ParentID)
SELECT 0, ID, ID
FROM #Emps
UNION ALL
SELECT 1, ID, ParentID
FROM #Emps
WHERE ParentID IS NOT NULL;
SET @NumInserted = @@ROWCOUNT;
SET @RoundNum = 1;
-- Add 'parents of parents' until no more found
WHILE @NumInserted > 0
BEGIN
SET @RoundNum += 1;
INSERT INTO #EmpParents (RoundNum, ID, ParentID)
SELECT @RoundNum, #EmpParents.ID, #Emps.ParentID
FROM #EmpParents
INNER JOIN #Emps ON #EmpParents.ParentID = #Emps.ID
WHERE #EmpParents.RoundNum = @RoundNum - 1
AND #Emps.ParentID IS NOT NULL;
SET @NumInserted = @@ROWCOUNT;
END
在最终报告中,请注意它使用最后一列(ParentID)作为主列,并找到与其对应的所有作业 ID。
/* Reporting */
SELECT ParentEmp.Job, STRING_AGG(TeamEmp.Job, ', ') AS Team
FROM #EmpParents
INNER JOIN #Emps AS ParentEmp ON #EmpParents.ParentID = ParentEmp.ID
INNER JOIN #Emps AS TeamEmp ON #EmpParents.ID = TeamEmp.ID
GROUP BY #EmpParents.ParentID, ParentEmp.Job
ORDER BY #EmpParents.ParentID;
这是结果
Job Team
------------------------------ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CEO CEO, CFO, CTO, CMO, Accounting Manager, Payroll Manager, Data Manager, Software Manager, Data Analyst, Data Engineer
CFO Accounting Manager, Payroll Manager, CFO
CTO CTO, Data Manager, Software Manager, Data Analyst, Data Engineer
CMO CMO
Accounting Manager Accounting Manager
Payroll Manager Payroll Manager
Data Manager Data Manager, Data Analyst, Data Engineer
Software Manager Software Manager
Data Analyst Data Analyst
Data Engineer Data Engineer
最后一点:这里没有错误检查并假设一个层次结构(例如,你不能有一个父母的循环,例如,我的下属是我老板的老板)。您可能希望在循环/等中进行一些错误检查来控制它。一个简单的方法是,如果 RoundNum 达到一个不可能的不切实际的高数字(例如,50),那么它会因错误而中止。