Sql server SQL Server中是否可以使用递归调用的存储过程?

Sql server SQL Server中是否可以使用递归调用的存储过程?,sql-server,stored-procedures,recursion,cursor,Sql Server,Stored Procedures,Recursion,Cursor,以下是作为VBScript子例程的内容: sub buildChildAdminStringHierarchical(byval pAdminID, byref adminString) set rsx = conn.execute ("select admin_id from administrator_owners where admin_id not in (" & adminString & ") and owner_id = " & pAdminID)

以下是作为VBScript子例程的内容:

sub buildChildAdminStringHierarchical(byval pAdminID, byref adminString)
    set rsx = conn.execute ("select admin_id from administrator_owners where admin_id not in (" & adminString & ") and owner_id = " & pAdminID)

    do while not rsx.eof
        adminString = adminString & "," & rsx(0)
        call buildChildAdminStringHierarchical(rsx(0),adminString)
        rsx.movenext
    loop
end sub
既然它在子例程中得到了递归调用,那么是否有必要将其转换为存储过程

这是我试过的

CREATE PROCEDURE usp_build_child_admin_string_hierarchically
    @ID AS INT,
    @ADMIN_STRING AS VARCHAR(8000),
    @ID_STRING AS VARCHAR(8000) OUTPUT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @index int;
    DECLARE @length int;
    DECLARE @admin_id int;
    DECLARE @new_string varchar(8000);

    SET @index = 1;
    SET @length = 0;
    SET @new_string = @ADMIN_STRING;

    CREATE TABLE #Temp (ID int)

    WHILE @index <= LEN(@new_string)
    BEGIN
        IF CHARINDEX(',', @new_string, @index) = 0
            SELECT @length = (LEN(@new_string) + 1) - @index;
        ELSE
            SELECT @length = (CHARINDEX(',', @new_string, @index) - @index);
        SELECT @admin_id = CONVERT(INT,SUBSTRING(@new_string, @index, @length));
        SET @index = @index + @length + 1;
        INSERT INTO #temp VALUES(@admin_id);
    END

    DECLARE TableCursor CURSOR FOR
        SELECT Admin_ID FROM Administrator_Owners WHERE Admin_ID NOT IN (SELECT ID FROM #temp) AND Owner_ID = @ID;

    OPEN TableCursor;
    FETCH NEXT FROM TableCursor INTO @admin_id;

    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF LEN(@ID_STRING) > 0
        SET @ID_STRING = @ID_STRING + ',' + CONVERT(VARCHAR, @admin_id);
        ELSE
        SET @ID_STRING = CONVERT(VARCHAR, @admin_id);

        EXEC usp_build_child_admin_string_hierarchically @admin_id, @ID_STRING, @ID_STRING;

        FETCH NEXT FROM TableCursor INTO @admin_id;
    END

    CLOSE TableCursor;
    DEALLOCATE TableCursor;

    DROP TABLE #temp;
END
GO
但是当调用该存储过程时,我得到以下错误。。。
与“TableCursor”同名的游标已经存在。

可以,但通常不是一个好主意。SQL用于基于集合的操作。此外,至少在MS SQL Server中,递归仅限于它可以进行的递归调用的数量。您最多只能嵌套32层


在您的情况下,问题在于游标在每次调用中都会持续,因此您会多次创建它。

问题在于,虽然游标不是全局游标,但它是会话游标。由于您正在执行递归,即使每次迭代都在新的proc范围中创建一个游标,它们都是在同一个PID连接中同时创建的,因此会发生冲突

您需要在过程的每次迭代中根据一些在递归过程中不会再现的条件生成唯一的游标名称

或者,最好是找到一种方法,使用set logic执行您需要的操作,并使用递归CTE处理任何必要的递归。

您可以指定一个游标,如下所示:

DECLARE TableCursor CURSOR LOCAL FOR
SELECT ...

至少在SQL Server 2008 R2 my machine中,这允许您递归调用存储过程,而不会遇到游标已存在的错误。

我猜您的错误是因为递归调用是在游标TableCursor关闭之前进行的。有没有可能给游标一个动态名称,比如TableCursorN,其中N是递归的深度-您必须将其作为一个额外的参数?问题不是递归,这当然是允许的,而是您使用的是静态游标名称。不过,我对MS SQL Server中的游标了解不够,因此无法将此作为回答,因为它必须说明如何在这种情况下使用游标才有用!:-生成唯一光标名称的最佳方法是什么?我对动态sql不太在行。我可以确认这在2005年也能奏效。这个答案应该标记为正确。