我有一个动态SQL statement我已经创建了一个存储的过程。我需要循环访问的结果,使用了光标。我有一个很难找出正确的语法。这里是我在做什么。

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

什么是正确的方式做到这一点?

有帮助吗?

解决方案

一个光标将只接受一个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

如果您需要避免使用游标全球,你也可以将您的动态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

其他提示

此代码是用于与光标的动态列一个很好的例子,因为你不能在@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

与工作无关系数据库(IDMS的人?) 在ODBC connection有资格作为一个的那些时光标和动态SQL似乎是唯一的途径。

select * from a where a=1 and b in (1,2)

需要45分钟的反应,同时重新写入使用的按键组没有在条款将运行在1二:

select * from a where (a=1 and b=1)
union all
select * from a where (a=1 and b=2)

如果在表B列包含1145行,使用了光标创造indidivudal的发言和执行它们,作为动态SQL是远远快于使用中的条款。愚蠢的?

并且是的,没时间在一个关系数据库,光标的应用。我只是不能相信我遇到一个实例,其中一个标循环是几幅度更快。

首先,避免如果在所有可能使用的光标。这里有一些资源铲除它出来的时候,似乎你不能没有:

必须有15种方法失去你的光标...第1部分,介绍

行到行的处理不光标

这是说,虽然,你可能会坚持一个毕竟 - 我不知道从你的问题,足以确保这类原因申请。如果是这样的话,你已经有了一个不同的问题 - 你的光标选择语句必须是一个的实际的SELECT语句,而不是EXECUTE语句。你就完蛋了。

但看到cmsjr答案(这进来,而我写的)有关使用临时表。我想避免的全球的游标甚至超过 “普通” 的....

之后,最近交换来自Oracle到SQL服务器的(雇主的偏好),我通知标的支持SQL服务器的滞后。游标并不总是邪恶的,有时需要,有时要快得多,并有时吸尘器比试图为你一个复杂的查询通过重新安排或增加优化。将"游标是邪恶"的意见更为突出,在SQL Server社区。

所以我想这回答是切换到Oracle或给MS一个线索。

有是,我想另一实例与你分享结果:d http://www.sommarskog.se/dynamic_sql.html#cursor0

在SQL Server的另一种方法是你所有的动态查询的做成表变量的存储过程,然后使用游标来查询并处理。至于可怕光标辩论:),我所看到的研究显示,在某些情况下,光标实际上可以更快,如果正确设置。我用他们自己时所需的查询是太复杂了,或者只是不从人的角度(对我来说)。)可能

此代码可以对您有用。

例如光标使用在SQL服务器

DECLARE sampleCursor CURSOR FOR 
      SELECT K.Id FROM TableA K WHERE ....;
OPEN sampleCursor
FETCH NEXT FROM sampleCursor INTO @Id
WHILE @@FETCH_STATUS <> -1
BEGIN

UPDATE TableB
   SET 
      ...
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top