SQL Server函数中的递归,光标不起作用
这是表结构SQL Server函数中的递归,光标不起作用,sql,sql-server,function,recursion,Sql,Sql Server,Function,Recursion,这是表结构 select nid, memberid, sponsorid from tblmember; 这将产生以下结果: nid memerid sponsor ------------------- 1 679414 0 2 622411 679414 3 647964 679414 5 285631 679414 6 119979 我试图创建一个树状结构,其中每个节点只能有三个子节点,因此如果memberid为679414的成员引入了一个新分支,并
select nid, memberid, sponsorid
from tblmember;
这将产生以下结果:
nid memerid sponsor
-------------------
1 679414 0
2 622411 679414
3 647964 679414
5 285631 679414
6 119979
我试图创建一个树状结构,其中每个节点只能有三个子节点,因此如果memberid为679414
的成员引入了一个新分支,并且他已经有三个子节点,那么如果679414
的第一个子节点的子节点少于3个子节点,那么新分支将被添加到该节点的第一个子节点。Sponsorid是父节点的Memberid(唯一)。为了在679414
的树中找到第一个子节点少于3个的节点,我使用游标创建了以下函数
ALTER FUNCTION dbo.getSponsor (@id VARCHAR(50))
RETURNS VARCHAR(101)
AS
BEGIN
DECLARE @cou INT;
DECLARE @id1 VARCHAR(200);
SELECT @cou = count(*)
FROM tblmember
WHERE sponsorid = @id
IF (@cou < 3)
BEGIN
RETURN @id
END
ELSE
BEGIN
DECLARE db_cursor LOCAL FOR
SELECT memberid
FROM dbo.tblmember
WHERE sponsorid = @id
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @id1
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC getsponsor @id1;
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
RETURN '';
END
我做错什么了吗?我在网上检查了一下,发现游标是全局的,因此在递归中它会导致问题,所以我在游标定义中加入了Local。我们可以使用递归公共表表达式来解决问题。 在计算节点树之后,我们只需忽略使用的节点
;WITH CTE AS (
SELECT *, 1 R FROM tblmember T WHERE sponsorid = @id
UNION ALL
SELECT T.id, T.memberid, T.sponsorid, R + 1 R FROM tblmember T INNER JOIN CTE ON T.sponsorid = CTE.memberid
)
,UsedNodes AS (
SELECT sponsorid, R FROM CTE
GROUP BY sponsorid, R
HAVING COUNT(*) = 3
)
SELECT TOP 1 @return_id = memberid
FROM CTE
WHERE memberid NOT IN ( SELECT sponsorid FROM UsedNodes )
ORDER BY R, id
看起来这是当前的深度优先搜索(因此,如果第一个子项中的任何一个子项有可用空间,则无论深度如何,第一个子项的第一个子项都将在第二个子项之前被选择)。这真的是你想要的订单吗?是的,我也没看到。你能推荐另一种算法吗。当主父节点没有子节点时,这不起作用,但我可以解决这个问题。谢谢
;WITH CTE AS (
SELECT *, 1 R FROM tblmember T WHERE sponsorid = @id
UNION ALL
SELECT T.id, T.memberid, T.sponsorid, R + 1 R FROM tblmember T INNER JOIN CTE ON T.sponsorid = CTE.memberid
)
,UsedNodes AS (
SELECT sponsorid, R FROM CTE
GROUP BY sponsorid, R
HAVING COUNT(*) = 3
)
SELECT TOP 1 @return_id = memberid
FROM CTE
WHERE memberid NOT IN ( SELECT sponsorid FROM UsedNodes )
ORDER BY R, id