Sei sulla pagina 1di 62
Conceptos básicos de desarrollo en

Conceptos básicos de desarrollo en

Conceptos básicos de desarrollo en
Conceptos básicos de desarrollo en
Procedimientos almacenados y Funciones

Procedimientos almacenados y Funciones

Procedimientos almacenados y Funciones
Que son? Un procedimiento almacenado es un conjunto de comandos SQL que pueden almacenarse en

Que son?

Un procedimiento almacenado es un conjunto de comandos SQL que pueden almacenarse en un servidor de base de datos. Luego de su creación, cada cliente puede invocarlo y de esta manera se reutiliza el código, sin necesidad de ejecutar los comandos individualmente.

cliente puede invocarlo y de esta manera se reutiliza el código, sin necesidad de ejecutar los
Ventajas de la utilización ● Sintaxis flexible : Los rutinas almacenadas pueden escribirse utilizando extensiones

Ventajas de la utilización

Sintaxis flexible: Los rutinas almacenadas pueden escribirse utilizando extensiones de la sintaxis de SQL, tales como, construcciones de control de flujo, que facilitan realizar lógicas complejas.

Capacidad de manejo de errores: Se pueden crear manejadores de error para ser utilizados cuando se produzca una condición determinada. De esta forma puede evitarse la finalización de la rutina ante un error.

Compilación Estándar: Se atienen a la sintaxis estándar, por lo que son trasladables a otras bases de datos que sigan los estándares.

Encapsulación y empaquetado de código: Permite tener el código almacenado y ser utilizado desde múltiples aplicaciones.

Menos “Re-invención de la rueda”: Actúan 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.

SQL que tiene habilidades, puede resolver un problema de gran índole con un SP y este
Ventajas de la utilización ● Fácil de Mantener : Una rutina es mas fácil de

Ventajas de la utilización

Fácil de Mantener: Una rutina es mas fácil de mantener que una copia embebida en cada aplicación.

Reducción del requerimiento de Ancho de Banda: Imagine múltiples operaciones realizadas por un cliente sin la utilización de un SP. Cada sentencia y su resultado viaja a través de la red, incluso aquellos que calculan un resultado intermedio. Si en cambio esta operación 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 información sensible. Esta se puede configurar para que el que la invoca o ejecuta, no vea información que no debe. Un SP puede ser utilizado para modificar tablas en modo seguro sin darle al usuario acceso a la tabla.

que no debe. Un SP puede ser utilizado para modificar tablas en modo seguro sin darle
Diferencias entre SP y funciones ● Un SP no retorna solo un valor. Es invocado

Diferencias entre SP y funciones

Un SP no retorna solo un valor. Es invocado con una sentencia CALL.

Una función se invoca dentro de una expresión y retorna un valor simple directamente al invocador para ser utilizada en esa expresión

No se puede invocar una función con CALL, y tampoco se puede invocar un SP en una expresión

en esa expresión ● No se puede invocar una función con CALL, y tampoco se puede
Invocacion de rutinas asociadas a la BD Cada rutina almacenada esta asociada con una base

Invocacion de rutinas asociadas a la BD

Cada rutina almacenada esta asociada con una base en particular.

Cuando se invoca la rutina, se realiza implícitamente 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 también se borran.

● Cuando se borra una base de datos, todos los procedimientos almacenados asociados con ella también
Definición CREATE PROCEDURE nombre_procedure ([Parámetros[, [características.] Cuerpo_de_la_rutina CREATE FUNCTION

Definición

CREATE PROCEDURE nombre_procedure ([Parámetros[, [características.] Cuerpo_de_la_rutina

CREATE FUNCTION nombre_funcion ([Parámetros[, RETURNS tipo_dato

[Características

Cuerpo_de_la_rutina

]

]])

]])

Puede darse como un bloque BEGIN / END que contiene varias sentencias. Cada declaración debe terminar con punto y coma (;). Si usa el cliente de consola de mysql, el (;) es ambiguo entre la definición 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.

de sentencia. Para esto existe el comando delimiter que nos permite definir como queremos marcar el
Definición La clausula opcional [Características] contiene los siguientes valores, estos pueden aparecer en cualquier

Definición

La clausula opcional [Características] 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

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

COMMENT 'Cadena'

Especifica una descripción para la rutina. Esta descripción es mostrada junto con la información de definición de una rutina.

Cuerpo_de_la_rutina

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

del SP o función Esta puede ser una sentencia simple,varias sentencias, o puede contener varios bloques
Declaración de Parámetros ● Los parámetros nos permiten pasarle valores a la rutina cuando se

Declaración de Parámetros

Los parámetros nos permiten pasarle valores a la rutina cuando se la invoca.

La declaración de parámetros ocurre entre los paréntesis () 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)

INT , p_importe DECIMAL (10,2)) RETURNS DECIMAL (10,2) RETURN p_CantPelicula * p_importe; SELECT F_MontoAlquiler(3,5)
Parámetros en los SP El nombre en la declaración de una variable debe ser precedido

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.

como de salida. El SP recibe el parámetro tal como lo pasa el invocador y cuando
Ejemplo: Parámetros de SP DELIMITER $$ CREATE PROCEDURE PRC_testeo_parametros ( IN p_in INT , OUT

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; $$

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

= 0 , @v_out = 0 , @v_inout = 0 CALL PRC_testeo_parametros (@v_in, @v_out, @v_inout); SELECT
Ejemplo: Parámetros de SP mysql> SET @v_in = 0 , @v_out = 0 , @v_inout

Ejemplo: Parámetros 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 |

+-------+--------+----------+

| @v_inout | +-------+--------+----------+ | 0 | 200 | 300 | +-------+--------+----------+ 1 row in set
La sentencia DECLARE La sentencia DECLARE es usada para declarar distintos tipos de items en

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.

son locales a este. Cuando un bloque termina, cualquier cursor abierto se cierra y las variables
Variables dentro de Rutinas Almacenadas DECLARE nombre_variable tipoDato [ DEFAULT valor] A una variable se

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

locales difieren de las variables de usuario, estas no contienen un “@” adelante. DECLARE v_prueba INT
Asignando valores a Variables con SET La sentencia SET asigna valores a variables, estas pueden

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 múltiples:

DECLARE var1, var2, var3;

SET var1 = 1 , var2 = 2 ; SET var3 = var1 + var2 ;

asignaciones simples o múltiples: DECLARE var1, var2, var3; SET var1 = 1 , var2 = 2
Asignando valores con SELECT INTO Asigna el resultado de una sentencia SELECT a una variable.

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 también 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 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.

utilizadas en el INTO permanecerán sin cambio. También se puede usar para asignar valores a parámetros
Ejemplo Asignación de Variables DELIMITER $$ DROP PROCEDURE IF EXISTS `sakila`.`PRC_MejorCliente`$$ CREATE PROCEDURE

Ejemplo Asignación 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;

%m-%d'); SET v_last_month_end = LAST_DAY(last_month_start); SET p_cliente = 0,p_pay=0;
Ejemplo Asignación de Variables SELECT customer_id, SUM(amount) pago INTO p_cliente,p_pay FROM payment WHERE DATE

Ejemplo Asignación 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;

GROUP BY customer_id ORDER BY pago DESC LIMIT 1; 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

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

COUNT(*) FROM film_actor; END ; // Cuando se lo invoca retorna tres conjuntos de resultados de
Recuperación múltiples conjuntos de datos CALL Pelicula_Actor_Contador() mysql> CALL Pelicula_Actor_Contador();

Recuperación múltiples conjuntos de datos

CALL Pelicula_Actor_Contador()

mysql> CALL Pelicula_Actor_Contador();

+------+----------+

+-------+----------+ | Actor | COUNT(*) |

+-------+----------+

| Film | COUNT(*) |

+------+----------+

| Film |

1000 |

+------+----------+

1 row in set (0.01 sec)

| Actor |

200 |

+-------+----------+ 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)

| Film_Actor | 5462 | +------------+----------+ 1 row in set (0.01 sec) Query OK, 0 rows
Control de Flujo: Pruebas Condicionales La sentencia IF y CASE nos permiten evaluar condiciones. Notese

Control de Flujo: Pruebas Condicionales

La sentencia IF y CASE nos permiten evaluar condiciones. Notese que tienen sintaxis diferente que la función IF() y la expresión CASE. Las ultimas producen un valor que es utilizado en una expresión Estas no son sentencias por si mismas. También 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 ambigüedad, 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;

END IF IF val IS NULL THEN SELECT 'val is NULL' ; ELSE SELECT 'val is
Condicional CASE CASE es la otra sentencia que evalúa condiciones. Tiene dos modos. La primera

Condicional CASE

CASE es la otra sentencia que evalúa 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

WHEN when_expr THEN statement_list [ WHEN when_expr THEN statement_list] [ ELSE statement_list] END CASE
Condicional CASE La expresión case_expr se evalúa y suele determinar cual de las siguientes clausulas

Condicional CASE

La expresión case_expr se evalúa 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 evalúa 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 comparación tiene el formato case_expr = when_expr. El significado de esto es que la comparación nunca es verdadera si el operando es NULL, no importa el valor del operando. La siguiente sentencia CASE evalúa si un valor dado es 0, 1, o diferente:

es NULL, no importa el valor del operando. La siguiente sentencia CASE evalúa si un valor
Ejemplo CASE 1er Forma CASE val WHEN 0 THEN SELECT 'val es 0' ; WHEN

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;

'val es 0' ; WHEN 1 THEN SELECT 'val es 1' ; ELSE SELECT 'val no
CASE 2da Forma CASE WHEN when_expr THEN statement_list [ WHEN when_expr THEN statement_list] [ ELSE

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;

0' ; WHEN val > 0 THEN SELECT 'val es mayor que 0' ; ELSE SELECT
Ciclos ● La sintaxis de sentencias en MySQL provee tres tipos distintos de ciclo: ●

Ciclos

La sintaxis de sentencias en MySQL provee tres tipos distintos de ciclo:

LOOP construye un ciclo incondicional sin sintaxis de terminación Por esta razón, 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 ejecución del ciclo. Los SQL estándar incluyen un ciclo FOR también. MySQL no lo soporta.

continua o termina la ejecución del ciclo. ● Los SQL estándar incluyen un ciclo FOR también.
Ciclo LOOP La sentencia LOOP crea un ciclo incondicional con la siguiente sintaxis: LOOP statement_list

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 función) una sentencia de retorno. El siguiente LOOP itera mientras la variable i sea menor que 10:

LEAVE o (en una función) una sentencia de retorno. El siguiente LOOP itera mientras la variable
Construcción Ciclo LOOP DECLARE i INT DEFAULT 0; my_loop: LOOP SET i = i +

Construcción 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;

DECLARE i INT DEFAULT 0; my_loop: LOOP SET i = i + 1; IF i =
Ciclo REPEAT La sentencia REPEAT crea un ciclo condicional. Tiene la siguiente sintaxis: REPEAT lista_sentencias

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 evalúa la expresión 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 expresión y END REPEAT. El siguiente ciclo REPEAT itera mientras la variable i sea menor a 10:

punto y coma entre la expresión y END REPEAT. El siguiente ciclo REPEAT itera mientras la
Construcción Ciclo REPEAT DECLARE i INT DEFAULT 0; REPEAT SET i = i + 1;

Construcción Ciclo REPEAT

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

Construcción Ciclo REPEAT DECLARE i INT DEFAULT 0; REPEAT SET i = i + 1; UNTIL
Ciclo WHILE La sentencia WHILE crea un ciclo condicional. Es similar al REPEAT a excepción

Ciclo WHILE

La sentencia WHILE crea un ciclo condicional. Es similar al REPEAT a excepción que la expresión de condición aparece al principio del ciclo en vez de al final. También, un ciclo WHILE continua mientra la condición sea verdadera, mientras que el ciclo REPEAT termina tan pronto como la condición se vuelve verdadera. La sintaxis de WHILE es la siguiente:

WHILE expr DO statement_list END WHILE

como la condición se vuelve verdadera. La sintaxis de WHILE es la siguiente: WHILE expr DO
Ciclo WHILE La expresión de condición se evalúa y el ciclo finaliza si la la

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):

DECLARE i INT DEFAULT 0; WHILE i < 10 DO SET i = i + 1; END WHILE;

mientras la variable sea menor a 10(diez): DECLARE i INT DEFAULT 0; WHILE i < 10
Diferencia REPEAT y WHILE Debido a que la evaluación en un REPEAT se encuentra al

Diferencia REPEAT y WHILE

Debido a que la evaluación en un REPEAT se encuentra al final del ciclo, las sentencias dentro del ciclo siempre se ejecutan al menos una vez. Con WHILE, la evaluación 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 también En tales casos, es útil etiquetarlos por si es necesario salir de mas de un nivel de ciclo a la vez.

los ciclos también En tales casos, es útil etiquetarlos por si es necesario salir de mas
Transferencia de Control Dentro de una rutina existen dos sentencias que transfieren el control. Cada

Transferencia de Control

Dentro de una rutina existen dos sentencias que transfieren el control. Cada sentencia requiere una etiqueta que indica a que construcción etiquetada debe aplicarse:

LEAVE label

ITERATE label

LEAVE transfiere el control al final de la construcción nombrada y puede ser usada con bloques y ciclos: BEGIN/END, LOOP, REPEAT, o WHILE.

el control al final de la construcción nombrada y puede ser usada con bloques y ciclos:
Transferencia de Control ITERATE transfiere el control al principio de la construcción nombrada. Solo puede

Transferencia de Control

ITERATE transfiere el control al principio de la construcción 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 construcción etiquetada.

El siguiente ejemplo incluye un ciclo etiquetado y muestra como salir del ciclo o comenzarlo nuevamente con LEAVE y ITERATE.

siguiente ejemplo incluye un ciclo etiquetado y muestra como salir del ciclo o comenzarlo nuevamente con
Ejemplo Transferencia DECLARE i INT DEFAULT 0; my_loop: LOOP SET i = i + 1;

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;

ELSEIF i > 20 THEN LEAVE my_loop; END IF ; SELECT 'i is between 10 and
Transferencia de Control La ultima forma de transferir el control es ejecutando una sentencia RETURN

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:

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;

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

Condiciones y manejadores de error

Un manejador de error tiene un nombre y una sentencia que sera ejecutada luego de la ocurrencia de una condición dada, tal como una advertencia o un error. Comúnmente 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 declaración con la sentencia DECLARE, debe hacerse junto con las variables.

DECLARE nombre_condición CONDITION FOR tipo_condición;

Tipo de condición puede ser un valor SQLSTATE o un código de error numérico DECLARE no_permite_null CONDITION FOR SQLSTATE '23000';

DECLARE no_permite_null CONDITION FOR 1048;

DECLARE no_permite_null CONDITION FOR SQLSTATE '23000' ; DECLARE no_permite_null CONDITION FOR 1048;
Condiciones y manejadores de error DECLARE HANDLER crea un manejador para una o mas condiciones

Condiciones y manejadores de error

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_condición [, tipo_condición]

sentencia

El tipo de manejador indica lo que sucede. CONTINUE causa que la rutina continúe la ejecución, la instrucción SQL que sigue a la declaración en la que se produjo la condición 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 estándar también define manejadores UNDO, pero MySQL no es compatible con ellos.

el que el manejador se declaro. El SQL estándar también define manejadores UNDO, pero MySQL no
Condiciones y manejadores de error Cada condición asociada a un manejador debe ser una de

Condiciones y manejadores de error

Cada condición asociada a un manejador debe ser una de las siguientes:

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

El nombre de una condición 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

● SQLEXCEPTION, las cuales manejan condiciones para todos los valores SQLSTATE no manejados por SQLWARNING o
Ejemplo Manejadores de Error CREATE PROCEDURE PRC_AgregaCliente (p_id INT ,p_id_tienda INT ,p_nombre VARCHAR

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;

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

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');

| +-----------------------------------+ mysql> CALL PRC_AgregaCliente(601,1,'Maria', 'Rodriguez');
Handlers DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET exit_loop = 1; DECLARE CONTINUE HANDLER FOR

Handlers

DECLARE CONTINUE HANDLER FOR SQLSTATE '02000'

SET exit_loop = 1;

DECLARE CONTINUE HANDLER FOR SQLSTATE '02000'

BEGIN

statement_list

END;

Para ignorar una condición, declare un manejador CONTINUE y asocielo con un bloque vacío:

DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;

declare un manejador CONTINUE y asocielo con un bloque vacío: DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN
Declaración de Cursores Un cursor te permite acceder a un conjunto de datos de a

Declaración 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 iteración del ciclo.

La implementación del cursor en MySQL tiene las siguientes propiedades:

Provee de cursores de lectura; no pueden utilizarse para modificar 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.

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

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;

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

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.)

de datos. (La sentencia del manejador esta vacía pues el único propósito es transferir el control
Ejemplo Cursores DELIMITER $$ CREATE PROCEDURE PRC_Films_actor(p_actor INT) BEGIN DECLARE v_row_count DECLARE v_code

Ejemplo Cursores

DELIMITER $$

CREATE PROCEDURE PRC_Films_actor(p_actor INT) BEGIN

DECLARE v_row_count DECLARE v_code DECLARE v_name DECLARE c CURSOR FOR

SELECT f.film_id,title FROM

INT DEFAULT 0; INT;

CHAR(52);

film_actor f_a,film f WHERE actor_id=p_actor;

f_a.film_id=f.film_id AND

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; $$

+ 1; END LOOP; END ; CLOSE c; SELECT 'Numero de peliculas realizadas =' , v_row_count;
Ejemplo Cursores En el ejemplo precedente se utiliza un bloque de sentencias anidadas porque un

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.

que setea una variable de estado que produce la terminación del ciclo, ya que la misma
Ejemplo Cursores CREATE PROCEDURE PRC_Films_actor_2(p_actor INT) BEGIN DECLARE v_exit_flag INT DEFAULT 0; DECLARE

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'

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;

SET v_exit_flag = 1;

+ 1; END LOOP; CLOSE c; SELECT 'Numero de peliculas =' , v_row_count; END ; SET
Ejemplo General CREATE PROCEDURE PRC_Pais() SQL SECURITY INVOKER BEGIN DECLARE v_id INT ; DECLARE v_name

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

v_id,v_name; INSERT INTO tmpcountry VALUES (v_name); END LOOP; END ; CLOSE cur; SELECT * FROM tmpcountry;
Triggers A partir de MySQL 5.0.2 se incluyó soporte básico para triggers. Por ahora es

Triggers

A partir de MySQL 5.0.2 se incluyó soporte básico para triggers. Por ahora es muy básico y limitado.

Triggers A partir de MySQL 5.0.2 se incluyó soporte básico para triggers. Por ahora es muy
Que son los triggers? Los triggers (disparadores en español) son acciones que pueden ejecutarse de

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.

Al crear un trigger, se lo asocia con una tabla, y se lo programa para que se active antes o después de la ejecución de que una sentencia del tipo DML (INSERT, DELETE o UPDATE) ocurra en esa tabla. Básicamente 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

Restricción

Una vez activado el trigger, se puede evaluar una condición, para ser ejecutado opcionalmente bajo ciertas condiciones.

Acción

La acción que realiza el trigger al ejecutarse.

para ser ejecutado opcionalmente bajo ciertas condiciones.  Acción La acción que realiza el trigger al
Triggers CREATE TRIGGER nombre_trigger { BEFORE | AFTER } { INSERT | UPDATE | DELETE

Triggers

CREATE TRIGGER nombre_trigger

{ BEFORE | AFTER }

{ INSERT | UPDATE | DELETE }

ON nombre_tabla

FOR EACH ROW

sentencia_a_ejecutar

{ BEFORE | AFTER } { INSERT | UPDATE | DELETE } ON nombre_tabla FOR EACH
Referencias ● En el trigger de un INSERT , NEW .nombre_columna indica el valor de

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 después del UPDATE.

OLD debe ser utilizado en modo solo-lectura. NEW puede ser utilizado para leer o cambiar valores de columnas.

. ● OLD debe ser utilizado en modo solo-lectura. NEW puede ser utilizado para leer o
Eliminación de Triggers Para eliminar un Trigger se utiliza la sentencia DROP TRIGGER. DROP TRIGGER

Eliminación 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;

Si no se hace referencia al nombre de la base de datos se utiliza la base
Triggers:Premisos Para poder crear o eliminar Triggers con las sentencias DROP y CREATE se deben

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 operación realizada.

Para utilizar NEW.col en una expresión, debe tener permiso de SELECT para la columna.

de la operación realizada. Para utilizar NEW .col en una expresión, debe tener permiso de SELECT
Ejemplo Triggers CREATE TABLE `sakila`.`audi_actor` ( `actor_id` SMALLINT (5) UNSIGNED NOT NULL AUTO_INCREMENT ,

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`)

UPDATE CURRENT_TIMESTAMP , user_audi VARCHAR (30), accion_audi VARCHAR (1), KEY `idx_actor_last_name` (`last_name`) )
Creación trigger INSERT DROP TRIGGER IF EXISTS tr_audi_actor_insert; CREATE TRIGGER ON actor tr_audi_actor_insert

Creación trigger INSERT

DROP TRIGGER IF EXISTS tr_audi_actor_insert;

CREATE TRIGGER ON actor

tr_audi_actor_insert AFTER

INSERT

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;

audi_actor VALUES ( NEW .actor_id, NEW .first_name, NEW .last_name, NE W .last_update, USER (), 'i' );
Creación trigger DELETE DROP TRIGGER IF EXISTS tr_audi_actor_delete; CREATE TRIGGER tr_audi_actor_delete AFTER ON

Creación trigger DELETE

DROP TRIGGER IF EXISTS tr_audi_actor_delete;

CREATE TRIGGER tr_audi_actor_delete AFTER ON actor

DELETE

FOR EACH ROW BEGIN INSERT INTO audi_actor VALUES (OLD.actor_id,OLD.first_name,OLD.last_name, OLD.last_update,USER(),'d'); END;

audi_actor VALUES ( OLD .actor_id, OLD .first_name, OLD .last_name, OLD .last_update, USER (), 'd' ); END
Creación trigger UPDATE DROP TRIGGER IF EXISTS tr_audi_actor_update; CREATE TRIGGER tr_audi_actor_update AFTER UPDATE

Creación 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;

audi_actor VALUES ( OLD .actor_id, OLD .first_name, OLD .last_name, OLD .last_update, USER (), 'u' ); END
Comprobación INSERT INTO actor(last_name,first_name) VALUES ( 'Roberto' , 'Darin' ); UPDATE actor SET

Comprobación

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;

WHERE actor_id=213; DELETE FROM actor WHERE actor_id=213 #Comprobamos tabla de auditoria SELECT * FROM audi_actor;