Saltar al contenido

Usando un cursor con SQL dinámico en un procedimiento almacenado

Ya no tienes que buscar más por todo internet ya que has llegado al espacio adecuado, poseemos la respuesta que buscas y sin liarte.

Solución:

Un cursor solo aceptará una declaración de selección, por lo que si el SQL realmente necesita ser dinámico, haga que el cursor de declaración forme parte de la declaración que está ejecutando. Para que lo siguiente funcione, su servidor tendrá que usar cursores globales.

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

Si necesita evitar el uso de cursores globales, también puede insertar los resultados de su SQL dinámico en una tabla temporal y luego usar esa tabla para completar su cursor.

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

Este código es un muy buen ejemplo para una columna dinámica con un cursor, ya que no puede usar ‘+’ en @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 ''%''[email protected]+''%'';
            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

Trabajar con una base de datos no relacional (¿IDMS alguien?) a través de una conexión ODBC califica como uno de esos momentos en los que los cursores y el SQL dinámico parecen la única ruta.

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

tarda 45 minutos en responder mientras que se reescribe para usar conjuntos de claves sin la cláusula in se ejecutará en menos de 1 segundo:

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

Si la declaración in para la columna B contiene 1145 filas, usar un cursor para crear declaraciones individuales y ejecutarlas como SQL dinámico es mucho más rápido que usar la cláusula in. tonto oye?

Y sí, no hay tiempo en una base de datos relacional en el que se deba usar el cursor. Simplemente no puedo creer que me he encontrado con una instancia en la que un bucle de cursor es varias magnitudes más rápido.

Comentarios y valoraciones del artículo

Agradecemos que desees estimular nuestra tarea exponiendo un comentario y dejando una puntuación te lo agradecemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *