SQL Server函数中的递归,光标无法正常工作

时间:2017-09-04 09:17:59

标签: 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的成员引入了一个新的分支并且他已经有三个子节点,那么将添加新的分支到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

但是当我使用以下代码尝试时,不会执行此游标。

DECLARE @a VARCHAR(200);
EXEC @a = [getSponsor] '679414'
SELECT @a;

我做错了什么吗?我在网上检查过,发现光标是全局的,因此在递归时会导致问题,所以我把Local放在游标定义中。

1 个答案:

答案 0 :(得分:2)

我们可以使用递归公用表表达式来解决问题。 在计算节点树之后,我们只是忽略使用的节点。

;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