在存储过程中使用带有动态SQL的游标

Mic*_*cah 46 t-sql stored-procedures dynamic-sql database-cursor

我有一个我在存储过程中创建的动态SQL语句.我需要使用游标迭代结果.我很难搞清楚正确的语法.这就是我正在做的事情.

SELECT @SQLStatement = 'SELECT userId FROM users'

DECLARE @UserId

DECLARE users_cursor CURSOR FOR
EXECUTE @SQLStatment --Fails here. Doesn't like this

OPEN users_cursor
FETCH NEXT FROM users_cursor
INTO @UserId

WHILE @@FETCH_STATUS = 0
BEGIN

EXEC asp_DoSomethingStoredProc @UserId

END
CLOSE users_cursor
DEALLOCATE users_cursor
Run Code Online (Sandbox Code Playgroud)

这样做的正确方法是什么?

cms*_*sjr 110

游标只接受select语句,因此如果SQL确实需要是动态的,则声明游标是您正在执行的语句的一部分.为了使以下工作,您的服务器必须使用全局游标.

Declare @UserID varchar(100)
declare @sqlstatement nvarchar(4000)
--move declare cursor into sql to be executed
set @sqlstatement = 'Declare  users_cursor CURSOR FOR SELECT userId FROM users'

exec sp_executesql @sqlstatement


OPEN users_cursor
FETCH NEXT FROM users_cursor
INTO @UserId

WHILE @@FETCH_STATUS = 0
BEGIN
Print @UserID
EXEC asp_DoSomethingStoredProc @UserId

FETCH NEXT FROM users_cursor --have to fetch again within loop
INTO @UserId

END
CLOSE users_cursor
DEALLOCATE users_cursor
Run Code Online (Sandbox Code Playgroud)

如果需要避免使用全局游标,还可以将动态SQL的结果插入临时表,然后使用该表填充游标.

Declare @UserID varchar(100)
create table #users (UserID varchar(100))

declare @sqlstatement nvarchar(4000)
set @sqlstatement = 'Insert into #users (userID) SELECT userId FROM users'
exec(@sqlstatement)

declare users_cursor cursor for Select UserId from #Users
OPEN users_cursor
FETCH NEXT FROM users_cursor
INTO @UserId

WHILE @@FETCH_STATUS = 0
BEGIN

EXEC asp_DoSomethingStoredProc @UserId

FETCH NEXT FROM users_cursor
INTO @UserId

END
CLOSE users_cursor
DEALLOCATE users_cursor

drop table #users
Run Code Online (Sandbox Code Playgroud)

  • 游标不是邪恶的.当然,资源密集且不宜在生产场景中使用.邪恶没有.仅仅因为某些东西可以被错误地使用并不意味着你不应该知道如何使用它.也许我误解了这个问题,但它似乎在询问如何使用光标,而不是使用它们的优缺点. (24认同)
  • 这让我有能力编写完全不可理解的代码!在动态生成的SQL中声明的变量在非dynaimic sql中使用,在执行路径的下方!我喜欢它! (5认同)
  • 很少有代码构造本质上是邪恶的(我在看你COBOL,可重写代码*是邪恶的),而游标不是其中之一.当然初学者可能很想接触他们,因为他们不理解SQL中的处理集,但有时他们会挽救生命 - 我已经开发了几个你不可能以任何其他方式处理的SSRS报告 (3认同)
  • 我要和邪恶一起去....是的,OP询问如何使用光标.他还询问"......正确的做法".负责任的答案是提供有关如何在没有光标的情况下完成最终结果的信息 - 它(几乎)始终可以这样做. (2认同)

小智 20

对于带有游标的动态列,此代码是一个非常好的示例,因为您无法在@STATEMENT中使用"+":

ALTER PROCEDURE dbo.spTEST
AS
    SET NOCOUNT ON
    DECLARE @query NVARCHAR(4000) = N'' --DATA FILTER
    DECLARE @inputList NVARCHAR(4000) = ''
    DECLARE @field sysname = '' --COLUMN NAME
    DECLARE @my_cur CURSOR
    EXECUTE SP_EXECUTESQL
        N'SET @my_cur = CURSOR FAST_FORWARD FOR
            SELECT
                CASE @field
                    WHEN ''fn'' then fn
                    WHEN ''n_family_name'' then n_family_name
                END
            FROM
                dbo.vCard
            WHERE
                CASE @field
                    WHEN ''fn'' then fn
                    WHEN ''n_family_name'' then n_family_name
                END
                LIKE ''%''+@query+''%'';
            OPEN @my_cur;',
        N'@field sysname, @query NVARCHAR(4000), @my_cur CURSOR OUTPUT',
        @field = @field,
        @query = @query,
        @my_cur = @my_cur OUTPUT
    FETCH NEXT FROM @my_cur INTO @inputList
    WHILE @@FETCH_STATUS = 0
    BEGIN
        PRINT @inputList
        FETCH NEXT FROM @my_cur INTO @inputList
    END
    RETURN
Run Code Online (Sandbox Code Playgroud)

  • 完美,非常有用,谢谢!作为注释,似乎游标也必须在动态 sql 中打开 - SQL Server 似乎认为游标未初始化,并且如果在动态内容之后完成,则会抛出错误。 (2认同)