viernes, 15 de mayo de 2009

Crear un Cursor SQL Server

Saludos, En esta ocación voy a mostrarle como crear un cursor en SQL Server y explicar la importancia del mismo.

Un cursor es una herramienta de SQL Server que nos permite recorrer el resultado de una consulta SQL y realizar operaciones con estos resultados dentro de un bucle de datos.

Para mostrar la sintaxis del cursor utilizemos el siguiente planteamiento, tenemos una tabla denominada persona y deseamos imprimir en pantalla los nombres y apellidos de todos los registros almacenados en la table persona.

La sintaxis de declaración de un cursor es la siguiente:

declare cursor_prueba cursor for
select nombres, apellidos from persona

/*ahora declaramos las variables con las que vamos a recorrer el cursor:*/

declare @nombres varchar(25)
declare @apellidos varchar(25)

/*Abrimos el cursor para iniciar el recorrido del mismo*/
open cursor_prueba

/*Se mueve al siguiente registro dentro del cursor y los asignamos a las variables antes declaradas*/
fetch next from cursor_prueba
into @nombres, apellidos

/*Retorna el estatus del último registro recorrido en el cursor, cuando es igual a 0 encontró registro pendientes de recorrer*/
while @@fetch_status = 0
begin

print 'El Nombre de la persona es: ' + @nombres + ' y sus apellidos: ' + apellidos

/*Se mueve al siguiente registro dentro del cursor*/
fetch next from cursor_prueba
into @nombres, apellidos


end

/* Cuando concluimos con el recorrido del cursor, este debe ser cerrado y luego destruído mediante las siguientes sentencias:*/
close cursor_prueba --Cierra el cursor.
deallocate cursor_prueba --Lo libera de la memoria y lo destruye.

Los cursores son muy eficientes para utilizarlos en Job de las base de datos que realizen alguna operación donde necesitemos modificar alguna información dentro de un bucle. Los cursores demandan mucho del servidor de base datos, por lo tanto, no es recomendable abusar del mismo, ya que necesitan bastante recursos para su ejecución

30 comentarios:

Anónimo dijo...

Excelente Artículo, como puedo crear dos cursores anidados, uno dentro de otro?

Anónimo dijo...

Muchas gracias, me fue muy útil.

Anónimo dijo...

Dos cursores anidades, no quiero ni imaginar lo que sería de ese servidor. Seguramente lo tiraría por la borda.
Salvo en situaciones extremas, dí NO A LOS CURSORES!!!!

Anónimo dijo...

No a los CURSORES jejejje

Michael Núñez dijo...

Querido Anónimo,

Nunca digas No a nada que te puede sacar de un apuro, es cierto que los cursores aumento de forma exponencial el uso del CPU haciendo que la base de datos presente bloqueos, pero todo depende del programador y su experiencia y el uso que le vas a dar a ese cursor, para actualizaciones masivas que no se van a ejecutar siempre, para que programar si lo puedes hacer de forma sencilla con un cursor.

Anónimo dijo...

Muy bien explicado y en mi poca experiencia un cursor seria la ultima salida pero suele ser el salvavidas en cuestion de dar resultados.

Anónimo dijo...

Un cordial saludo me pueden explicar por que me sale este error

DECLARE CURSOR must be the only statement in a query batch.

Estoy creando un cursor dentro de un sp el cual va a recorrer los impuestos de mi proveedor e imprimira los impuestos q el posee

DECLARE CursorImpuesto CURSOR FOR SELECT cod_impuesto FROM tmp_rpte_prov_impuesto
DECLARE @Id_Codigo numeric(2,0)

OPEN CursorImpuesto
FETCH NEXT FROM CursorImpuesto INTO @Id_Codigo
WHILE @@fetch_status = 0
BEGIN
PRINT @Id_Codigo
FETCH NEXT FROM CursorImpuesto INTO @Id_Codigo
END
CLOSE CursorImpuesto
DEALLOCATE CursorImpuesto

Se los agradezco

Michael Núñez dijo...

El problema es la declaración, tienes que cambiarla a esta forma

DECLARE @Id_Codigo numeric(2,0)

DECLARE CursorImpuesto CURSOR FOR SELECT cod_impuesto FROM tmp_rpte_prov_impuesto

OPEN CursorImpuesto

puedes probar de esa forma.

Anónimo dijo...

muchas gracias creo entender cual fue mi error pero a la final lo logre con tablas temporales

Anónimo dijo...

muchas gracias, esta muy bien explicado me sirvio para un trabajo escolar de la uni, felicitaciones!

Anónimo dijo...

buenas tardes, mi pregunta es como imprimo una sentencia sql q tengo en un cursor

Michael Núñez dijo...

Solo tienes que utilizar la sentencia print. Ojo, esta sentencia solo funciona con texto, por lo que tendrías que convertir a texto un valor numérico, fecha, etc.

Anónimo dijo...

Estimado.
Excelente explicacion. Muy agradecido por todo.
Te animo a que sigas adelante con el blog.

Anónimo dijo...

Gracias por compartir este código para realizar unos reportes, que ya me dolía la cabeza porque no daba con el código que estaba implementando. De verdad mil gracias por personas que comparten sus conocimientos.

jonny70 dijo...

Extraodinario, muy claro me sirvio mucho para recuperar datos historicos.

Anónimo dijo...

disculpen mi absoluta ignorancia soy nuevo trabajando directamente con el gestor de bases de datos, pero sino uso el cursor cual es la herramienta alternativa, es decir, sino uso el cursor que puedo usar en su lugar?

Michael Núñez dijo...

Bueno, una opción es utilizar un loop con un while.

Renzo dijo...

hola amigo una pregunta... se puede usar un cursor dentro de una funcion? ya que he creado una funcion con n cursor dentro y todo esta normal hasta antes del "while @@fetch_status = 0" a partir de alli no lee nada de lo q esta dentro del while.. porq? :(


EJEMPLO:


CREATE FUNCTION verCruceCursos(@curso1 as char(2),@curso2 as char(2))
RETURNS varchar(15)
as
BEGIN

declare @respuesta varchar(15)
set @respuesta = 'No Existe Cruce'

declare curCurso1 cursor for select dia,horainicio,duracion from horarios where curso=@curso1

declare @dia1 char(10)
declare @inicio1 int,@duracion1 int

open curCurso1
fetch next from curCurso1 into @dia1,@inicio1,@duracion1
while @@fetch_status = 0 --> A PARTIR DE AKI NO LEE NADA
begin
-- inicio cursor 1

declare curCurso2 cursor for
select dia,horainicio,duracion from horarios where curso=@curso2
.. etc

Michael Núñez dijo...

Si, los cursores trabajan dentro de un función, tienes que tener algo mal en tu cursor para que no realice lo que esperas.

Xavi dijo...

En el ejemplo le falta la @ al apellido, de esa forma quedaria:
fetch next from cursor_prueba
into @nombres, @apellidos

Anónimo dijo...

Hola, excelente página, estoy haciendo un trabajo para la U y no puedo ver cual es el problema de este proceso:

alter proc SP1
as

declare MiCursor cursor for -- declaro el cursor para
select id, valor, texto from Datos
order by id --ordena la tabla

declare @id Int
declare @valor int
declare @texto varchar

open MiCursor --abrimos el cursor

create table #paso (palabra varchar(100), cantidad int)

fetch next from MiCursor
into @id,@valor,@texto


if @@fetch_status <> 0
print ' No hay registros ' ;
while @@fetch_status = 0
begin

insert #paso

exec SeparaPalabras @texto

insert palabra
select @id,@valor, palabra, cantidad from #paso
where rtrim(palabra) is not null

Select * from #Paso

delete #paso

Fetch next from MiCursor

into @id ,@valor,@texto

end

close MiCursor
deallocate MiCursor

drop table #paso


Al ejecutarlpo me sale el siguiente error

Msg 16915, Level 16, State 1, Procedure SP1, Line 5
A cursor with the name 'MiCursor' already exists.
Msg 16905, Level 16, State 1, Procedure SP1, Line 12
The cursor is already open.

Gracias, Alejandra

Anónimo dijo...

DOS CURSORESS ????
...mmm... lo mejor seria queee...
en vez de 2 cursores, Hazte 4 CURSORES.

ASI TE DAN EL SOBRE AZUL Y QUEDAS LISTO!!, CON BILLETES $$$, EN EL BOLSILLO.

Luego buscas trabajo en otra empresa y pides el aumento que tanto quieres.

Resumen : Trabajo Nuevo y Plata para que te des los gustos.

...y todo por querer buscar la forma de complicar las cosas, cuando la respuesta es mas sencilla.

Saludos.
todo en muy buena onda!!.


Michael Núñez dijo...

Bueno, otro ignorante mas...si existe el cursor es por alguna razón o lo inventaron en vano. Te recomiendo que fomentes la lectura y luego hablamos.

Saludos, en buena onda.

Alejandra Vallejo Fdez. dijo...

Hola, gracias por tu publicacion esta bien explicada (como con bolitas y palitos...) soy ISC y en la universidad no vimos nada de cursores ni siquiera sabia que existian jaja, pero ahora debo utilizarlos porque se aplican mucho en mi actual trabajo.
Que bueno que haya personas que comparten sus conocimientos y ayudan a los demas, eres un ejemplo a seguir, al menos para mi :)
Saludos desde Puebla, Mexico.

alexa.avf@gmail.com
@Alexa_avf

Anónimo dijo...

Muchas gracias por el aporte!!!

Anónimo dijo...

hola, una pregunta:

tengo el valor 09-23-13 13:00:10 en char que es fecha y hora, como lo puedo convertir a smalldatetime?

GRACIAS...

Michael Núñez dijo...

puedes usar Convert(datetime, campo) o cast(campo as datetime)

Anónimo dijo...

ok, ya lo hice asi:
select convert(datetime, fec_che) as fecha from t_checador
solo que marca el sig error:
The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value.

y eso es solo en el select, yo lo quiero insertar en una tabla donde el tipo de dato es smalldatetime.

gracias...

Anónimo dijo...

ayuda por favor!!!!!!!!!
=)


Crear un Stored procedure que
utilizando un curso realice lo siguiente
Obtener la fecha de nacimiento y calcular
la edad y actualizar el campo EDAD.

CREATE TABLE ALUMNOS (
ID_ALUMNO NUMBER(3),
NOMBRE VARCHAR2(100),
APELLIDO_PATERNO VARCHAR2(100),
APELLIDO_MATERNO VARCHAR2(100),
FECHA_NAC DATE,
FECHA_GRAD DATE,
MES_NAC VARCHAR2(20)
DIA_GRAD VARCHAR2(20)
EDAD NUMBER(2);

Anónimo dijo...

es muy interesante quisiera aprender mas sobre ese tema de cursores...podría poner mas ejemplos