You are on page 1of 62

Conceptos bsicos de desarrollo en

Procedimientos almacenados y Funciones

Que son?
Un procedimiento almacenado es un conjunto de comandos SQL que pueden almacenarse en un servidor de base de datos. Luego de su creacin, cada cliente puede invocarlo y de esta manera se reutiliza el cdigo, sin necesidad de ejecutar los comandos individualmente.

Ventajas de la utilizacin

Sintaxis flexible: Los rutinas almacenadas pueden escribirse utilizando extensiones de la sintaxis de SQL, tales como, construcciones de control de flujo, que facilitan realizar lgicas complejas. Capacidad de manejo de errores: Se pueden crear manejadores de error para ser utilizados cuando se produzca una condicin determinada. De esta forma puede evitarse la finalizacin de la rutina ante un error. Compilacin Estndar: Se atienen a la sintaxis estndar, por lo que son trasladables a otras bases de datos que sigan los estndares. Encapsulacin y empaquetado de cdigo: Permite tener el cdigo almacenado y ser utilizado desde mltiples aplicaciones. Menos Re-invencin de la rueda: Actan como una biblioteca de soluciones para resolver problemas, facilitan el compartir del conocimiento y la experiencia. Un programador SQL que tiene habilidades, puede resolver un problema de gran ndole con un SP y este puede ser reutilizado por otro.

Ventajas de la utilizacin

Fcil de Mantener: Una rutina es mas fcil de mantener que una copia embebida en cada aplicacin. Reduccin del requerimiento de Ancho de Banda: Imagine mltiples operaciones realizadas por un cliente sin la utilizacin de un SP. Cada sentencia y su resultado viaja a travs de la red, incluso aquellos que calculan un resultado intermedio. Si en cambio esta operacin se realiza con SP, las sentencias y resultados intermedios se procesan completamente del lado del servidor. Mejor seguridad: Una rutina puede ser escrita para acceder a informacin sensible. Esta se puede configurar para que el que la invoca o ejecuta, no vea informacin que no debe. Un SP puede ser utilizado para modificar tablas en modo seguro sin darle al usuario acceso a la tabla.

Diferencias entre SP y funciones


Un SP no retorna solo un valor. Es invocado con una sentencia CALL. Una funcin se invoca dentro de una expresin y retorna un valor simple directamente al invocador para ser utilizada en esa expresin No se puede invocar una funcin con CALL, y tampoco se puede invocar un SP en una expresin

Cada rutina almacenada esta asociada con una base en particular. Cuando se invoca la rutina, se realiza implcitamente USE db_name. No se permite cambiar la base dentro de un SP. Se interpreta una referencia, nombre_rutina, en la base de datos por defecto. Para referirse a una rutina en una base de datos especifica hay que hacerlo de la manera: CALL nombre_base_de_datos.nombre_rutina Cuando una rutina se ejecuta,se cambia la base de datos a la que esta asociada la rutina y cuando termina setea como base por defecto la base anterior. Debido a esto, se debe tener acceso a esa base de datos para poder invocar la rutina. Cuando se borra una base de datos, todos los procedimientos almacenados asociados con ella tambin se borran.

Invocacion de rutinas asociadas a la BD

Definicin
CREATE PROCEDURE nombre_procedure ([Parmetros[,...]]) [caractersticas.] Cuerpo_de_la_rutina CREATE FUNCTION nombre_funcion ([Parmetros[,...]]) RETURNS tipo_dato [Caractersticas..] Cuerpo_de_la_rutina Puede darse como un bloque BEGIN / END que contiene varias sentencias. Cada declaracin debe terminar con punto y coma (;). Si usa el cliente de consola de mysql, el (;) es ambiguo entre la definicin de la rutina y el final de sentencia. Para esto existe el comando delimiter que nos permite definir como queremos marcar el final de una rutina.

Definicin
La clausula opcional [Caractersticas] contiene los siguientes valores, estos pueden aparecer en cualquier orden:

SQL SECURITY {DEFINER | INVOKER}

Un SP corre con los privilegios del usuario que los creo o el que lo invoca. DEFINER es el valor por default.

DETERMINISTIC o NOT DETERMINISTIC COMMENT 'Cadena'

Este valor indica si la rutina produce siempre el mismo resultado o no. El default es NOT DETERMINISTIC.

Especifica una descripcin para la rutina. Esta descripcin es mostrada junto con la informacin de definicin de una rutina.

Cuerpo_de_la_rutina Contiene el cuerpo del SP o funcin Esta puede ser una sentencia simple,varias sentencias, o puede contener varios bloques de sentencias.

Declaracin de Parmetros

Los parmetros nos permiten pasarle valores a la rutina cuando se la invoca. La declaracin de parmetros ocurre entre los parntesis () que le siguen al nombre de la rutina CREATE PROCEDURE o CREATE FUNCTION.

CREATE FUNCTION F_MontoAlquiler(p_CantPelicula INT, p_importe DECIMAL(10,2)) RETURNS DECIMAL(10,2) RETURN p_CantPelicula * p_importe; SELECT F_MontoAlquiler(3,5)

Parmetros en los SP
El nombre en la declaracin de una variable debe ser precedido por una de las siguientes palabras para indicar en que direccin fluye la informacin a travs de ese parmetro: IN : Indica un parmetro de entrada. El valor del parmetro es pasado al SP. El SP puede asignarle diferentes valores al parmetro, pero el cambio es visible solamente dentro del SP. OUT : Indica un parmetro de salida. Si se pasa un valor al parmetro, es ignorado por el SP, y su valor inicial es NULL. El SP setea su valor y cuando termina el valor del parmetro es pasado por el SP al que lo llama. Este valor se ve accediendo a la variable. INOUT : Indica un parmetro que puede ser tanto de entrada como de salida. El SP recibe el parmetro tal como lo pasa el invocador y cuando termina vuelve a pasar su estado final.

Ejemplo: Parmetros de SP
DELIMITER $$ CREATE PROCEDURE PRC_testeo_parametros (IN p_in INT, OUT p_out INT, INOUT p_inout INT) BEGIN SELECT p_in , p_out , p_inout; SET p_in = 100 , p_out = 200 , p_inout = 300; END; $$ SET @v_in = 0 , @v_out = 0 , @v_inout = 0 CALL PRC_testeo_parametros (@v_in, @v_out, @v_inout); SELECT @v_in, @v_out, @v_inout

Ejemplo: Parmetros de SP
mysql> SET @v_in = 0 , @v_out = 0 , @v_inout = 0; Query OK, 0 rows affected (0.00 sec) mysql> CALL PRC_testeo_parametros (@v_in, @v_out, @v_inout);
+------+-------+---------+ | p_in | p_out | p_inout | +------+-------+---------+ | 0 | NULL | 0 | +------+-------+---------+ 1 row in set (0.01 sec)

Query OK, 0 rows affected (0.01 sec) mysql> SELECT @v_in, @v_out, @v_inout;

+-------+--------+----------+ | @v_in | @v_out | @v_inout | +-------+--------+----------+ | 0 | 200 | 300 | +-------+--------+----------+ 1 row in set (0.00 sec)

La sentencia DECLARE
La sentencia DECLARE es usada para declarar distintos tipos de items en rutinas almacenadas: Variables locales Condiciones, tales como alertas o excepciones Manejadores de error Cursores Solo puede ser usada en un bloque BEGIN/END y debe aparecer en el bloque antes que cualquier otra sentencia. Si se declaran distintos tipos de items, se deben declarar variables y condiciones primero, luego cursores y finalmente manejadores de error. Los items creados por DECLARE dentro de un bloque son locales a este. Cuando un bloque termina, cualquier cursor abierto se cierra y las variables dejan de ser accesibles.

Variables dentro de Rutinas Almacenadas


DECLARE nombre_variable tipoDato [DEFAULT valor] A una variable se le pueden asignar valores usando SET, FETCH ... INTO y SELECT ... INTO. Las variables locales difieren de las variables de usuario, estas no contienen un @ adelante. DECLARE v_prueba INT DEFAULT 0

Asignando valores a Variables con SET


La sentencia SET asigna valores a variables, estas pueden ser variables de sistema o variables de usuario. Se pueden setear variables fuera de las rutinas o pueden ser variables dentro de la rutina previamente declaradas con DECLARE. La sentencia SET puede realizar asignaciones simples o mltiples: DECLARE var1, var2, var3; SET var1 = 1 , var2 = 2 ; SET var3 = var1 + var2 ;

Asignando valores con SELECT...INTO


Asigna el resultado de una sentencia SELECT a una variable. Fuera de la rutina deben ser variables de usuario. Dentro de las rutinas, la sentencia puede utilizarse tambin para asignarle valores a variables locales, las cuales fueron declaradas previamente con DECLARE.

DECLARE first_name_var CHAR(45); DECLARE last_name_var CHAR(45); SELECT first_name, last_name INTO v_first_name, v_last_name FROM actor a WHERE actor_id=1;
La sentencia SELECT debe traer como mximo una fila, sino ocurrir un error. Si no trae ninguna fila, las variables utilizadas en el INTO permanecern sin cambio. Tambin se puede usar para asignar valores a parmetros de una rutina.

Ejemplo Asignacin de Variables


DELIMITER $$ DROP PROCEDURE IF EXISTS `sakila`.`PRC_MejorCliente`$$ CREATE PROCEDURE `sakila`.`PRC_MejorCliente`( OUT p_cliente SMALLINT, OUT p_pay DECIMAL(5,2) ) BEGIN DECLARE v_last_month_start DATE; DECLARE v_last_month_end DATE; /* Determine start and end time periods */ SET v_last_month_start = STR_TO_DATE('2005-06-01','%Y%m-%d'); SET v_last_month_end = LAST_DAY(last_month_start); SET p_cliente = 0,p_pay=0;

Ejemplo Asignacin de Variables


SELECT customer_id, SUM(amount) pago INTO p_cliente,p_pay FROM payment WHERE DATE(payment_date) BETWEEN v_last_month_start AND v_last_month_end GROUP BY customer_id ORDER BY pago DESC LIMIT 1; END $$ CALL PRC_MejorCliente(@cli,@pay); SELECT @cli,@pay;

Recuperacin mltiples conjuntos de datos


Una extensin del MySQL a los procedures es que la sentencia SELECT puede ser ejecutada para generar conjuntos de resultados que son retornados directamente al cliente sin proceso intermediario. EL cliente recibe los resultados como si ejecutara la sentencia SELECT el mismo. Esto no aplica a las funciones almacenadas. DELIMITER // CREATE PROCEDURE PRC_Pelicula_Actor_Contador () BEGIN SELECT 'Film', COUNT(*) FROM film; SELECT 'Actor', COUNT(*) FROM actor; SELECT 'Film_Actor', COUNT(*) FROM film_actor; END; // Cuando se lo invoca retorna tres conjuntos de resultados de un registro

Recuperacin mltiples conjuntos de datos


CALL Pelicula_Actor_Contador() mysql> CALL Pelicula_Actor_Contador(); +------+----------+ | Film | COUNT(*) | +------+----------+ | Film | 1000 | +------+----------+ 1 row in set (0.01 sec) +------------+----------+ | Film_Actor | COUNT(*) | +------------+----------+ | Film_Actor | 5462 | +------------+----------+ 1 row in set (0.01 sec) Query OK, 0 rows affected (0.01 sec) +-------+----------+ | Actor | COUNT(*) | +-------+----------+ | Actor | 200 | +-------+----------+ 1 row in set (0.01 sec)

La sentencia IF y CASE nos permiten evaluar condiciones. Notese que tienen sintaxis diferente que la funcin IF() y la expresin CASE. Las ultimas producen un valor que es utilizado en una expresin Estas no son sentencias por si mismas. Tambin terminan con END en lugar de END CASE. Gracias a la sintaxis diferente, es posible utilizar las funciones IF() y las expresiones CASE dentro de las rutinas almacenadas sin tener ambigedad, incluso si se utilizan dentro de una sentencia IF o CASE. IF expr THEN statement_list [ELSEIF expr THEN statement_list] ... [ELSE statement_list] END IF IF val IS NULL THEN SELECT 'val is NULL'; ELSE SELECT 'val is not NULL'; END IF;

Control de Flujo: Pruebas Condicionales

Condicional CASE
CASE es la otra sentencia que evala condiciones. Tiene dos modos. La primera sintaxis es la siguiente: CASE case_expr WHEN when_expr THEN statement_list [WHEN when_expr THEN statement_list] ... [ELSE statement_list] END CASE

Condicional CASE
La expresin case_expr se evala y suele determinar cual de las siguientes clausulas en el resto de la sentencia debe ejecutarse. La when_expr en la clausula inicial del WHEN se evala y compara con la case_expr. Si son iguales, la lista de sentencias siguiente al THEN se ejecuta. Si when_expr no es igual a case_expr, y existen otras clausulas WHEN, se manejan de forma similar a su turno. Si ninguna clausula WHEN tiene una when_expr igual a case_expr, y hay una clausula ELSE, la lista de sentencias de de la clausula ELSE es ejecutada. Cada comparacin tiene el formato case_expr = when_expr. El significado de esto es que la comparacin nunca es verdadera si el operando es NULL, no importa el valor del operando. La siguiente sentencia CASE evala si un valor dado es 0, 1, o diferente:

Ejemplo CASE 1er Forma


CASE val WHEN 0 THEN SELECT 'val es 0'; WHEN 1 THEN SELECT 'val es 1'; ELSE SELECT 'val no es 0 or 1'; END CASE;

CASE 2da Forma


CASE WHEN when_expr THEN statement_list [WHEN when_expr THEN statement_list] ... [ELSE statement_list] END CASE

Ejemplo CASE 2da Forma


CASE WHEN val IS NULL THEN SELECT 'val is NULL'; WHEN val < 0 THEN SELECT 'val es menor que 0'; WHEN val > 0 THEN SELECT 'val es mayor que 0'; ELSE SELECT 'val es 0'; END CASE;

Ciclos
La sintaxis de sentencias en MySQL provee tres tipos distintos de ciclo: LOOP construye un ciclo incondicional sin sintaxis de terminacin Por esta razn, debe contener una sentencia que especifique la salida del ciclo. REPEAT y WHILE, las otras dos construcciones de ciclo, son condicionales. Incluyen una clausula que determina si continua o termina la ejecucin del ciclo. Los SQL estndar incluyen un ciclo FOR tambin. MySQL no lo soporta.

Ciclo LOOP
La sentencia LOOP crea un ciclo incondicional con la siguiente sintaxis: LOOP statement_list END LOOP La lista de sentencias dentro del ciclo se ejecuta repetidamente. El ciclo iterara por siempre a menos que la lista de sentencias contenga alguna sentencia que genera la salida del ciclo. La salida puede hacerse efectiva con una sentencia LEAVE o (en una funcin) una sentencia de retorno. El siguiente LOOP itera mientras la variable i sea menor que 10:

Construccin Ciclo LOOP


DECLARE i INT DEFAULT 0; my_loop: LOOP SET i = i + 1; IF i = 10 THEN LEAVE my_loop; END IF; END LOOP my_loop;

Ciclo REPEAT
La sentencia REPEAT crea un ciclo condicional. Tiene la siguiente sintaxis: REPEAT lista_sentencias UNTIL expr END REPEAT Las sentencias dentro del ciclo se ejecutan y luego se evala la expresin condicional expr. Si la expresion es verdadera, el ciclo termina. De otro modo, comienza nuevamente. Notese que no se utiliza punto y coma entre la expresin y END REPEAT. El siguiente ciclo REPEAT itera mientras la variable i sea menor a 10:

Construccin Ciclo REPEAT


DECLARE i INT DEFAULT 0; REPEAT SET i = i + 1; UNTIL i >= 10 END REPEAT;

Ciclo WHILE
La sentencia WHILE crea un ciclo condicional. Es similar al REPEAT a excepcin que la expresin de condicin aparece al principio del ciclo en vez de al final. Tambin, un ciclo WHILE continua mientra la condicin sea verdadera, mientras que el ciclo REPEAT termina tan pronto como la condicin se vuelve verdadera. La sintaxis de WHILE es la siguiente: WHILE expr DO statement_list END WHILE

Ciclo WHILE
La expresin de condicin se evala y el ciclo finaliza si la la condicin no es verdadera. De otra forma, la lista de sentencias dentro del ciclo se ejecuta, el control se transfiere al comienzo, y la expresin es evaluada nuevamente. El siguiente ciclo WHILE itera mientras la variable sea menor a 10(diez): DECLARE i INT DEFAULT 0; WHILE i < 10 DO SET i = i + 1; END WHILE;

Diferencia REPEAT y WHILE


Debido a que la evaluacin en un REPEAT se encuentra al final del ciclo, las sentencias dentro del ciclo siempre se ejecutan al menos una vez. Con WHILE, la evaluacin se realiza al principio, por lo que es posible que las sentencias dentro del ciclo no se ejecuten ni siquiera una vez. Por ejemplo, el siguiente ciclo WHILE no ejecutara nunca las sentencias dentro del ciclo: WHILE 1 = 0 DO SET x = 1; END WHILE; As como los bloques BEGIN/END pueden ser anidados, los ciclos tambin En tales casos, es til etiquetarlos por si es necesario salir de mas de un nivel de ciclo a la vez.

Transferencia de Control
Dentro de una rutina existen dos sentencias que transfieren el control. Cada sentencia requiere una etiqueta que indica a que construccin etiquetada debe aplicarse: LEAVE label ITERATE label LEAVE transfiere el control al final de la construccin nombrada y puede ser usada con bloques y ciclos: BEGIN/END, LOOP, REPEAT, o WHILE.

Transferencia de Control
ITERATE transfiere el control al principio de la construccin nombrada. Solo puede utilizarse dentro de ciclos: LOOP, REPEAT, o WHILE. No puede utilizarse para reiniciar un bloque BEGIN/END. LEAVE y ITERATE deben aparecer dentro de una construccin etiquetada. El siguiente ejemplo incluye un ciclo etiquetado y muestra como salir del ciclo o comenzarlo nuevamente con LEAVE y ITERATE.

Ejemplo Transferencia
DECLARE i INT DEFAULT 0; my_loop: LOOP SET i = i + 1; IF i < 10 THEN ITERATE my_loop; ELSEIF i > 20 THEN LEAVE my_loop; END IF; SELECT 'i is between 10 and 20'; END LOOP my_loop;

Transferencia de Control
La ultima forma de transferir el control es ejecutando una sentencia RETURN para retornar un valor al proceso que llamo la rutina. Esto solo se aplica a las funciones, no a los procesos almacenados. El siguiente ejemplo retorna el nombre del pas asociado a un cdigo de pas: CREATE FUNCTION `sakila`.`F_NombrePelicula`(p_id INT) RETURNS CHAR(255) BEGIN DECLARE v_namer CHAR(255); SELECT title INTO v_name FROM film WHERE film_id=p_id; RETURN v_namer; END;

Condiciones y manejadores de error


Un manejador de error tiene un nombre y una sentencia que sera ejecutada luego de la ocurrencia de una condicin dada, tal como una advertencia o un error. Comnmente los manejadores se usan para detectar problemas y tratarlos de una manera mas apropiada y evitar que la rutina termine con un error. Se pueden nombrar mediante una declaracin con la sentencia DECLARE, debe hacerse junto con las variables.

DECLARE nombre_condicin CONDITION FOR tipo_condicin;


Tipo de condicin puede ser un valor SQLSTATE o un cdigo de error numrico DECLARE no_permite_null CONDITION FOR SQLSTATE '23000'; DECLARE no_permite_null CONDITION FOR 1048;

DECLARE HANDLER crea un manejador para una o mas condiciones y las asocia con una sentencia SQL que sera ejecutada si cualquiera de las condiciones ocurre: DECLARE tipo_manejador HANDLER FOR tipo_condicin [, tipo_condicin] ... sentencia El tipo de manejador indica lo que sucede. CONTINUE causa que la rutina contine la ejecucin, la instruccin SQL que sigue a la declaracin en la que se produjo la condicin es la siguiente para ser procesada. EXIT causa la transferencia del control al final del bloque en el que el manejador se declaro. El SQL estndar tambin define manejadores UNDO, pero MySQL no es compatible con ellos.

Condiciones y manejadores de error

Cada condicin asociada a un manejador debe ser una de las siguientes:

Condiciones y manejadores de error


Un valor SQLSTATE o cdigo de error de MYSQL, se especifica de la misma manera que en una sentencia DECLARE CONDITION.

El nombre de una condicin declarada previamente con una sentencia DECLARE CONDITION. SQLWARNING, las cuales manejan condiciones para todos los valores SQLSTATE que comienzan con 01. NOT FOUND, las cuales manejan condiciones para todos los valores SQLSTATE que comienzan con 02. SQLEXCEPTION, las cuales manejan condiciones para todos los valores SQLSTATE no manejados por SQLWARNING o NOT FOUND

Ejemplo Manejadores de Error CREATE PROCEDURE PRC_AgregaCliente (p_id

INT,p_id_tienda INT,p_nombre VARCHAR(45),p_apellido VARCHAR(45)) BEGIN DECLARE EXIT HANDLER FOR 1062 BEGIN SELECT 'ERROR numero de tienda invalido' AS result; END; DECLARE EXIT HANDLER FOR 1452 BEGIN SELECT 'ERROR numero de cliente ya existe' AS result; END; INSERT INTO customer VALUES(p_id,p_id_tienda,p_nombre,p_apellido,NULL,1,1,CU RRENT_DATE(),CURRENT_DATE()); SELECT 'Cliente agregado con xito' AS result; END;

Ejemplo Manejadores de Error


mysql> CALL PRC_AgregaCliente(601,9999999,'Maria', 'Rodriguez'); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`sakila/customer`, CONSTRAINT `fk_customer_store` FOREIGN KEY (`store_id`) REFERENCES `store` (`store_id`) ON UPDATE CASCADE) mysql> CALL PRC_AgregaCliente(2,1,'Maria', 'Rodriguez'); ERROR 1062 (23000): Duplicate entry '2' for key 1 mysql> CALL PRC_AgregaCliente(601,9999999,'Maria', 'Rodriguez'); +---------------------------------+ | result | +---------------------------------+ | ERROR numero de tienda invalido | +---------------------------------+ mysql> CALL PRC_AgregaCliente(2,1,'Maria', 'Rodriguez'); +-----------------------------------+ | result | +-----------------------------------+ | ERROR numero de cliente ya existe | +-----------------------------------+ mysql> CALL PRC_AgregaCliente(601,1,'Maria', 'Rodriguez');

Handlers
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET exit_loop = 1; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' BEGIN statement_list END; Para ignorar una condicin, declare un manejador CONTINUE y asocielo con un bloque vaco: DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;

Declaracin de Cursores
Un cursor te permite acceder a un conjunto de datos de a una fila a la vez. Debido a esto, los cursores son utilizados en ciclos que fijan y procesan una fila dentro de cada iteracin del ciclo. La implementacin del cursor en MySQL tiene las siguientes propiedades: Provee de cursores de lectura; no pueden utilizarse para modificar tablas. Los cursores solo avanzan a travs de los datos fila por fila; esto significa, que no son desplazables en cualquier sentido.

Para usar un cursor en una rutina almacenada, comience escribiendo una sentencia DECLARE CURSOR en el cual se nombra el cursor y se asocia al la sentencia SELECT que produce el conjunto de datos:

DECLARE nombre_cursor CURSOR FOR sentencia_select


Cada cursor declarado dentro de un bloque debe tener un nombre diferente.

Manejo de Cursores
Los cursores deben abrirse con una sentencia OPEN. Esta ejecuta la sentencia SELECT asociada con el cursor: OPEN nombre_cursor La sentencia FETCH obtiene la prxima fila del conjunto de datos del cursor abierto. Tiene que utilizarse una variable por cada columna del conjunto de datos. Pueden obtenerse los valores dentro de variables o parmetros de rutinas: FETCH nombre_cursor INTO var_name [, var_name] ... FETCH frecuentemente se utiliza en un ciclo para que todas las filas puedan ser procesadas. Esto presenta un problema: Que pasa cuando se alcanza el fin de datos? Ocurre una condicin de No Data (SQLSTATE 02000), la cual puede ser detectada declarando un manejador para esa condicin DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' statement;

Cierre de Cursores
Cuando se termina de utilizar el cursor, se debe cerrar con una sentencia CLOSE: CLOSE nombre_cursor Cerrar un cursor es opcional. Cualquier cursor declarado en un bloque se cierra automticamente cuando el bloque termina. El siguiente ejemplo declara un cursor nombrado c y lo asocia con una sentencia que selecciona filas de las pelculas que realizo un actor. Tambin declara una manejador de condicin que detecta el fin del conjunto de datos. (La sentencia del manejador esta vaca pues el nico propsito es transferir el control al final del bloque.)

DELIMITER $$

Ejemplo Cursores

CREATE PROCEDURE PRC_Films_actor(p_actor INT) BEGIN DECLARE v_row_count INT DEFAULT 0; DECLARE v_code INT; DECLARE v_name CHAR(52); DECLARE c CURSOR FOR SELECT f.film_id,title FROM film_actor f_a,film f WHERE f_a.film_id=f.film_id AND actor_id=p_actor; OPEN c; BEGIN DECLARE EXIT HANDLER FOR SQLSTATE '02000' BEGIN END; LOOP FETCH c INTO v_code, v_name; SET v_row_count = v_row_count + 1; END LOOP; END; CLOSE c; SELECT 'Numero de peliculas realizadas =', v_row_count; END; $$

Ejemplo Cursores
En el ejemplo precedente se utiliza un bloque de sentencias anidadas porque un manejador EXIT termina el bloque dentro del cual se declara, no el ciclo dentro del cual la condicin ocurre. Si no se hubiera utilizado un bloque de sentencias anidadas, el manejador hubiera transferido el control al final del bloque principal luego de llegar al fin del conjunto de datos, y la sentencia CLOSE y SELECT siguientes al ciclo no hubieran sido ejecutadas. Un enfoque alternativo no requiere de un bloque de sentencias anidadas: Usa un manejador CONTINUE que setea una variable de estado que produce la terminacin del ciclo, ya que la misma se se controla dentro de ciclo.

Ejemplo Cursores
CREATE PROCEDURE PRC_Films_actor_2(p_actor INT) BEGIN DECLARE v_exit_flag INT DEFAULT 0; DECLARE v_row_count INT DEFAULT 0; DECLARE v_code INT; DECLARE v_name CHAR(52); DECLARE c CURSOR FOR SELECT f.film_id,title FROM film_actor f_a,film f WHERE f_a.film_id=f.film_id AND actor_id=p_actor; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET v_exit_flag = 1; OPEN c; fetch_loop: LOOP FETCH c INTO v_code, v_name; IF v_exit_flag THEN LEAVE fetch_loop; END IF; SET v_row_count = v_row_count + 1; END LOOP; CLOSE c; SELECT 'Numero de peliculas =', v_row_count; END;

Ejemplo General
CREATE PROCEDURE PRC_Pais() SQL SECURITY INVOKER BEGIN DECLARE v_id INT; DECLARE v_name VARCHAR(50); DECLARE cur CURSOR FOR SELECT country_id,country FROM country; CREATE TEMPORARY TABLE tmpcountry (country VARCHAR(50)); OPEN cur; BEGIN DECLARE EXIT HANDLER FOR SQLSTATE '02000' BEGIN END; LOOP FETCH cur INTO v_id,v_name; INSERT INTO tmpcountry VALUES(v_name); END LOOP; END; CLOSE cur; SELECT * FROM tmpcountry; END

Triggers
A partir de MySQL 5.0.2 se incluy soporte bsico para triggers. Por ahora es muy bsico y limitado.

Que son los triggers?


Los triggers (disparadores en espaol) son acciones que pueden ejecutarse de manera automtica cuando determinado evento ocurre en una tabla. Al crear un trigger, se lo asocia con una tabla, y se lo programa para que se active antes o despus de la ejecucin de que una sentencia del tipo DML (INSERT, DELETE o UPDATE) ocurra en esa tabla. Bsicamente un trigger se compone de tres partes: Evento Es el evento que tiene que ocurrir para que el trigger se active. Puede ser una sentencia INSERT, DELETE o UPDATE Restriccin Una vez activado el trigger, se puede evaluar una condicin, para ser ejecutado opcionalmente bajo ciertas condiciones. Accin La accin que realiza el trigger al ejecutarse.

Triggers
CREATE TRIGGER nombre_trigger { BEFORE | AFTER } { INSERT | UPDATE | DELETE } ON nombre_tabla FOR EACH ROW sentencia_a_ejecutar

Referencias

En el trigger de un INSERT , NEW.nombre_columna indica el valor de una columna a ser insertado dentro de una nueva columna. OLD no esta permitido. En el trigger de un DELETE, OLD.nombre_columna indica el valor de una columna a ser borrado. NEW no esta disponible. En el trigger de un UPDATE, OLD.nombre_columna y NEW.nombre_columna hacer referencia al valor de una fila antes y despus del UPDATE. OLD debe ser utilizado en modo solo-lectura. NEW puede ser utilizado para leer o cambiar valores de columnas.

Eliminacin de Triggers
Para eliminar un Trigger se utiliza la sentencia DROP TRIGGER. DROP TRIGGER nombre_base.nombre_trigger; Si no se hace referencia al nombre de la base de datos se utiliza la base por defecto. DROP TRIGGER nombre_trigger;

Triggers:Premisos
Para poder crear o eliminar Triggers con las sentencias DROP y CREATE se deben tener privilegios SUPER Para asignar valor a una columna con SET NEW.col = VALOR, debe tener permiso de UPDATE o INSERT para la columna, dependiendo de la operacin realizada. Para utilizar NEW.col en una expresin, debe tener permiso de SELECT para la columna.

Ejemplo Triggers
CREATE TABLE `sakila`.`audi_actor` ( `actor_id` SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT, `first_name` VARCHAR(45) NOT NULL, `last_name` VARCHAR(45) NOT NULL, `last_update` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, user_audi VARCHAR(30), accion_audi VARCHAR(1), KEY `idx_actor_last_name` (`last_name`) )

Creacin trigger INSERT


DROP TRIGGER IF EXISTS tr_audi_actor_insert; CREATE TRIGGER tr_audi_actor_insert AFTER INSERT ON actor FOR EACH ROW BEGIN INSERT INTO audi_actor VALUES (NEW.actor_id,NEW.first_name,NEW.last_name,NE W.last_update,USER(),'i'); END;

Creacin trigger DELETE


DROP TRIGGER IF EXISTS tr_audi_actor_delete; CREATE TRIGGER tr_audi_actor_delete AFTER DELETE ON actor FOR EACH ROW BEGIN INSERT INTO audi_actor VALUES (OLD.actor_id,OLD.first_name,OLD.last_name, OLD.last_update,USER(),'d'); END;

Creacin trigger UPDATE


DROP TRIGGER IF EXISTS tr_audi_actor_update; CREATE TRIGGER tr_audi_actor_update AFTER UPDATE ON actor FOR EACH ROW BEGIN INSERT INTO audi_actor VALUES (OLD.actor_id,OLD.first_name,OLD.last_name, OLD.last_update,USER(),'u'); END;

Comprobacin
INSERT INTO actor(last_name,first_name) VALUES('Roberto','Darin'); UPDATE actor SET first_name='Ricardo' WHERE actor_id=213; DELETE FROM actor WHERE actor_id=213 #Comprobamos tabla de auditoria SELECT * FROM audi_actor;

You might also like