005 Procedimientos Funciones TRigger y Cursores en Transact SQL
005 Procedimientos Funciones TRigger y Cursores en Transact SQL
END
SALDO_ANTERIOR,
SALDO_POSTERIOR,
IMPORTE,
FXMOVIMIENTO
FROM MOVIMIENTOS
INNER JOIN CUENTAS ON MOVIMIENTOS.IDCUENTA = CUENTAS.IDCUENTA
WHERE NUMCUENTA = @numCuenta
ORDER BY FXMOVIMIENTO DESC
END
La ejecución del procedimiento se realiza normalmente.
RETURN @Return
END
Pueden ser utilizadas en cualquier sentencia Transact SQL. Un aspecto a tener en cuenta, es que para
utilizar una función escalar debemos identificar el nombre de la función con el propietario de la misma.
El siguiente ejemplo muestra como utilizar la función anteriormente creada en una sentencia Transact
SQL. Un aspecto muy a tener en cuenta es que la función ejecutará sus sentencias SELECT una vez por cada
fila del conjunto de resultados devuelto por la consulta SELECT principal.
SELECT IDCUENTA,
NUMCUENTA,
SALDO,
FXALTA,
-- Ejecucion de la funcion:
dbo.fn_MultiplicaSaldo( NUMCUENTA, IDCUENTA) AS RESULTADO
FROM CUENTAS
El siguiente ejemplo muestra como utilizar una función escalar en un script Transact SQL.
PRINT @Resultado
Las funciones escalares son muy similares a procedimientos almacenados con parámetros de
salida, pero estas pueden ser utilizadas en consultas de seleccion y en la clausula where de las
mismas.
Las funciones no pueden ejecutar sentencias INSERT o UPDATE.
Funciones en linea
Las funciones en linea son las funciones que devuelven un conjunto de resultados
correspondientes a la eecución de una sentencia SELECT.
La sintaxis para una función de tabla en linea es la siguiente:
(
-- Lista de parámetros
<@param1, sysname, @p1> <Data_Type_For_Param1, , int>,...
)
RETURNS TABLE
AS
RETURN
(
-- Sentencia Transact SQL
)
El siguiente ejemplo muestra como crear una función en linea.
SELECT *
FROM CUENTAS
INNER JOIN CUENTAS_CLIENTE
ON CUENTAS_CLIENTE.IDCUENTA = CUENTAS.IDCUENTA
INNER JOIN CLIENTES
ON CLIENTES.id = CUENTAS_CLIENTE.IDCLIENTE
INNER JOIN fn_MovimientosCuenta('200700000001') A
ON A.IDCUENTA= CUENTAS.IDCUENTA
Funciones en línea de multiples sentencias
Las funciones en línea de multiples sentencias son similares a las funciones en línea excepto
que el conjunto de resultados que devuelven puede estar compuesto por la ejecución de varios
consultas SELECT.
Este tipo de función se usa en situaciones donde se requiere una mayor lógica de proceso.
La sintaxis para una funciones de tabla de multi sentencias es la siguiente:
Saldo_posterior decimal(10,2),
Importe_Movimiento decimal(10,2),
FxMovimiento datetime
)
AS
BEGIN
-- Variables necesarias para la lógica de la funcion.
DECLARE @idcuenta int,
@numcuenta varchar(20),
@saldo decimal(10,2)
OPEN CDATOS
FETCH CDATOS INTO @idcuenta, @numcuenta, @saldo
-- Recorremos el cursor
WHILE (@@FETCH_STATUS = 0)
BEGIN
-- Insertamos la cuenta en la variable de salida
INSERT INTO @datos
(NumCuenta, Saldo)
VALUES
(@numcuenta, @saldo)
-- Insertamos los tres últimos movimientos de la cuenta
INSERT INTO @datos
(Saldo_anterior, Saldo_posterior,
Importe_Movimiento, FxMovimiento )
SELECT TOP 3
SALDO_ANTERIOR, SALDO_POSTERIOR,
IMPORTE, FXMOVIMIENTO
FROM MOVIMIENTOS
WHERE IDCUENTA = @idcuenta
ORDER BY FXMOVIMIENTO DESC
-- Vamos a la siguiente cuenta
FETCH CDATOS INTO @idcuenta, @numcuenta, @saldo
END
CLOSE CDATOS;
DEALLOCATE CDATOS;
RETURN
END
Para ejecutar la función:
En la segunda (deleted), disponible en las operaciones UPDATE y DELETE, están los valores
anteriores a la ejecución de la actualización o borrado. Es decir, los datos que serán borrados.
Deleted estará vacia en una operacion INSERT.
¿No existe una tabla UPDATED? No, hacer una actualización es lo mismo que borrar (deleted)
e insertar los nuevos (inserted). La sentencia UPDATE es la única en la que inserted y deleted
tienen datos simultaneamente.
No puede se modificar directamente los datos de estas tablas.
El siguiente ejemplo, graba un historico de saldos cada vez que se modifica un saldo de la tabla
cuentas.
UPDATE CUENTAS
SET SALDO = SALDO + 10
WHERE IDCUENTA = 1
Una consideración a tener en cuenta es que el trigger se ejecutará aunque la instruccion DML
(UPDATE, INSERT o DELETE ) no haya afectado a ninguna fila. En este caso inserted y deleted
devolveran un conjunto de datos vacio.
Podemos especificar a que columnas de la tabla debe afectar el trigger.
BEGIN
-- SET NOCOUNT ON impide que se generen mensajes de texto
-- con cada instrucción
SET NOCOUNT ON;
ROLLBACK
END
En este caso obtendremos el siguiente mensaje de error:
La transacción terminó en el desencadenador. Se anuló el lote.
Podemos activar y desactivar Triggers a tarvés de las siguientes instrucciones.
GO
-- activa el trigger TR_CUENTAS
ENABLE TRIGGER TR_CUENTAS ON CUENTAS
GO
-- Desactiva todos los trigger de la tabla CUENTAS
ALTER TABLE CUENTAS DISABLE TRIGGER ALL
GO
-- Activa todos los trigger de la tabla CUENTAS
ALTER TABLE CUENTAS ENABLE TRIGGER ALL
Trigger DDL
Los trigger DDL se ejecutan en respuesta a una variedad de eventos de lenguaje de
definición de datos (DDL). Estos eventos corresponden principalmente a instrucciones
CREATE, ALTER y DROP de Transact-SQL, y a determinados procedimientos
almacenados del sistema que ejecutan operaciones de tipo DDL.
La sintaxis general de un trigger es la siguiente.
WHILE (@@FETCH_STATUS = 0)
BEGIN
-- Lectura de la siguiente fila de un cursor
FETCH <nombre_cursor> INTO <lista_variables>
...
END -- Fin del bucle WHILE
-- Cierra el cursor
CLOSE <nombre_cursor>
-- Libera los recursos del cursor
DEALLOCATE <nombre_cursor>
WHILE (@@FETCH_STATUS = 0 )
BEGIN
PRINT @Nombre + ' ' + @Apellido1 + ' ' + @Apellido2
-- Lectura de la siguiente fila del cursor
FETCH cClientes INTO @id, @Nombre, @Apellido1,
@Apellido2, @NifCif, @FxNacimiento
END
Especifica que el ámbito del cursor es local para el proceso por lotes, procedimiento almacenado o
desencadenador en que se creó el cursor.
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.
Especifica que el cursor sólo se puede desplazar de la primera a la última fila. FETCH NEXT es la
única opción de recuperación admitida.
SCROLL
Especifica 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. No es posible especificar
SCROLL si se incluye también FAST_FORWARD.
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 < INTO
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,@FxNacimiento
END
-- Lectura de la fila anterior
FETCH PRIOR FROM cClientes
INTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif, @FxNacimiento
PRINT @Nombre + ' ' + @Apellido1 + ' ' + @Apellido2
-- Cierre del cursor
CLOSE cClientes
-- Liberar los recursos
DEALLOCATE cClientes
El siguiente conjunto de parámetros que podemos especificar es [ STATIC | KEYSET |
DYNAMIC | FAST_FORWARD ]. A continuación mostramos el significado de cada una de estas
opciones.
STATIC
Define un cursor que hace una copia temporal de los datos que va a utilizar. Todas las solicitudes
que se realizan al cursor se responden desde esta tabla temporal de tempdb; por tanto, las
modificaciones realizadas en las tablas base no se reflejan en los datos devueltos por las
operaciones de recuperación realizadas en el cursor y además este cursor no admite modificaciones.
Especifica que la pertenencia y el orden de las filas del cursor se fijan cuando se abre el cursor. El
conjunto de claves que identifica las filas de forma única está integrado en la tabla denominada
keyset de tempdb.
Define un cursor que, al desplazarse por él, refleja en su conjunto de resultados todos los cambios
realizados en los datos de las filas. Los valores de los datos, el orden y la pertenencia de las filas
pueden cambiar en cada operación de recuperación. La opción de recuperación ABSOLUTE no se
puede utilizar en los cursores dinámicos.
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.
Especifica que se garantiza que las actualizaciones o eliminaciones posicionadas realizadas a través
del cursor serán correctas. Microsoft SQL Server bloquea las filas cuando se leen en el cursor para
garantizar que estarán disponibles para futuras modificaciones. No es posible especificar
SCROLL_LOCKS si se especifica también FAST_FORWARD o STATIC.
Especifica que las actualizaciones o eliminaciones posicionadas realizadas a través del cursor no se
realizarán correctamente si la fila se ha actualizado después de ser leída en el cursor. SQL Server no
bloquea las filas al leerlas en el cursor. En su lugar, utiliza comparaciones de valores de columna
timestamp o un valor de suma de comprobación si la tabla no tiene columnas timestamp, para
determinar si la fila se ha modificado después de leerla en el cursor. Si la fila se ha modificado, el
intento de actualización o eliminación posicionada genera un error. No es posible especificar
OPTIMISTIC si se especifica también FAST_FORWARD.
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
NOMBRE_PAIS,
ACTIVO,
FX_ALTA
FROM
PAISES
WHERE COD_PAIS = @codPais'