Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server函数中的递归,光标不起作用_Sql_Sql Server_Function_Recursion - Fatal编程技术网

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