Cursores en Transact -SQL - Copia

28
Base de Datos II Ingeniería de Sistemas CURSORES TRANSACT-SQL

Transcript of Cursores en Transact -SQL - Copia

Page 1: Cursores en Transact -SQL - Copia

Base de Datos IIIngeniería de Sistemas

CURSORES TRANSACT-SQL

Page 2: Cursores en Transact -SQL - Copia

CURSORES EN TRANSACT-SQL

• Un cursor es una variable que nos permite recorrer con un conjunto de resultados obtenidos a través de una sentencia SELECT fila a fila.

• Cuando trabajemos con cursores, debemos seguir los siguientes pasos:• Declarar el cursor, utilizando DECLARE• Abrir el cursor, utilizando OPEN• Leer los datos del cursor, utilizando FETCH ...

INTO• Cerrar el cursor, utilizando CLOSE• Liberar el cursor, utilizando DEALLOCATE

Page 3: Cursores en Transact -SQL - Copia

La sintaxis general para trabajar con un cursor es la siguiente:

Page 4: Cursores en Transact -SQL - Copia

Ejemplo-- Declaracion de variables para el cursorDECLARE @Id int,@Nombre varchar(255),@Apellido1 varchar(255),@Apellido2 varchar(255),@NifCif varchar(20),@FxNacimiento datetime

-- Declaración del cursorDECLARE cClientes CURSOR FORSELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimientoFROM CLIENTES-- Apertura del cursorOPEN cClientes

-- Lectura de la primera fila del cursor

FETCH cClientes INTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif, @FxNacimiento WHILE (@@FETCH_STATUS = 0 )BEGINPRINT @Nombre + ' ' + @Apellido1 + ' ' + @Apellido2-- Lectura de la siguiente fila del cursorFETCH cClientes INTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif, @FxNacimientoEND -- Cierre del cursorCLOSE cClientes-- Liberar los recursosDEALLOCATE cClientes

Page 5: Cursores en Transact -SQL - Copia

Declare CURSOR• Esta instrucción permite la declaración y la descripción del cursor ANSI.

Sintaxis:

INSENSITIVE solo se permiten las operaciones sobre la fila siguienteSCROLL los desplazamientos en las filas del cursor podrán hacerse en todoslos sentidos.UPDATE especifica que las actualizaciones se harán sobre la tabla de origendel cursor. Un cursor INSENSITIVE con una cláusula ORDER BY no puedeactualizarse. Un cursor con ORDER BY, UNION, DISTINCT o HAVING esINSENSITIVE y READ ONLY.

Page 6: Cursores en Transact -SQL - Copia

En la apertura del cursor, podemos especificar los siguientes parámetros

Page 7: Cursores en Transact -SQL - Copia

LOCAL• Especifica que el ámbito del cursor es local para el proceso por

lotes, procedimiento almacenado o desencadenador en que se creó el cursor.

DECLARE cClientes CURSOR LOCAL FORSELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimientoFROM CLIENTES.

GLOBAL• Especifica que el ámbito del cursor es global para la conexión.

Puede hacerse referencia al nombre del cursor en cualquier procedimiento almacenado o proceso por lotes que se ejecute en la conexión.

DECLARE cClientes CURSOR GLOBAL FORSELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimientoFROM CLIENTES

El primer conjunto de parámetros que podemos especificar es

[ LOCAL | GLOBAL ].

Page 8: Cursores en Transact -SQL - Copia

El siguiente conjunto de parámetros que podemos especificar es [ FORWARD_ONLY | SCROLL ].

FORWARD_ONLYEspecifica que el cursor sólo se puede desplazar de la primera a la última fila.DECLARE cClientes CURSOR FORWARD_ONLY FORSELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimientoFROM CLIENTES

SCROLLEspecifica que están disponibles todas las opciones de recuperación (FIRST, LAST, PRIOR, NEXT, RELATIVE, ABSOLUTE). Si no se especifica SCROLL en una instrucción DECLARE CURSOR la única opción de recuperación que se admite es NEXT.Si se incluye la opción SCROLL, la forma en la realizamos la lectura del cursor varia, debiendo utilizar la siguiente sintaxis: FETCH [ NEXT | PRIOR | FIRST | LAST | RELATIVE | ABSOLUTE ] FROM nomCursor INTO

Page 9: Cursores en Transact -SQL - Copia

Ejemplo-- Declaracion de variables para el cursorDECLARE @Id int,@Nombre varchar(255),@Apellido1 varchar(255),@Apellido2 varchar(255),@NifCif varchar(20),@FxNacimiento datetime-- Declaración del cursorDECLARE cClientes CURSOR SCROLL FORSELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimientoFROM CLIENTES-- Apertura del cursorOPEN cClientes-- Lectura de la primera fila del cursorFETCH NEXT FROM cClientesINTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif, @FxNacimiento

WHILE (@@FETCH_STATUS = 0 )

BEGIN PRINT @Nombre + ' ' + @Apellido1 + ' ' + @Apellido2 -- Lectura de la siguiente fila del cursor FETCH NEXT FROM cClientes INTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif,@FxNacimientoEND-- Lectura de la fila anteriorFETCH PRIOR FROM cClientesINTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif, @FxNacimiento

PRINT @Nombre + ' ' + @Apellido1 + ' ' + @Apellido2

-- Cierre del cursorCLOSE cClientes-- Liberar los recursosDEALLOCATE cClientes

Page 10: Cursores en Transact -SQL - Copia

El siguiente conjunto de parámetros que podemos especificar es [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ].

STATICse realiza una copia temporal de los datos en la base de datos tempdb para que el cursor no se vea afectado por las modificaciones que puedan realizarse sobre la base de datos.DECLARE cClientes CURSOR STATIC FORSELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimientoFROM CLIENTES

KEYSETlas filas y su orden en el cursor se fijan en el momento de la apertura del cursor. Las referencias hacia cada una de estas filas de información se conservan en una tabla temporal en tempdb.DECLARE cClientes CURSOR KEYSET FORSELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimientoFROM CLIENTES

Page 11: Cursores en Transact -SQL - Copia

DYNAMICel cursor refleja exactamente los datos presentes en la base de datos. Esto significa que el número de filas, su orden y su valor pueden variar de forma dinámica.DECLARE cClientes CURSOR DYNAMIC FORSELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimientoFROM CLIENTES

FAST_FORWARDpermite definir un cursor hacia adelante y como sólo lectura(FORWARD_ONLY y READ_ONLY).DECLARE cClientes CURSOR FAST_FORWARD FORSELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimientoFROM CLIENTES

Page 12: Cursores en Transact -SQL - Copia

El siguiente conjunto de parámetros que podemos especificar es [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ].

READ_ONLY : Evita que se efectúen actualizaciones a través de este cursor. No es posible hacer referencia al cursor en una cláusula WHERE CURRENT OF de una instrucción UPDATE o DELETE. Esta opción reemplaza la capacidad de actualizar el cursor.SCROLL_LOCKS permite garantizar el éxito de las instrucciones UPDATE y DELETE que pueden ser ejecutadas en relación al cursor. Con este tipo de cursor, se fija un bloqueo en la apertura para evitar que otra transacción trate de modificar los datos.OPTIMISTIC con esta opción, puede que una operación de UPDATE o DELETE realizada en el cursor no pueda ejecutarse correctamente, porque otra transacción haya modificado los datos en paralelo.TYPE_WARNING se envía un mensaje (warning) a la aplicación cliente, si se efectúan conversiones implícitas de tipo solicitado a otro.

Page 13: Cursores en Transact -SQL - Copia

• Para actualizar los datos de un cursor debemos especificar FOR UPDATE despues de la sentencia SELECT en la declaración del cursor, y WHERE CURRENT OF <nombre_cursor> en la sentencia UPDATE tal y como muestra el siguiente ejemplo.

Page 14: Cursores en Transact -SQL - Copia

actualizamos el precio de los productos: si su stock es mayor o igual a 1000, se descuenta el precio al 50%, sino se descuenta el precio al 20%.-- DECLARACION DE VARIABLES PARA EL CURSORDECLARE @ID INT, @NOMBRE VARCHAR(255), @PRECIO DECIMAL, @ST INT-- DECLARACIÓN DEL CURSOR DE ACTUALIZACIONDECLARE CPRODUCTO CURSOR FOR

SELECT IDPRODUCTO,NOMBREPRODUCTO,

PRECIOUNIDAD,UNIDADESENEXISTENCIA

FROM TB_PRODUCTOS

FOR UPDATE-- APERTURA DEL CURSOROPEN CPRODUCTO-- LECTURA DE LA PRIMERA FILA DEL CURSOR

FETCH CPRODUCTO INTO@ID, @NOMBRE, @PRECIO, @ST-- MIENTRAS PUEDA LEER EL REGISTROWHILE (@@FETCH_STATUS = 0 )BEGIN

IF(@ST>=1000) SET @PRECIO = 0.5*@PRECIOELSE SET @PRECIO = 0.80*@PRECIOUPDATE TB_PRODUCTOS SET PRECIOUNIDAD = @PRECIOWHERE CURRENT OF CPRODUCTO--IMPRIMIRPRINT 'EL PRECIO DE PRODUCTO '+ @NOMBRE+ ' ES ' + STR(@PRECIO)-- LECTURA DE LA SIGUIENTE FILA DEL CURSORFETCH CPRODUCTO INTO @ID, @NOMBRE, @PRECIO, @ST

END-- CIERRE DEL CURSORCLOSE CPRODUCTO-- LIBERAR LOS RECURSOSDEALLOCATE CPRODUCTO

Page 15: Cursores en Transact -SQL - Copia

-- Declaracion de variables para el cursor DECLARE @Id int, @Nombre varchar(255), @Apellido1 varchar(255), @Apellido2 varchar(255), @NifCif varchar(20), @FxNacimiento datetime -- Declaración del cursor DECLARE cClientes CURSOR FOR SELECT Id, Nombre, Apellido1, Apellido2, NifCif, FxNacimiento FROM CLIENTES FOR UPDATE -- Apertura del cursor OPEN cClientes -- Lectura de la primera fila del cursor FETCH cClientes INTO @id, @Nombre, @Apellido1,

@Apellido2, @NifCif, @FxNacimiento WHILE (@@FETCH_STATUS = 0 ) BEGIN UPDATE Clientes

SET Apellido2 = isnull(@Apellido2, ' ') + ' - Modificado' WHERE CURRENT OF cClientes -- Lectura de la siguiente fila del

cursor FETCH cClientes INTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif,

@FxNacimiento END -- Cierre del cursor CLOSE cClientes -- Liberar los recursos DEALLOCATE cClientes

Page 16: Cursores en Transact -SQL - Copia

Abrir un CursorEsta instrucción permite hacer operativo el cursor y crear eventualmente las tablas temporales asociadas. La variable @@CURSOR_ROWS se asigna después de OPEN.Teniendo en cuenta el espacio en disco y la memoria utilizada, y el bloqueo eventual de los datos en la apertura del cursor, esta operación debe ser ejecutada lo más cerca posible del tratamiento de los datos extraídos del cursor.Sintaxis:

OPEN [ GLOBAL ] <nombre_cursor>

Page 17: Cursores en Transact -SQL - Copia

Leer un Registro: FETCH• Es la instrucción que permite extraer una fila del cursor y

asignar valores a variables con su contenido. Tras FETCH, la variable @@FETCH_STATUS está a 0 si FETCH no retorna errores.

• NEXT lee la fila siguiente (única opción posible para los INSENSITIVE

CURSOR).• PRIOR lee la fila anterior• FIRST lee la primera fila• LAST lee la última fila• ABSOLUTE n lee la enésima fila del conjunto• RELATIVE n lee la enésima fila a partir de la fila actual.

Page 18: Cursores en Transact -SQL - Copia

• Cuando trabajamos con cursores, la función @@FETCH_STATUS nos indica el estado de la última instrucción FETCH emitida. Los valores posibles son los siguientes:

Page 19: Cursores en Transact -SQL - Copia

Cerrar el cursor

Cierra el cursor y libera la memoria. Esta operación debe interponerse lo antes posible con el fin de liberar los recursos cuanto antes. La sintaxis es la siguiente:

CLOSE <nombre_cursor>

Page 20: Cursores en Transact -SQL - Copia

Liberar los recursos

• Es un comando de limpieza, no forma parte de la especificación ANSI. • La sintaxis es la siguiente:• DEALLOCATE <nombre_cursor>

Page 21: Cursores en Transact -SQL - Copia

Ejemplos• Ejemplo 1: Trabajando con un cursor, mostrar el primer

registro de productos. --CURSORESDECLARE MI_CURSOR CURSOR FORSELECT TOP 1 * FROM COMPRAS.PRODUCTOS--ABRIROPEN MI_CURSOR--IMPRIMIR EL PRIMER REGISTROFETCH NEXT FROM MI_CURSOR--CERRARCLOSE MI_CURSOR--LIBERARDEALLOCATE MI_CURSOR

Page 22: Cursores en Transact -SQL - Copia

Ejemplo• Ejemplo 2: Trabajando con un cursor dinámico, defina un

cursor dinámico que permita visualizar: el primer registro, el registro en la posición 6 y el último registro.

--CURSORESDECLARE MI_CURSOR CURSOR SCROLL FORSELECT * FROM COMPRAS.PRODUCTOS-- ABRIROPEN MI_CURSOR-- IMPRIMIR LOS REGISTROSFETCH FIRST FROM MI_CURSORFETCH ABSOLUTE 6 FROM MI_CURSORFETCH LAST FROM MI_CURSOR-- CERRARCLOSE MI_CURSOR-- LIBERARDEALLOCATE MI_CURSOR

Page 23: Cursores en Transact -SQL - Copia

Ejemplo• Ejemplo: Trabajando con un

cursor, listar los clientes registrados en la base de datos, incluya el nombre del país.

-- DECLARO VARIABLES DE TRABAJODECLARE @ID VARCHAR(5) , @NOMBRE VARCHAR(50), @PAIS VARCHAR(50)-- DECLARO EL CURSORDECLARE MI_CURSOR CURSOR FORSELECT C.IDCLIENTE,

C.NOMBRECLIENTE,P.NOMBREPAIS

FROM VENTAS.CLIENTES CJOIN VENTAS.PAISES P ON C.IDPAIS=P.IDPAIS-- ABRIROPEN MI_CURSOR

-- LEER EL PRIMER REGISTROFETCH MI_CURSOR INTO @ID, @NOMBRE, @PAIS--MIENTRAS PUEDA LEER EL REGISTROWHILE @@FETCH_STATUS=0BEGIN--IMPRIMIR EL REGISTROPRINT@ID+','+@NOMBRE+','+@PAIS--LEER EL REGISTRO SIGUIENTEFETCH MI_CURSOR INTO @ID, @NOMBRE, @PAISEND-- CERRARCLOSE MI_CURSOR-- LIBERARDEALLOCATE MI_CURSOR;

Page 24: Cursores en Transact -SQL - Copia

Ejemplolistar la relación de los clientes que han registrado pedidos. En dicho proceso, debemos imprimir el nombre del cliente, la cantidad de pedidos registrados y al finalizar totalizar el proceso (suma total de todos los pedidos).-- DECLARO VARIABLES DE TRABAJODECLARE @NOMBRE VARCHAR(50), @Q

INT, @TOTAL INTSET @TOTAL=0-- DECLARO EL CURSORDECLARE MI_CURSOR CURSOR FORSELECT C.NOMBRECIA,COUNT(*)FROM VENTAS.CLIENTES CJOIN VENTAS.PEDIDOSCABE PC ON

C.IDCLIENTE=PC.IDCLIENTEGROUP BY C.NOMBRECLIENTE-- ABRIROPEN MI_CURSOR-- LEER EL PRIMER REGISTRO

FETCH MI_CURSOR INTO @NOMBRE, @Q-- MIENTRAS PUEDA LEER EL REGISTROWHILE @@FETCH_STATUS=0BEGIN-- IMPRIMIR EL REGISTROPRINT @NOMBRE+','+CAST(@Q AS VARCHAR)-- ACUMULARSET @TOTAL += @Q-- LEER EL REGISTRO SIGUIENTEFETCH MI_CURSOR INTO @NOMBRE, @QEND-- CERRARCLOSE MI_CURSOR-- LIBERARDEALLOCATE MI_CURSOR;-- IMPRIMIRPRINT 'TOTAL DE PEDIDOS:' + CAST(@TOTAL AS VARCHAR)

Page 25: Cursores en Transact -SQL - Copia

Ejemplos de Funciones en Transact sql• PROBLEMA 01: Promedio de números Implementar un

programa que halle e imprima el promedio de dos números enteros.

• a) utilizando procedimientos:-------------- PROCEDIMIENTO ALMACENADO --------------------------CREATE PROCEDURE p_getPromedio@A INT,@B INT,@C INT OUTPUTAS

BEGINSET @C = (@A + @B)/2

END------------------------------------------------------------------

Page 26: Cursores en Transact -SQL - Copia

----------------- PROGRAMA PRINCIPAL-----------------------------DECLARE @A floatDECLARE @B floatDECLARE @C float-- 1. Entrada de datos

set @A = 59set @B = 20

-- 2. Funcion / Procedimiento AlmacenadoEXEC p_getPromedio @A, @B, @C OUTPUT

-- 3. Salida de datosprint 'El promedio de los números ' + CAST(@A AS VARCHAR(10))+ ' y ' + CAST(@B AS VARCHAR(10))print 'Es el valor de: ' + CAST(@C AS VARCHAR(10))

Page 27: Cursores en Transact -SQL - Copia

----------------------- FUNCIONES -----------------------------CREATE FUNCTION getPromedio (@A FLOAT, @B FLOAT)RETURNS FLOATWITH EXECUTE AS CALLERAS

BEGIN

DECLARE @C FLOATSET @C = (@A + @B)/2RETURN @C

END

----------------- PROGRAMA PRINCIPAL-----------------------------DECLARE @A floatDECLARE @B floatDECLARE @C float-- 1. Entrada de datos

set @A = 59set @B = 20

-- 2. Funcion / Procedimiento Almacenadoset @C = dbo.getPromedio(@A, @B)

-- 3. Salida de datos

print 'El promedio de los números '+ CAST(@A AS VARCHAR(10)) + ' y ' + CAST(@B AS VARCHAR(10))

print 'Es el valor de: ' + CAST(@C AS VARCHAR(10))

Page 28: Cursores en Transact -SQL - Copia

Ejemplo1. Factorial, uso de la recursividad

Escribir un programa, que dado un valor de N, imprima en pantalla el número factorial de ese número.

2. Fibonacci, uso de la recursividadEscribir un programa, que dado un valor de N, imprima en pantalla el número Fibonnacci correspondiente (La secuencia de los números Fibonacci son: 0, 1, 1, 2, 3, 5, 8, 13, 21, 32,...)