Unidad 3 De acuerdo a lo visto cmo

  • Slides: 107
Download presentation
Unidad 3

Unidad 3

 • De acuerdo a lo visto, cómo es la organización o estructura de

• De acuerdo a lo visto, cómo es la organización o estructura de un programa en el servidor de BD? • … • Organización de programa en bloques.

BLOQUE • CREATE… • • • AS DECLARE… … Sentencias SQL … cabecera cuerpo

BLOQUE • CREATE… • • • AS DECLARE… … Sentencias SQL … cabecera cuerpo se incluyen todos los elementos de definición del programa; como nombre, parámetros (entrada y/o salida), tipo de trigger, etc. se definen todos los elementos de desarrollo como declaración de variables y bloque de sentencias

BLOQUE • CREATE… • • • AS DECLARE… … Sentencias SQL … cabecera declaración

BLOQUE • CREATE… • • • AS DECLARE… … Sentencias SQL … cabecera declaración cuerpo ejecución

BLOQUE • CREATE… • • • AS DECLARE… … Sentencias SQL … cabecera declaración

BLOQUE • CREATE… • • • AS DECLARE… … Sentencias SQL … cabecera declaración ejecución excepciones cuerpo

 • Manejo de excepciones: control de errores. • PL/SQL usa bloque de exceptions.

• Manejo de excepciones: control de errores. • PL/SQL usa bloque de exceptions. DECLARE. . excep EXCEPTION; /* (2) */ BEGIN. . . IF. . . THEN RAISE excep; /* (2) */ END IF; . . . EXCEPTION WHEN TOO_MANY_ROWS THEN /* (1) */ sentencias_manejo_excepcion_sistema; WHEN excep THEN /* (2) */ sentencias_manejo_excepcion_usuario; WHEN OTHERS THEN. . . ; ; END;

 • SQL Server 2005 posee un mecanismo de manejo de excepciones en un

• SQL Server 2005 posee un mecanismo de manejo de excepciones en un formato de bloque TRY/CATCH: BEGIN TRY INSERT INTO Sales. Currency (Currency. Code, Name, Modified. Date ) VALUES('LAE', 'Pol', '01/06/2005') PRINT 'Inserción completada con exito. ' END TRY BEGIN CATCH PRINT 'Inserción fallida. ' END CATCH

BEGIN TRY DECLARE @divisor int , @dividendo int, @resultado int SET @dividendo = 100

BEGIN TRY DECLARE @divisor int , @dividendo int, @resultado int SET @dividendo = 100 SET @divisor = 0 -- Esta linea provoca un error de division por 0 SET @resultado = @dividendo/@divisor PRINT 'No hay error‘ END TRY BEGIN CATCH PRINT 'Se ha producido un error‘ END CATCH

 • SQL Server 2000 no maneja el TRY/CATCH. • Qué se ha usado

• SQL Server 2000 no maneja el TRY/CATCH. • Qué se ha usado para controlar errores? • IF ELSE…PRINT…RETURN

 • @@ERROR. Variable global de sistema. Almacena el número de error producido por

• @@ERROR. Variable global de sistema. Almacena el número de error producido por la última sentencia Transact SQL ejecutada. • Devuelve 0 si la última instrucción Transact-SQL se ejecutó con éxito. • Si la instrucción causó un error, devuelve el número de error. • El valor de @@ERROR cambia al finalizar cada instrucción Transact-SQL. • Qué se aconseja? • Guardar @@ERROR en una variable de tipo entero inmediatamente después de que se complete la instrucción Transact-SQL. El valor de la variable se puede usar posteriormente.

DECLARE @divisor int , @dividendo int , @resultado int SET @dividendo = 100 SET

DECLARE @divisor int , @dividendo int , @resultado int SET @dividendo = 100 SET @divisor = 0 /*se genera una division por 0 ->error*/ SET @resultado = @dividendo/@divisor IF @@ERROR = 0 PRINT 'No hay error' ELSE PRINT 'Error de division'

DECLARE @divisor int , @dividendo int , @resultado int SET @dividendo = 100 SET

DECLARE @divisor int , @dividendo int , @resultado int SET @dividendo = 100 SET @divisor = 0 /*se genera una division por 0 ->error*/ SET @resultado = @dividendo/@divisor /*esta linea vuelve a establecer @@error a 0*/ PRINT 'Controlando el error. . . ' IF @@ERROR = 0 PRINT 'No hay error' ELSE PRINT 'Error de division'

DECLARE @divisor int, @dividendo int , @resultado int declare @nu int SET @dividendo =

DECLARE @divisor int, @dividendo int , @resultado int declare @nu int SET @dividendo = 100 SET @divisor = 0 SET @resultado = @dividendo/@divisor set @nu=@@error print 'Controlando el error. . . ' IF @nu = 0 PRINT 'No hay error' ELSE PRINT 'Hay error: ' +cast(@nu as varchar)

 • En ocasiones es necesario provocar voluntariamente un error; nos puede interesar que

• En ocasiones es necesario provocar voluntariamente un error; nos puede interesar que se genere un error cuando los datos incumplen una regla de negocio. • Se puede provocar un error en tiempo de ejecución a través de la función RAISERROR.

 • Raiserror. Devuelve un mensaje de error definido por el usuario y establece

• Raiserror. Devuelve un mensaje de error definido por el usuario y establece un indicador del sistema para registrar que se ha producido un error; más eficaz que PRINT para devolver mensajes a las aplicaciones. • Sintaxis • RAISERROR ( { msg_id | msg_str } { , severity , state } [ , argument [ , . . . n ] ] ) [ WITH option [ , . . . n ] ]

 • msg_id. Número de mensaje de error definido por el usuario que está

• msg_id. Número de mensaje de error definido por el usuario que está almacenado en la tabla sysmessages. Deben ser mayores de 50. 000. • msg_str. Mensaje ad hoc con un formato similar al estilo de formato PRINT. . . Puede contener un máximo de 400 caracteres. Si el mensaje contiene más de 400 caracteres, solamente aparecerán los 397 primeros y se agregarán puntos suspensivos… • Severity. Nivel de gravedad definido por el usuario que se asocia con este mensaje. Todos los usuarios pueden utilizar los niveles de gravedad de 0 a 18. • State. Entero arbitrario entre 1 y 127 que representa información acerca del estado de llamada del error. Un valor negativo de state pasa a tener un valor predeterminado de 1. • VER RESTO DE CONFIGURACION

Create procedure chequearpersona 1 (@dni varchar(9)) as if exists (select * from persona where

Create procedure chequearpersona 1 (@dni varchar(9)) as if exists (select * from persona where dni=@dni) begin select nombre, apellido from persona where dni=@dni end else raiserror ('Valor pedido no existe', 16, 1) exec chequearpersona 1 '34343'

 • Es posible definir errores de usuario con el fin de poder reutilizarlos,

• Es posible definir errores de usuario con el fin de poder reutilizarlos, y así ofrecer un comportamiento homogéneo. • Esto puede realizarse a través del procedimiento almacenado del sistema sp_addmessage (especificando código de error, severidad, texto del error, e idioma). • Pueden consultarse los errores existentes en sysmessages.

 • EXEC sp_addmessage @msgnum = 50001, @severity = 16, @msgtext = 'No existe

• EXEC sp_addmessage @msgnum = 50001, @severity = 16, @msgtext = 'No existe elemento buscado', @lang = 'us_english‘ • SELECT * FROM master. dbo. sysmessages Create procedure chequearpersona 1 (@dni varchar(9)) as if exists (select * from persona where dni=@dni) begin select nombre, apellido from persona where dni=@dni end else raiserror (50001, 16, 1)

 • Apliquemos @@error y raiserror a algun procedimiento realizado anteriormente. • Que tipo

• Apliquemos @@error y raiserror a algun procedimiento realizado anteriormente. • Que tipo de problema podria ser? • Select? • Qué error podría surgir con un select? • Uso de @@rowcount

Create procedure chequearpersona (@dni varchar(9)) as if exists (select * from persona where dni=@dni)

Create procedure chequearpersona (@dni varchar(9)) as if exists (select * from persona where dni=@dni) begin select nombre, apellido from persona where dni=@dni end else print 'Persona no esta registrada'

Create procedure chequearpersona 6 (@dni varchar(9)) as select nombre, apellido from persona where dni=@dni

Create procedure chequearpersona 6 (@dni varchar(9)) as select nombre, apellido from persona where dni=@dni if @@rowcount=0 print 'Persona no esta registrada'

alter procedure chequearpersona 6 (@dni varchar(9)) as select nombre, apellido from persona where dni=@dni

alter procedure chequearpersona 6 (@dni varchar(9)) as select nombre, apellido from persona where dni=@dni if @@rowcount=0 raiserror ('Persona no esta registrada', 16, 1)

 • Insertar un registro de persona. • Puede surgir un error ?

• Insertar un registro de persona. • Puede surgir un error ?

Create procedure insertarpersona 5 (@DNI varchar(9), @nombre varchar(25), @apellido varchar(50), @ciudad varchar(25), @direccioncalle varchar(50),

Create procedure insertarpersona 5 (@DNI varchar(9), @nombre varchar(25), @apellido varchar(50), @ciudad varchar(25), @direccioncalle varchar(50), @direccionnum varchar(3), @telefono varchar(9), @fechanacimiento datetime, @varon char(1)) as insert into persona (DNI, Nombre, Apellido, Ciudad, Direccion. Calle, Direccion. Num, Telefono, Fecha. Nacimiento, Varon) values (@DNI, @Nombre, @APellido, @Ciudad, @Direccion. Calle, @Direccion. Num, @Telefono, @Fecha. Nacimiento, @Varon) if @@error<>0 print 'Hubo un error de insercion'

alter procedure insertarpersona 5 (@DNI varchar(9), @nombre varchar(25), @apellido varchar(50), @ciudad varchar(25), @direccioncalle varchar(50),

alter procedure insertarpersona 5 (@DNI varchar(9), @nombre varchar(25), @apellido varchar(50), @ciudad varchar(25), @direccioncalle varchar(50), @direccionnum varchar(3), @telefono varchar(9), @fechanacimiento datetime, @varon char(1)) as declare @nu int insert into persona (DNI, Nombre, Apellido, Ciudad, Direccion. Calle, Direccion. Num, Telefono, Fecha. Nacimiento, Varon) values (@DNI, @Nombre, @APellido, @Ciudad, @Direccion. Calle, @Direccion. Num, @Telefono, @Fecha. Nacimiento, @Varon) set @nu=@@error if @nu=2627 print 'No se aceptan claves duplicadas. No se pudo insertar persona. ' else if @nu=547 print 'Conflicto con restricciones tipo check en insercion. No se pudo insertar persona. ' if @nu=0 print 'Insercion realizada correctamente'

alter procedure insertarpersona 5 (@DNI varchar(9), @nombre varchar(25), @apellido varchar(50), @ciudad varchar(25), @direccioncalle varchar(50),

alter procedure insertarpersona 5 (@DNI varchar(9), @nombre varchar(25), @apellido varchar(50), @ciudad varchar(25), @direccioncalle varchar(50), @direccionnum varchar(3), @telefono varchar(9), @fechanacimiento datetime, @varon char(1)) as declare @nu int insert into persona (DNI, Nombre, Apellido, Ciudad, Direccion. Calle, Direccion. Num, Telefono, Fecha. Nacimiento, Varon) values (@DNI, @Nombre, @APellido, @Ciudad, @Direccion. Calle, @Direccion. Num, @Telefono, @Fecha. Nacimiento, @Varon) set @nu=@@error if @nu=2627 raiserror ('No se aceptan claves duplicadas', 16, 1) else if @nu=547 raiserror ('Conflicto con restricciones tipo check en insercion', 16, 1) if @nu=0 print 'Insercion realizada correctamente'

 • Hacer lo mismo con el siguiente PA (actualiza id de una titulacion)

• Hacer lo mismo con el siguiente PA (actualiza id de una titulacion) create PROCEDURE updatetitulacion 1 (@idtitantiguo numeric(6), @idtitnuevo numeric(6)) AS if (select count(*) from titulacion where idtitulacion=@idtitantiguo)=1 begin if (select count(*) from titulacion where idtitulacion=@idtitnuevo)=0 begin update titulacion set idtitulacion=@idtitnuevo where idtitulacion=@idtitantiguo return 0 end else return 2 end else return 1

create PROCEDURE updatetitulacion 5 (@idtitantiguo numeric(6), @idtitnuevo numeric(6)) AS update titulacion set idtitulacion=@idtitnuevo where

create PROCEDURE updatetitulacion 5 (@idtitantiguo numeric(6), @idtitnuevo numeric(6)) AS update titulacion set idtitulacion=@idtitnuevo where idtitulacion=@idtitantiguo if @@error<>0 print 'Hubo un error. . . ' else if @@error=0 print 'todo bien'

alter PROCEDURE updatetitulacion 5 (@idtitantiguo numeric(6), @idtitnuevo numeric(6)) AS update titulacion set idtitulacion=@idtitnuevo where

alter PROCEDURE updatetitulacion 5 (@idtitantiguo numeric(6), @idtitnuevo numeric(6)) AS update titulacion set idtitulacion=@idtitnuevo where idtitulacion=@idtitantiguo if @@error<>0 print 'Hubo un error. . . ' else if @@error=0 print 'todo bien' if @@rowcount=0 print 'no se encontro titulacion'

 • Uso de INTO en SELECT • Into en select…

• Uso de INTO en SELECT • Into en select…

 • INTO (en SELECT). La cláusula INTO habilita para especificar que el conjunto

• INTO (en SELECT). La cláusula INTO habilita para especificar que el conjunto de resultados se utilizará para crear una tabla nueva con el nombre definido en la cláusula: Crea una nueva tabla e inserta en ella las filas resultantes… • Se suele utilizar para crear tablas de trabajo, o tablas intermedias; se crean para una determinada tarea y luego se borran. • Se puede utilizar para crear una copia de seguridad de la tabla. • Sintaxis. • INTO new_table

SELECT * INTO new_table_name FROM old_tablename SELECT column_name(s) INTO new_table_name FROM old_tablename En BD

SELECT * INTO new_table_name FROM old_tablename SELECT column_name(s) INTO new_table_name FROM old_tablename En BD Universidad: select * into copia from persona

select Nombre, Apellido into copia 1 from persona Where ciudad=‘Concepcion’ select Asignatura. Nombre as

select Nombre, Apellido into copia 1 from persona Where ciudad=‘Concepcion’ select Asignatura. Nombre as asig, persona. nombre, persona. apellido into copia 2 from asignatura, profesor, persona Where asignatura. idprofesor=profesor. idprofesor and profesor. dni=persona. dni

 • No confundir con… • INSERT INTO…SELECT: • Inserción multiple de filas. •

• No confundir con… • INSERT INTO…SELECT: • Inserción multiple de filas. • La sentencia INSERT permite tambien insertar varios registros en una tabla. • Pare ello se utiliza una combinación de la sentencia INSERT junto a una sentencia SELECT. • El resultado es que se insertan todos los registros devueltos por la consulta.

 • Sintaxis. • INSERT INTO <nombre_tabla> [(<campo 1>[, <campo 2>, . . .

• Sintaxis. • INSERT INTO <nombre_tabla> [(<campo 1>[, <campo 2>, . . . ])] SELECT [(<campo 1>[, <campo 2>, . . . ])] FROM <nombre_tabla_origen>; • Se deben cumplir las siguientes normas: • La lista de campos de las sentencias insert y select deben coincidir en número y tipo de datos. • Ninguna de las filas devueltas por la consulta debe infringir las reglas de integridad de la tabla en la que vayamos a realizar la inserción.

create table ciudades (id int identity (1, 1) primary key, ciudad varchar (30)) insert

create table ciudades (id int identity (1, 1) primary key, ciudad varchar (30)) insert into ciudades (ciudad) select distinct ciudad from persona

 • Hacer un PA para la tabla persona, con parametro de entrada (ciudad)

• Hacer un PA para la tabla persona, con parametro de entrada (ciudad) que realice un select de todas las personas de esas ciudad, y genere una copia de seguridad con esos datos.

create procedure chequearpersonaycopiar (@ciudad varchar(25)) as if exists (select * from persona where ciudad=@ciudad)

create procedure chequearpersonaycopiar (@ciudad varchar(25)) as if exists (select * from persona where ciudad=@ciudad) Begin select * from persona where ciudad=@ciudad select * into copiapersonaciudad from persona where ciudad=@ciudad end else print 'Persona no esta registrada'

 • Modificar PA usando @@error o @rowcount, raiserror

• Modificar PA usando @@error o @rowcount, raiserror

alter procedure chequearpersonaycopiar (@ciudad varchar(25)) as select * from persona where ciudad=@ciudad select *

alter procedure chequearpersonaycopiar (@ciudad varchar(25)) as select * from persona where ciudad=@ciudad select * into copiapersonaciudad from persona where ciudad=@ciudad if @@rowcount=0 raiserror ('No hay registros de personas en esa ciudad, no se pudo generar copia', 16, 1) else print ('Copia generada')

alter procedure chequearpersonaycopiar (@ciudad varchar(25)) as IF EXISTS (SELECT name FROM sysobjects WHERE name

alter procedure chequearpersonaycopiar (@ciudad varchar(25)) as IF EXISTS (SELECT name FROM sysobjects WHERE name = 'copiapersonaciudad' AND xtype = 'U') drop table copiapersonaciudad else Begin select * from persona where ciudad=@ciudad select * into copiapersonaciudad from persona where ciudad=@ciudad if @@rowcount=0 raiserror ('No hay registros de personas en esa ciudad, no se pudo generar copia', 16, 1) else print ('Copia generada') end

 • Cursores

• Cursores

 • Cursor. Variable que permite recorrer un conjunto de resultados obtenidos a través

• Cursor. Variable que permite recorrer un conjunto de resultados obtenidos a través de un SELECT fila a fila: permiten situarse en filas específicas del conjunto de resultados. • Recuperan una fila o bloque de filas. • Aceptan modificaciones de los datos de las filas en la posición actual del conjunto de resultados • En qué se podrían relacionar los SELECT INTO e INSERT INTO SELECT con cursores?

 • Para trabajar con cursores se deben seguir los siguientes pasos: • Declarar

• Para trabajar con cursores se deben 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

 • Sintaxis General • • -- Declaración del cursor DECLARE <nombre_cursor> CURSOR FOR

• Sintaxis General • • -- Declaración del cursor DECLARE <nombre_cursor> CURSOR FOR <sentencia_sql> • • -- apertura del cursor OPEN <nombre_cursor> • • -- Lectura de la primera fila del cursor FETCH <nombre_cursor> INTO <lista_variables> • • • 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>

 • @@FETCH_STATUS. Variable global. Devuelve el estado de la última instrucción FETCH de

• @@FETCH_STATUS. Variable global. Devuelve el estado de la última instrucción FETCH de cursor ejecutada.

 • Ejemplo. Abrir un cursor y recorrerlo: DECLARE persona_Cursor CURSOR FOR SELECT Nombre,

• Ejemplo. Abrir un cursor y recorrerlo: DECLARE persona_Cursor CURSOR FOR SELECT Nombre, Apellido, Ciudad FROM persona WHERE varon=1 OPEN persona_Cursor FETCH NEXT FROM persona_Cursor WHILE @@FETCH_STATUS = 0 BEGIN FETCH NEXT FROM persona_Cursor END CLOSE persona_Cursor DEALLOCATE persona_Cursor

 • Ejemplo. Abrir un cursor, recorrerlo e imprimir: DECLARE @nombre varchar(20) DECLARE @apellido

• Ejemplo. Abrir un cursor, recorrerlo e imprimir: DECLARE @nombre varchar(20) DECLARE @apellido varchar(20) DECLARE @ciudad varchar(20) DECLARE persona_Cursor CURSOR FOR SELECT Nombre, Apellido, Ciudad FROM persona WHERE varon=1 ORDER BY Apellido, Nombre OPEN persona_Cursor FETCH NEXT FROM persona_Cursor INTO @nombre, @apellido, @ciudad WHILE @@FETCH_STATUS = 0 BEGIN PRINT +@nombre +' '+@apellido +' vive en '+@ciudad FETCH NEXT FROM persona_Cursor INTO @nombre, @apellido, @ciudad END CLOSE persona_Cursor DEALLOCATE persona_Cursor

 • Ejemplo. Abrir un cursor, recorrerlo y actualizar: DECLARE @nombre varchar(20) DECLARE @creditos

• Ejemplo. Abrir un cursor, recorrerlo y actualizar: DECLARE @nombre varchar(20) DECLARE @creditos float DECLARE @coste float DECLARE asig_Cursor CURSOR FOR SELECT Nombre, creditos, costebasico FROM asignatura OPEN asig_Cursor FETCH NEXT FROM asig_Cursor into @nombre, @creditos, @coste WHILE @@FETCH_STATUS = 0 BEGIN update asignatura set costebasico=@coste+@creditos*4 where nombre=@nombre FETCH NEXT FROM asig_Cursor into @nombre, @creditos, @coste END CLOSE asig_Cursor DEALLOCATE asig_Cursor

 • Ejecutar el siguiente cursor • Que hace?

• Ejecutar el siguiente cursor • Que hace?

SET NOCOUNT ON DECLARE @nom varchar(20), @cont varchar(30), @message varchar (80), @nombp varchar (20)

SET NOCOUNT ON DECLARE @nom varchar(20), @cont varchar(30), @message varchar (80), @nombp varchar (20) PRINT '---- proveedores almacen kollao----' DECLARE proov_cursor CURSOR FOR SELECT nombre, nombre_contacto FROM proveedor OPEN proov_cursor FETCH NEXT FROM proov_cursor INTO @nom, @cont WHILE @@FETCH_STATUS = 0 BEGIN PRINT ' ' SELECT @message = '----- productos por proveedor: ' + @nom + ' , ' + @cont PRINT @message DECLARE prod_cursor CURSOR FOR SELECT nombre_fantasia FROM proveedor, producto WHERE producto. proveedor=proveedor. codigo_proveedor and proveedor. nombre=@nom OPEN prod_cursor FETCH NEXT FROM prod_cursor INTO @nombp IF @@FETCH_STATUS <> 0 PRINT ' <<No productos>>' WHILE @@FETCH_STATUS = 0 BEGIN SELECT @message = ' ' + @nombp PRINT @message FETCH NEXT FROM prod_cursor INTO @nombp END CLOSE prod_cursor DEALLOCATE prod_cursor FETCH NEXT FROM proov_cursor INTO @nom, @cont END CLOSE proov_cursor DEALLOCATE proov_cursor

 • /* Este cursor deja las contraseñas iguales al nombre de usuario. La

• /* Este cursor deja las contraseñas iguales al nombre de usuario. La tabla Cliente tiene estos tres campos: Cli. Cod, Cli. User, Cli. Pass */ -- declaramos las variables declare @cod as int declare @user as varchar(50) declare @pass as varchar(50) • -- declaramos un cursor llamado "CURSORITO". declare CURSORITO cursor for select Cli. Cod, Cli. User, Cli. Pass from Cliente • open CURSORITO -- Avanzamos un registro y cargamos en las variables los valores encontrados en el primer registro • fetch next from CURSORITO into @cod, @user, @pass while @@fetch_status = 0 begin update Cliente set Cli. Pass= @user where Cli. Cod=@cod -- Avanzamos otro registro fetch next from CURSORITO into @cod, @user, @pass end -- cerramos el cursor close CURSORITO deallocate CURSORITO

 • Generar un PA que a traves de un cursor, imprima el nombre,

• Generar un PA que a traves de un cursor, imprima el nombre, creditos y cuatrimestre de las asignaturas registradas.

create procedure asignaturacusor as DECLARE @nombre varchar(20) DECLARE @creditos float DECLARE @cuatri int DECLARE

create procedure asignaturacusor as DECLARE @nombre varchar(20) DECLARE @creditos float DECLARE @cuatri int DECLARE asignatura_Cursor CURSOR FOR SELECT Nombre, creditos, cuatrimestre FROM asignatura OPEN asignatura_Cursor FETCH NEXT FROM asignatura_Cursor INTO @nombre, @creditos, @cuatri WHILE @@FETCH_STATUS = 0 BEGIN PRINT 'Asignatura ' +@nombre +' corresponde a cuatrimestre ' +cast(@cuatri as varchar)+' y tiene '+cast(@creditos as varchar) +' creditos' FETCH NEXT FROM asignatura_Cursor INTO @nombre, @creditos, @cuatri END CLOSE asignatura_Cursor DEALLOCATE asignatura_Cursor exec asignaturacusor

 • Generar un PA que a traves de un cursor, imprima el nombre,

• Generar un PA que a traves de un cursor, imprima el nombre, creditos y cuatrimestre de ciertas asignaturas registradas, de acuerdo a parametro de entrada (cuatrimestre).

create procedure asignaturacusorotro (@cuatr int) as DECLARE @nombre varchar(20) DECLARE @creditos float DECLARE @cuatri

create procedure asignaturacusorotro (@cuatr int) as DECLARE @nombre varchar(20) DECLARE @creditos float DECLARE @cuatri int DECLARE asignatura_Cursor CURSOR FOR SELECT Nombre, creditos, cuatrimestre FROM asignatura where cuatrimestre=@cuatr OPEN asignatura_Cursor FETCH NEXT FROM asignatura_Cursor INTO @nombre, @creditos, @cuatri WHILE @@FETCH_STATUS = 0 BEGIN PRINT 'Asignatura ' +@nombre +' corresponde a cuatrimestre ' +cast(@cuatri as varchar)+' y tiene '+cast(@creditos as varchar) +' creditos' FETCH NEXT FROM asignatura_Cursor INTO @nombre, @creditos, @cuatri END CLOSE asignatura_Cursor DEALLOCATE asignatura_Cursor

alter procedure asignaturacusorotro (@cuatr int) as DECLARE @nombre varchar(20) DECLARE @creditos float DECLARE @cuatri

alter procedure asignaturacusorotro (@cuatr int) as DECLARE @nombre varchar(20) DECLARE @creditos float DECLARE @cuatri int DECLARE asignatura_Cursor CURSOR FOR SELECT Nombre, creditos, cuatrimestre FROM asignatura where cuatrimestre=@cuatr OPEN asignatura_Cursor FETCH NEXT FROM asignatura_Cursor INTO @nombre, @creditos, @cuatri if @@fetch_status<>0 print 'No hay registros' WHILE @@FETCH_STATUS = 0 BEGIN PRINT 'Asignatura ' +@nombre +' corresponde a cuatrimestre ' +cast(@cuatri as varchar)+' y tiene '+cast(@creditos as varchar) +' creditos' FETCH NEXT FROM asignatura_Cursor INTO @nombre, @creditos, @cuatri END CLOSE asignatura_Cursor DEALLOCATE asignatura_Cursor

 • Cursores con parametros. • Al declarar un cursor podemos definir: • DECLARE

• Cursores con parametros. • Al declarar un cursor podemos definir: • DECLARE <nombre_cursor> CURSOR [ LOCAL | GLOBAL ] • [ FORWARD_ONLY | SCROLL ] [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] [ TYPE_WARNING ] FOR <sentencia_sql> INVESTIGAR • • [ LOCAL | GLOBAL ] [ FORWARD_ONLY | SCROLL ] [ STATIC | DYNAMIC | FAST_FORWARD ] [ READ_ONLY]

 • [ LOCAL | GLOBAL ]. • • • LOCAL. Especifica que el

• [ LOCAL | GLOBAL ]. • • • LOCAL. Especifica que el ámbito del cursor es local para el proceso por lotes, procedimiento almacenado o trigger en que se creó el cursor. DECLARE c. Clientes CURSOR LOCAL FOR SELECT … 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 c. Clientes CURSOR GLOBAL FOR SELECT… • Si no se especifica GLOBAL ni LOCAL, el valor predeterminado es local.

 • [ FORWARD_ONLY | SCROLL ] • FORWARD_ONLY. Especifica que el cursor sólo

• [ FORWARD_ONLY | SCROLL ] • FORWARD_ONLY. 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. • • DECLARE c. Clientes CURSOR FORWARD_ONLY FOR SELECT … • 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. 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 • •

-- Declaracion de variables para el cursor DECLARE @Id int, @Nombre varchar(255), @Apellido 1

-- Declaracion de variables para el cursor DECLARE @Id int, @Nombre varchar(255), @Apellido 1 varchar(255), @Apellido 2 varchar(255), @Nif. Cif varchar(20), @Fx. Nacimiento datetime -- Declaración del cursor DECLARE c. Clientes CURSOR SCROLL FOR SELECT Id, Nombre, Apellido 1, Apellido 2, Nif. Cif, Fx. Nacimiento FROM CLIENTES -- Apertura del cursor OPEN c. Clientes -- Lectura de la primera fila del cursor FETCH NEXT FROM c. Clientes INTO @id, @Nombre, @Apellido 1, @Apellido 2, @Nif. Cif, @Fx. Nacimiento WHILE (@@FETCH_STATUS = 0 ) BEGIN PRINT @Nombre + ' ' + @Apellido 1 + ' ' + @Apellido 2 -- Lectura de la siguiente fila del cursor FETCH NEXT FROM c. Clientes INTO @id, @Nombre, @Apellido 1, @Apellido 2, @Nif. Cif, @Fx. Nacimiento END -- Lectura de la fila anterior FETCH PRIOR FROM c. Clientes INTO @id, @Nombre, @Apellido 1, @Apellido 2, @Nif. Cif, @Fx. Nacimiento PRINT @Nombre + ' ' + @Apellido 1 + ' ' + @Apellido 2 -- Cierre del cursor CLOSE c. Clientes -- Liberar los recursos DEALLOCATE c. Clientes

 • [ STATIC | DYNAMIC | FAST_FORWARD ]. • • • STATIC. Define

• [ STATIC | DYNAMIC | FAST_FORWARD ]. • • • 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; las modificaciones realizadas en las tablas base no se reflejan en los datos devueltos por las operaciones de recuperación realizadas en el cursor. No admite modificaciones. DECLARE c. Clientes CURSOR STATIC FOR DYNAMIC. Define un cursor que, al desplazarse por él, refleja en su conjunto de resultados todos los cambios realizados en los datos de las filas. DECLARE c. Clientes CURSOR DYNAMIC FOR FAST_FORWARD. Especifica un cursor FORWARD_ONLY, READ_ONLY. No se puede especificar FAST_FORWARD si se especifica también SCROLL o FOR_UPDATE. DECLARE c. Clientes CURSOR FAST_FORWARD FOR

 • [ READ_ONLY ]. • READ_ONLY. Evita que se efectúen actualizaciones a través

• [ READ_ONLY ]. • READ_ONLY. Evita que se efectúen actualizaciones a través de este cursor. • DECLARE c. Clientes CURSOR READ_ONLY FOR

 • Triggers-Disparadores

• Triggers-Disparadores

 • Clase especial de procedimiento almacenado que se ejecuta automáticamente (se “dispara”) cuando

• Clase especial de procedimiento almacenado que se ejecuta automáticamente (se “dispara”) cuando se produce un evento en el servidor de bases de datos. • Se ejecuta siempre que se intenta modificar los datos de una tabla que el trigger protege: realizar un INSERT, UPDATE o DELETE…dependiendo de la accion especificada. • No es posible evitar su ejecución. • Los triggers se definen para una tabla específica, denominada tabla del trigger.

 • No es posible invocar directamente los triggers, que tampoco pasan ni aceptan

• No es posible invocar directamente los triggers, que tampoco pasan ni aceptan parámetros. • Gran herramienta para controlar reglas de negocio más complejas que una simple integridad referencial. • Ojo: el usuario no espera que el trigger le devuelva registros luego de agregar o modificar información.

 • Sintaxis. CREATE trigger <Nombre del trigger> ON <Nombre de la Tabla> FOR

• Sintaxis. CREATE trigger <Nombre del trigger> ON <Nombre de la Tabla> FOR <INSERT l UPDATE l DELETE> AS Sentencias….

 • Un trigger para inserción de registros genera automáticamente una tabla en el

• Un trigger para inserción de registros genera automáticamente una tabla en el cache con la información que intenta añadir, esta tabla se denomina INSERTED y es a través de esta tabla que se pueden hacer comparaciones en otras tablas. • Un trigger para eliminación de registros genera automáticamente una tabla en el cache con la información que intenta eliminar, esta tabla se denomina DELETED y es a través de esta tabla que se pueden hacer comparaciones en otras tablas. • Si se trata de un trigger para actualización se generan ambas tablas INSERTED con los nuevos datos y DELETED con la información que será reemplazada.

 • Un trigger se "dispara" sólo cuando la instrucción de modificación de datos

• Un trigger se "dispara" sólo cuando la instrucción de modificación de datos finaliza. • SQL Server verifica la posible violación de tipos de datos, reglas o restricciones de integridad. • El trigger y la instrucción que lo "dispara" se consideran una sola transacción que puede revertirse desde dentro del disparador. • Si se detecta un error grave, se revierte toda la transacción.

create TRIGGER reminder ON persona FOR INSERT, UPDATE AS PRINT 'Se está intentando modificar

create TRIGGER reminder ON persona FOR INSERT, UPDATE AS PRINT 'Se está intentando modificar datos‘ /*RAISERROR. . . */ Generar trigger e intentar insertar o actualizar un registro. . .

 • INSERT • Aplicar reglas de negocio…? ? ?

• INSERT • Aplicar reglas de negocio…? ? ?

 • Las personas que se registren en almacenes Kollao como clientes deben ser

• Las personas que se registren en almacenes Kollao como clientes deben ser mayores de 18 años. • Como seria un trigger que verifique esto?

create trigger insertclienteedad on cliente for insert as declare @fecha datetime select @fecha= fecha_nacimiento

create trigger insertclienteedad on cliente for insert as declare @fecha datetime select @fecha= fecha_nacimiento from inserted if (datediff(yy, @fecha, getdate()))<18 begin raiserror (‘No se aceptan clientes menores de 18 años', 16, 1) end else print ‘Se inserto cliente exitosamente'

 • El cliente se registra de todas maneras… • Qué hacer para evitar

• El cliente se registra de todas maneras… • Qué hacer para evitar esto?

create trigger insertclienteedad on cliente for insert as declare @fecha datetime select @fecha= fecha_nacimiento

create trigger insertclienteedad on cliente for insert as declare @fecha datetime select @fecha= fecha_nacimiento from inserted if (datediff(yy, @fecha, getdate()))<18 begin raiserror (‘No se aceptan clientes menores de 18 años', 16, 1) rollback transaction /*deshace la transaccion*/ end else print ' Se inserto cliente exitosamente '

 • Se puede entonces: • Generar un PA simple para insercion en cliente…

• Se puede entonces: • Generar un PA simple para insercion en cliente… • Generar un PA para insercion que tome en cuenta reglas de integridad … • Generar un trigger para la insercion en cliente que tome en cuenta la regla de negocio.

create PROCEDURE insert_cliente (@rut_cliente_1 [varchar](10), @primer_nombre_2 [varchar](15), @segundo_nombre_3 [varchar](15), @primer_apellido_4 [varchar](15), @segundo_apellido_5 [varchar](15), @calle_6

create PROCEDURE insert_cliente (@rut_cliente_1 [varchar](10), @primer_nombre_2 [varchar](15), @segundo_nombre_3 [varchar](15), @primer_apellido_4 [varchar](15), @segundo_apellido_5 [varchar](15), @calle_6 [varchar](20), @numero_7 [varchar](3), @ciudad_8 [varchar](15), @mail_9 [varchar](30), @fecha_nacimiento_10 [smalldatetime], @Sexo_11 [char](1)) AS if not exists(select * from cliente where rut_cliente=@rut_cliente_1) INSERT INTO [empresa]. [dbo]. [cliente] ( [rut_cliente], [primer_nombre], [segundo_nombre], [primer_apellido], [segundo_apellido], [calle], [numero], [ciudad], [mail], [fecha_nacimiento], [Sexo]) VALUES ( @rut_cliente_1, @primer_nombre_2, @segundo_nombre_3, @primer_apellido_4, @segundo_apellido_5, @calle_6, @numero_7, @ciudad_8, @mail_9, @fecha_nacimiento_10, @Sexo_11) else raiserror('No se puede ingresar cliente, rut esta actualmente en uso', 16, 1)

create PROCEDURE insert_cliente 1 (@rut_cliente_1 [varchar](10), @primer_nombre_2 [varchar](15), @segundo_nombre_3 [varchar](15), @primer_apellido_4 [varchar](15), @segundo_apellido_5 [varchar](15),

create PROCEDURE insert_cliente 1 (@rut_cliente_1 [varchar](10), @primer_nombre_2 [varchar](15), @segundo_nombre_3 [varchar](15), @primer_apellido_4 [varchar](15), @segundo_apellido_5 [varchar](15), @calle_6 [varchar](20), @numero_7 [varchar](3), @ciudad_8 [varchar](15), @mail_9 [varchar](30), @fecha_nacimiento_10 [smalldatetime], @Sexo_11 [char](1)) AS INSERT INTO [empresa]. [dbo]. [cliente] ( [rut_cliente], [primer_nombre], [segundo_nombre], [primer_apellido], [segundo_apellido], [calle], [numero], [ciudad], [mail], [fecha_nacimiento], [Sexo]) VALUES ( @rut_cliente_1, @primer_nombre_2, @segundo_nombre_3, @primer_apellido_4, @segundo_apellido_5, @calle_6, @numero_7, @ciudad_8, @mail_9, @fecha_nacimiento_10, @Sexo_11) if @@rowcount=0 raiserror('No se pudo realizar el registro de cliente', 16, 1)

 • Hacer pruebas. . . • exec insert_cliente '037722227’, 'Loreto', 'Lagos', 'Jeria', 'Heras',

• Hacer pruebas. . . • exec insert_cliente '037722227’, 'Loreto', 'Lagos', 'Jeria', 'Heras', '345', 'Co ncepcion', 'jp@hotmail. com', '23 -5 -1980', 'f‘ • …

 • TAREA 29 -6 (con nota)-hecho. • Se necesita insertar un producto cuya

• TAREA 29 -6 (con nota)-hecho. • Se necesita insertar un producto cuya fecha de vencimiento sea minimo en 15 dias despues del registro. Si no es asi, no se debe realizar la insercion. • Generar PA de insercion en producto que tome en cuenta integridad referencial (pk y fk). • Regla de negocio la manejara trigger. • Hacer pruebas.

create PROCEDURE [insert_producto_1] (@codigo_producto_1 [varchar](8), @nombre_fantasia_2 [varchar](20), @marca_3 [varchar](15), @detalle_4 [varchar](100), @precio_5 [money], @fecha_vencimiento_6

create PROCEDURE [insert_producto_1] (@codigo_producto_1 [varchar](8), @nombre_fantasia_2 [varchar](20), @marca_3 [varchar](15), @detalle_4 [varchar](100), @precio_5 [money], @fecha_vencimiento_6 [smalldatetime], @proveedor_7 [varchar](6), @stock_8 [int]) AS if not exists(select * from producto where codigo_producto=@codigo_producto_1) begin if exists (select * from proveedor where codigo_proveedor=@proveedor_7) begin INSERT INTO producto VALUES ( @codigo_producto_1, @nombre_fantasia_2, @marca_3, @detalle_4, @precio_5, @fecha_vencimiento_6, @proveedor_7, @stock_8) end else raiserror ('Proveedor no esta registrado, no se puede registrar producto', 16, 1) end else raiserror ('Codigo de producto ya existe, no se puede registrar producto', 16, 1)

create trigger insertproducto on producto for insert as declare @fecha datetime select @fecha= fecha_vencimiento

create trigger insertproducto on producto for insert as declare @fecha datetime select @fecha= fecha_vencimiento from inserted if (datediff(dd, getdate(), @fecha))<15 begin raiserror ('No se aceptan productos con esa fecha de vencimiento', 16, 1) rollback transaction end else print ‘La fecha de vencimiento es válida, se realizo registro' insert into producto values ('ere 45434', 'pañuelos', 'elite', 'dfsfdfd', 640, ‘ 12 -72011', 'JG 6543', 5)

 • Ejercicio-hecho. • Se necesita insertar un producto nuevo. Si su stock es

• Ejercicio-hecho. • Se necesita insertar un producto nuevo. Si su stock es menor que 10, no se debe realizar la insercion. • PA de insercion ya esta creado. *** • Generar trigger. • Hacer pruebas.

create trigger insertproductostock on producto for insert as if (select stock from inserted)<10 begin

create trigger insertproductostock on producto for insert as if (select stock from inserted)<10 begin raiserror ('No se aceptan productos con tan poco stock', 16, 1) rollback transaction end else print ‘Stock valido'

 • Ejercicio con nota-hecho. • El almacen solo maneja 5 productos por proveedor

• Ejercicio con nota-hecho. • El almacen solo maneja 5 productos por proveedor registrado en la BD. No se debe poder insertar un nuevo producto si no se cumple esta regla. • PA de insercion creado. *** • Generar trigger. • Hacer pruebas.

create trigger insertproductoproveedor on producto for insert as if (select count(*) from producto, inserted

create trigger insertproductoproveedor on producto for insert as if (select count(*) from producto, inserted where producto. proveedor=inserted. proveedor)=6 begin raiserror ('Solo se aceptan 5 productos por proveedor', 16, 1) rollback transaction end else print ‘Proveedor con cantidad de productos ok'

 • Veamos que pasa con Update.

• Veamos que pasa con Update.

 • Al modificar algun dato de sucursal, se debe manejar un respaldo de

• Al modificar algun dato de sucursal, se debe manejar un respaldo de estos datos (los antiguos), incluida fecha y usuario que genero la modificacion. • Cómo sería? • Generar PA para modificacion de sucursal (direccion, telefono) tomando en cuenta integridad (pk, fk)

create table auditsuc (nr int identity (1, 1) primary key, cod varchar(6), dir varchar

create table auditsuc (nr int identity (1, 1) primary key, cod varchar(6), dir varchar (50), tel varchar (12), fecha datetime, usuario varchar(10))

create trigger modsucursal on sucursal for update as declare @cod varchar(6), @dir varchar (50),

create trigger modsucursal on sucursal for update as declare @cod varchar(6), @dir varchar (50), @tel varchar(12) select @cod=(select codigo_sucursal from deleted) select @dir=(select direccion from deleted) select @tel=(select telefono_sucursal from deleted) insert into auditsuc (cod, dir, tel, fecha, usuario) values(@cod, @dir, @tel, getdate(), user)

 • @@rowcount. Variable global. Guarda el numero de filas afectadas por la ultima

• @@rowcount. Variable global. Guarda el numero de filas afectadas por la ultima instrucción.

 • De acuerdo a las reglas de negocio, no se pueden actualizar varios

• De acuerdo a las reglas de negocio, no se pueden actualizar varios registros de sucursales a la vez. • Usando @@rowcount…como seria un trigger que verifique esto?

alter trigger modsucursal on sucursal for update as if @@rowcount=1 begin declare @cod varchar(6),

alter trigger modsucursal on sucursal for update as if @@rowcount=1 begin declare @cod varchar(6), @dir varchar (50), @tel varchar(12) select @cod=(select codigo_sucursal from deleted) select @dir=(select direccion from deleted) select @tel=(select telefono_sucursal from deleted) insert into auditsuc (cod, dir, tel, fecha, usuario) values(@cod, @dir, @tel, getdate(), user) end else raiserror(‘No se pueden realizar actualizaciones de varias filas', 16, 1) rollback transaction

 • On UPDATE en una fila especifica…

• On UPDATE en una fila especifica…

 • Se debe generar copia del dato actualizado, fecha y usuario que lo

• Se debe generar copia del dato actualizado, fecha y usuario que lo realizo. • Se actualiza telefono de sucursal. • Generar PA de actualizacion de telefono sucursal (a traves de codigo). • Generar trigger.

create table auditsuc 1 (nr int identity (1, 1) primary key, cod varchar(6), tel

create table auditsuc 1 (nr int identity (1, 1) primary key, cod varchar(6), tel varchar (12), fecha datetime, usuario varchar(10)) create trigger modsucursaltel on sucursal for update as if update(telefono_sucursal) begin declare @cod varchar(6), @tel varchar(12) select @cod=(select codigo_sucursal from deleted) select @tel=(select telefono_sucursal from deleted) insert into auditsuc 1 (cod, tel, fecha, usuario) values(@cod, @tel, getdate(), user) end

 • ON DELETE.

• ON DELETE.

 • Al eliminarse un proveedor, se debe manejar un respaldo de los datos

• Al eliminarse un proveedor, se debe manejar un respaldo de los datos eliminados.

create table auditproveedor (nr int identity (1, 1) primary key, cod varchar(6), nom varchar

create table auditproveedor (nr int identity (1, 1) primary key, cod varchar(6), nom varchar (20), contacto varchar (30), tel varchar (12), fecha datetime, usuario varchar(10))

create trigger delproveedor on proveedor for delete as declare @cod varchar(6), @nom varchar (20),

create trigger delproveedor on proveedor for delete as declare @cod varchar(6), @nom varchar (20), @contacto varchar (30), @tel varchar(12) select @cod=(select codigo_proveedor from deleted) select @nom=(select nombre from deleted) select @contacto=(select nombre_contacto from deleted) select @tel=(select telefono_contacto from deleted) insert into auditproveedor (cod, nom, contacto, tel , fecha, usuario) values(@cod, @nom, @contacto, @tel, getdate(), user)

 • No se puede borrar mas de un proveedor a la vez!!!

• No se puede borrar mas de un proveedor a la vez!!!

create trigger delproveedor on proveedor for delete as declare @cod varchar(6), @nom varchar (20),

create trigger delproveedor on proveedor for delete as declare @cod varchar(6), @nom varchar (20), @contacto varchar (30), @tel varchar(12) If @@rowcount=1 begin select @cod=(select codigo_proveedor from deleted) select @nom=(select nombre from deleted) select @contacto=(select nombre_contacto from deleted) select @tel=(select telefono_contacto from deleted) insert into auditproveedor (cod, nom, contacto, tel , fecha, usuario) values(@cod, @nom, @contacto, @tel, getdate(), user) end Else Raiserror (‘No se puede eliminar mas de un proveedor a la vez’, 16, 1) rollback transaction

create trigger delproveedor 1 on proveedor for delete as IF (SELECT COUNT(*) FROM Deleted)

create trigger delproveedor 1 on proveedor for delete as IF (SELECT COUNT(*) FROM Deleted) > 1 BEGIN RAISERROR(‘No puede borrar más de un proveedor al mismo tiempo. ’, 16, 1) ROLLBACK TRANSACTION END

create trigger delproveedor 1 on proveedor for delete as IF @@rowcount > 1 BEGIN

create trigger delproveedor 1 on proveedor for delete as IF @@rowcount > 1 BEGIN RAISERROR(‘No puede borrar más de un proveedor al mismo tiempo. ’, 16, 1) ROLLBACK TRANSACTION END

 • Conocer triggers creados: • select * from sysobjects where type = ‘TR’

• Conocer triggers creados: • select * from sysobjects where type = ‘TR’ • Obtener el texto del trigger • sp_helptext nombretrigger

 • ALTER TRIGGER • DROP Trigger • Deshabilitar • ALTER TABLE compra •

• ALTER TRIGGER • DROP Trigger • Deshabilitar • ALTER TABLE compra • DISABLE TRIGGER insertcomprastock • Habilitar • ALTER TABLE compra • ENABLE TRIGGER insertcomprastock