Twitter Facebook Google + RSS Feed

Cursores en SQL Server

24
SQL Server

Jueves, 26 de noviembre de 2009 a las 10:27hs por Dario Krapp

Introducción, conceptos y definiciones básicas

En SQL Server un cursor puede definirse como un elemento que representará a un conjunto de datos determinado por una consulta T-SQL, el cursor permitirá recorrer fila a fila, leer y eventualmente modificar dicho conjunto de resultados.

SQL Server ofrecerá una amplia variedad de opciones y de funciones para crear y operar sobre cursores. En este articulo, donde hemos utilizado SQL Server 2008 Enterprise Edition en los ejemplos, daremos un paseo por las posibilidades disponibles.

La creación y utilización de un cursor estará compuesta, como es de esperarse, por una serie de instrucciones T-SQL, las cuales podrán separarse en grupos bien diferenciados, los cuales son: Declaración, Apertura, Acceso a datos, Cierre y Desalojo, a continuación detallaremos cada grupo de instrucciones.

Declaración

El primer paso constará de la declaración del cursor, donde se indicarán (junto con el nombre del cursor) la consulta que el mismo representará y algunas otras características bastante interesantes.

Un ejemplo de declaración de cursor es el siguiente:

DECLARE ProdInfo CURSOR FOR SELECT Name FROM Production.Product

Donde ProdInfo representará al nombre del cursor y la sentencia “SELECT ProductNumber,Name FROM Production.Product” será el conjunto de datos del mismo.

Como comentamos previamente, es posible en este paso definir algunas características del comportamiento del cursor, por ejemplo la sentencia:

DECLARE ProdInfo CURSOR READ_ONLY FOR SELECT Name FROM Production.Product

Indicará que el cursor será de solo lectura, más adelante veremos en detalle las opciones disponibles, por el momento nuestro objetivo es crear un cursor lo más simple posible.

Apertura

La apertura del cursor ejecutará la consulta definida en el paso previo y cargará los datos en el mismo. La función OPEN de T-SQL permitirá efectuar esta terea, para continuar con el ejemplo previo la forma de abrir el cursor será la siguiente:

OPEN   ProdInfo

Recorrido del cursor y acceso a los datos

Este paso constará de recorrer los resultados del cursor, la instrucción FETCH permitirá efectuar dicha operación. Las filas leídas podrán copiarse a variables utilizando la sentencia INTO en combinación con la sentencia FETCH, por ejemplo la sentencia:

FETCH NEXT FROM ProdInfo INTO @Description

Tomará la siguiente fila de resultados del cursor y lo alojará en la variable @Description.

Un detalle a comentar es que en la sentencia INTO (como puede verse en el ejemplo anterior) el mapeo entre columnas del cursor y variables se realizará implícitamente, asignándose la primera columna a la primera variable, la segunda columna a la segunda variable y así sucesivamente. Esto implica que deberán crearse tantas variables como columnas se definan en la declaración del cursor y las mismas deberán ubicarse en el mismo orden que se encuentran definidas las columnas en la sentencia SELECT de la declaración.

Como cada sentencia FETCH leerá un registro, una pregunta interesante que podríamos hacernos es, ¿de qué manera podremos saber si existe un próximo o previo registro, o si hemos llegado al límite (ya sea superior o inferior)?. La respuesta se encontrará en una variable de SQL Server llamada @@FETCH_STATUS que tomará el valor 0 si la lectura del registro ha sido correcta.

En este punto será también posible modificar o eliminar las filas que se van recorriendo, como veremos al final del artículo.

Cierre del cursor

En el cierre del cursor se liberarán los registros tomados por el mismo. Una vez que el cursor es cerrado ya no podrá recorrerse el conjunto de resultados hasta que el mismo sea reabierto, la sentencia CLOSE cerrará un cursor abierto y la sintaxis puede verse a continuación:

CLOSE  ProdInfo

Desalojo del cursor

Este paso eliminará la referencia al cursor definido previamente, por lo que ya no será posible realizar una reapertura del mismo, en este caso la sintaxis será:

DEALLOCATE ProdInfo

Ejemplo de cursor

A continuación juntaremos todos los pasos descriptos previamente y crearemos el ejemplo más simple de un cursor el cual recorrerá la tabla Production.ProductDescription de la base de datos AdventureWorks y mostrará por pantalla el valor del registro Description luego que el mismo ha sido copiado a la variable @Description.

DECLARE @Description AS nvarchar(400) 
DECLARE ProdInfo CURSOR FOR SELECT [Description] FROM Production.ProductDescription 
OPEN ProdInfo
FETCH NEXT FROM ProdInfo INTO @Description
WHILE @@fetch_status = 0
BEGIN
    PRINT @Description
    FETCH NEXT FROM ProdInfo INTO @Description
END
CLOSE ProdInfo
DEALLOCATE ProdInfo

En el ejemplo puede verse la utilización de la variable @@FETCH_STATUS para verificar la existencia de la fila leída, por otra parte la sentencia FETCH NEXT devolverá la próxima fila de datos, siempre que la misma exista.
Este ejemplo, a pesar de parecer tan trivial y claro esconde un amplia variedad de comportamientos que el cursor asumirá, y que en este caso han tomado el valor por defecto, ya que no los hemos definido explícitamente.
El próximo paso será dar una recorrida por estas opciones y entender cuales se adaptarán mejor a nuestras necesidades.


24 comentarios »

  1. HMB dice:

    Claro y sencillo… me ayudo.

  2. Rayco dice:

    Una buena iniciación al uso de los cursores en Transact SQL, buen aporte.

  3. Kristian dice:

    Excelente esta muy entendible, gracias por el aporte, pero desearia obtener mas info tal vez me podrian ayudar con un manual. O donde puedo conseguir

  4. andrestkd dice:

    Practico y concreto, buen aporte.

  5. Jose Zarate dice:

    Excelente!! mas claro lo tengo

  6. jeremiasm dice:

    En que parte se guardan los cursores, tengo sql server 2008 y no encuentro en el explorador de objetos el cursor creado.

    • Dario Krapp dice:

      Hola jeremiasm, buenos días

      El tema es que un cursor no es un objeto persistente que se almacena en tablas del SQL como por ejemplo las tablas, los stored procedures o los indices entre otros.
      Los cursores son objetos que se crean en memoria (por eso es importante utilizar la sentencia deallocate para desalojarlo de la memoria que utiliza SQL Server). Por ese motivo no los vas a poder encontrar en el object explorer.
      Slds

  7. Luis dice:

    entendi muy bien, se agradece

  8. Edwin dice:

    Gracias Por la Ayuda …
    Buen Aporte .

  9. Sebastian dice:

    Gracias por el aporte, por cierto que buen nombre el del sitio, me veo muy identificado con este!.

  10. ERNESTO dice:

    Muy buen comentario , quisiera me pudieran ayudar , quiero realizar un cursor haciendo lo siguiente espero me puedan ayudar tengo 2 tablas
    Tabla 1 Folio
    Tabla 2 Folio + Precio

    quisiera actualizar mi tabla 1 de la 2 por medio de un cursor,quedo en espera de sus valiosos comentarios

  11. manuel lora dice:

    excelente me gusto

  12. KS dice:

    muy bueno, pero quisiera que me puedas ayudar, quiero hacer un cursor que me ayude a actualizar un campo por ejemplo:

    telefono DNI1
    telefono DNI1

    de lo anterior quisiera lo siguiente:

    telefono1 DNI1
    telefono2 DNI1

    Tendras algun material que me pueda ayudar.

    Saludos

  13. jrcastillof dice:

    Muy Buen Aporte,, lo voy a revisar, mas tarde (a la media noche), pero por lo que leí se nota claro y sencillo.

  14. VerSanCheZ dice:

    Hola a todos, tengo dos tablas ( Empleados y Entradas ), lo que quiero saber es como le hago para que la consulta me devuelva lo siguiente:

    No. Nombre Reg1 Reg2 Reg3 Reg4
    01 Pedro 07:10:20 11:45:00 12:36:14 18:50:44
    02 Luis 09:15:20 11:05:00 11:36:14 17:50:44

    La Tabla Empleado tienen los siguientes Campos;
    No. int
    Nombre varchar

    Registros de la tabla de Empleados
    01 Pedro
    02 Luis
    03 Paco

    Y la Tabla Entradas
    No. int
    Fecha date
    Registro time(0)

    Registros de la tabla Entradas
    01 2015-01-01 07:10:20
    02 2015-01-01 09:15:20
    01 2015-01-01 11:45:00
    02 2015-01-01 11:05:00
    01 2015-01-01 12:36:14
    02 2015-01-01 11:36:14
    01 2015-01-01 18:50:44
    02 2015-01-01 17:50:44

  15. carlos dice:

    Realmente muy útil!

  16. Jonathan dice:

    Muy bien explicado, excelente (y)

  17. Jesus Ob Ac dice:

    gracias por el aporte, me ha servido como no tienes idea.

    saludos

  18. Roman dice:

    Muchas gracias! Mas claro imposible!!!

Deja un comentario

Buscar