Escolar Documentos
Profissional Documentos
Cultura Documentos
desarrollo en
Procedimientos almacenados y
Funciones
Que son?
Cuerpo_de_la_rutina
SELECT F_MontoAlquiler(3,5)
Parámetros en los SP
El nombre en la declaración de una variable debe ser
precedido por una de las siguientes palabras para indicar en
que dirección fluye la información a través de ese parámetro:
● IN : Indica un parámetro de entrada. El valor del parámetro
es pasado al SP. El SP puede asignarle diferentes valores
al parámetro, pero el cambio es visible solamente dentro del
SP.
● OUT : Indica un parámetro de salida. Si se pasa un valor al
parámetro, es ignorado por el SP, y su valor inicial es NULL.
El SP setea su valor y cuando termina el valor del
parámetro es pasado por el SP al que lo llama. Este valor
se ve accediendo a la variable.
● INOUT : Indica un parámetro que puede ser tanto de
entrada como de salida. El SP recibe el parámetro tal como
lo pasa el invocador y cuando termina vuelve a pasar su
estado final.
Ejemplo: Parámetros 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;
$$
La sentencia SELECT debe traer como máximo una fila, sino ocurrirá
un error. Si no trae ninguna fila, las variables utilizadas en el INTO
permanecerán sin cambio.
También se puede usar para asignar valores a parámetros de una
rutina.
Ejemplo Asignación de Variables
DELIMITER $$
END $$
CALL PRC_MejorCliente(@cli,@pay);
SELECT @cli,@pay;
Recuperación múltiples conjuntos
de datos
Una extensión 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
Recuperación múltiples conjuntos
de datos
CALL Pelicula_Actor_Contador()
mysql> CALL Pelicula_Actor_Contador();
+------+----------+ +-------+----------+
| Film | COUNT(*) | | Actor | COUNT(*) |
+------+----------+ +-------+----------+
| Film | 1000 | | Actor | 200 |
+------+----------+ +-------+----------+
1 row in set (0.01 sec) 1 row in set (0.01 sec)
+------------+----------+
| Film_Actor | COUNT(*) |
+------------+----------+
| Film_Actor | 5462 |
+------------+----------+
1 row in set (0.01 sec)
soporta.
Ciclo LOOP
La sentencia LOOP crea un ciclo incondicional con la siguiente
sintaxis:
LOOP
statement_list
END LOOP
REPEAT
lista_sentencias
UNTIL expr
END REPEAT
WHILE expr DO
statement_list
END WHILE
Ciclo WHILE
La expresión de condición se evalúa y el ciclo finaliza si la la
condición no es verdadera. De otra forma, la lista de sentencias
dentro del ciclo se ejecuta, el control se transfiere al comienzo, y la
expresión es evaluada nuevamente. El siguiente ciclo WHILE itera
mientras la variable sea menor a 10(diez):
WHILE 1 = 0 DO
SET x = 1;
END WHILE;
LEAVE label
ITERATE label
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 país asociado a un código
de país:
tablas.
● Los cursores solo avanzan a través 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 próxima 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 parámetros 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 condición de “No
Data” (SQLSTATE 02000), la cual puede ser detectada declarando
un manejador para esa condición
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 automáticamente cuando el bloque termina.
El siguiente ejemplo declara un cursor nombrado “c” y lo asocia con
una sentencia que selecciona filas de las películas que realizo un
actor. También declara una manejador de condición que detecta el
fin del conjunto de datos. (La sentencia del manejador esta vacía
pues el único propósito es transferir el control al final del bloque.)
Ejemplo Cursores
DELIMITER $$
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 condición 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 terminación 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 básico
para triggers. Por ahora es muy básico y limitado.
Que son los triggers?
Los triggers (disparadores en español) son acciones que pueden
ejecutarse de manera automática cuando determinado evento
ocurre en una tabla.
{ BEFORE | AFTER }
ON nombre_tabla
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.