如何将此游标操作转换为闭包层次结构上的基于集合的操作?
How to turn this cursor operation into a set based operation on a closure hierarchy?
- Trees.DirectReports 是闭包(层级)table.
- 有一个名为
Users
的 table,其中:RowID, EmployeeId, and MangerId
。 @RowCount
是此 table 中的记录数, #EmpMgr
是此 table 的游标。
下面是相关的 sql 代码,我想将其从基于游标的操作转换为基于集合的操作。
WHILE @RowCount <= @NumberRecords --loop through each record in Users table
BEGIN
SET @EmpId = (SELECT EmployeeId FROM #EmpMgr WHERE RowID = @RowCount)
SET @MgrId = (SELECT ManagerId FROM #EmpMgr WHERE RowID = @RowCount)
INSERT INTO [Trees].[DirectReports](EmployeeId, ManagerId, Depth)
SELECT c.EmployeeId, p.ManagerId, p.Depth + c.Depth + 1
FROM Trees.DirectReports p join Trees.DirectReports c
WHERE p.EmployeeId = @MgrId AND c.ManagerId = @EmpId
SET @RowCount = @RowCount + 1
END
所以我真的很想弄清楚如何将其作为一个集合查询来执行,因为我知道那样会快得多,但我的大脑今天还没有完全建立正确的联系来解决这个问题。
*请注意,要回答这个问题,您需要已经了解闭包 table 的工作原理。否则以上可能没有意义。
在其他几个帖子的帮助下找到了我要找的东西。主要答案是这样的:
WITH cte AS
(
SELECT LegacyId ancestor, LegacyId descendant, 0 depth FROM Users
UNION ALL
SELECT cte.ancestor, u.LegacyId descendant, cte.depth + 1 depth
FROM dbo.Users u JOIN cte ON u.ManagerId = cte.descendant
)
select * from cte
然而,一开始让我失望的是有一些坏数据导致循环依赖。我能够使用以下查询来确定这些实例的位置:
with cte (id,pid,list,is_cycle)
as
(
select legacyid id, managerid pid,',' + cast (legacyid as varchar(max)) + ',',0
from users
union all
select u.legacyid id,
u.managerid pid,
cte.list + cast(u.legacyid as varchar(10)) + ',' ,case when cte.list like '%,' + cast (u.legacyid as varchar(10)) + ',%' then 1 else 0 end
from cte join users u on u.managerid = cte.id
where cte.is_cycle = 0
)
select *
from cte
where is_cycle = 1
一旦我纠正了周期性数据,一切都很好。查看以下 SO 帖子以获取更多信息,因为这些是我用来提出解决方案的内容: and How can I create a closure table using data from an adjacency list?
- Trees.DirectReports 是闭包(层级)table.
- 有一个名为
Users
的 table,其中:RowID, EmployeeId, and MangerId
。@RowCount
是此 table 中的记录数,#EmpMgr
是此 table 的游标。
下面是相关的 sql 代码,我想将其从基于游标的操作转换为基于集合的操作。
WHILE @RowCount <= @NumberRecords --loop through each record in Users table
BEGIN
SET @EmpId = (SELECT EmployeeId FROM #EmpMgr WHERE RowID = @RowCount)
SET @MgrId = (SELECT ManagerId FROM #EmpMgr WHERE RowID = @RowCount)
INSERT INTO [Trees].[DirectReports](EmployeeId, ManagerId, Depth)
SELECT c.EmployeeId, p.ManagerId, p.Depth + c.Depth + 1
FROM Trees.DirectReports p join Trees.DirectReports c
WHERE p.EmployeeId = @MgrId AND c.ManagerId = @EmpId
SET @RowCount = @RowCount + 1
END
所以我真的很想弄清楚如何将其作为一个集合查询来执行,因为我知道那样会快得多,但我的大脑今天还没有完全建立正确的联系来解决这个问题。
*请注意,要回答这个问题,您需要已经了解闭包 table 的工作原理。否则以上可能没有意义。
在其他几个帖子的帮助下找到了我要找的东西。主要答案是这样的:
WITH cte AS
(
SELECT LegacyId ancestor, LegacyId descendant, 0 depth FROM Users
UNION ALL
SELECT cte.ancestor, u.LegacyId descendant, cte.depth + 1 depth
FROM dbo.Users u JOIN cte ON u.ManagerId = cte.descendant
)
select * from cte
然而,一开始让我失望的是有一些坏数据导致循环依赖。我能够使用以下查询来确定这些实例的位置:
with cte (id,pid,list,is_cycle)
as
(
select legacyid id, managerid pid,',' + cast (legacyid as varchar(max)) + ',',0
from users
union all
select u.legacyid id,
u.managerid pid,
cte.list + cast(u.legacyid as varchar(10)) + ',' ,case when cte.list like '%,' + cast (u.legacyid as varchar(10)) + ',%' then 1 else 0 end
from cte join users u on u.managerid = cte.id
where cte.is_cycle = 0
)
select *
from cte
where is_cycle = 1
一旦我纠正了周期性数据,一切都很好。查看以下 SO 帖子以获取更多信息,因为这些是我用来提出解决方案的内容: