Saltearse al contenido

Sentencias compuestas

BEGIN ... END

Esta sentencia nos permite escribir una o más sentencias contenidas entre las palabras clave BEGIN ... END. Esta sentencia compuesta puede figurar en programas almacenados (funciones, procedimientos, disparadores, etc.).

Su sintaxis es la siguiente:

1
BEGIN
2
<lista de sentencias>
3
END;

Además, es posible escribir sentencias compuestas BEGIN ... END anidadas.

DELIMITER

Vamos a ver que cuando necesitemos escribir varias sentencias para definir una rutina, el cliente (Workbench o mysql por línea de comandos) no nos permitirá ejecutarla.


Podemos ver que Workbench nos indica que hay errores en las sentencias, cuando hay más de una, aún utilizando BEGIN ... END.

Esto se debe a que el cliente interpreta las sentencias una por vez, separándolas por cada aparición del carácter ‘;’ para luego enviarlas al servidor. Por lo tanto, no puede interpretar la creación de la rutina completa como una sola sentencia.


Solo toma una sentencia hasta donde figura el primer carácter ‘;’ en lugar de toda la definición, lo cual da un error.

DELIMITER es un comando del cliente (no del servidor), que tiene como objetivo modificar el carácter que se usa para delimitar o separar sentencias (por defecto ‘;’) a otro de nuestra elección, por ejemplo: ‘$$’ o ‘//’.

Si estamos definiendo una rutina, necesitamos que el cliente tome todas las sentencias que la componen como una sola, y la envíe al servidor. Podemos lograr esto modificando el delimitador y usándolo solo en la última sentencia, para que el cliente pueda pasar toda la definición al servidor. El resto de las sentencias mantienen el caráceter ‘;’ para que el servidor pueda ejecutarlas correctamente. Luego podemos revertir el delimitador modificado a su valor original.

Por ejemplo, si cambiamos el delimitador a $$:

1
DELIMITER $$ -- modificamos el delimitador de sentencias
2
3
CREATE FUNCTION ...
4
BEGIN
5
<sentencia1>;
6
<sentencia2>;
7
<sentencia3>;
8
<sentencia4>;
9
END$$
10
11
DELIMITER ; -- revertimos al valor original

Esto, efectivamente enviará la creación de la función al servidor como una sola sentencia.

Pronto veremos su uso en la definición de una rutina.

Variables locales

MySQL permite el uso de variables locales en funciones y procedimientos almacenados. Estas variables deben declararse y usarse siempre dentro de la sentencia compuesta BEGIN ... END. Al terminar de ejecutarse la sentencia compuesta, las variables locales son eliminadas.

La declaración de una variable local debe incluir su tipo, y puede incluir un valor por defecto. La sintaxis es la siguiente:

1
DECLARE <nombre> <tipo> [DEFAULT <valor>];

Por ejemplo:

1
DECLARE edad INT;
2
DECLARE nombre VARCHAR(75);
3
DECLARE e_civil VARCHAR(20) DEFAULT "soltero/a";

Un ejemplo de definición y uso

Veamos un ejemplo que aplica las características vistas:

1
USE world;
2
3
DELIMITER $$
4
5
CREATE FUNCTION promedio_pob(codigo CHAR(3))
6
RETURNS FLOAT DETERMINISTIC
7
BEGIN
8
DECLARE prom FLOAT;
9
SELECT AVG(population) INTO prom
10
FROM city
11
WHERE city.CountryCode = codigo;
12
IF prom IS NULL THEN
13
RETURN 0;
14
ELSE
15
RETURN prom;
16
END IF;
17
END$$
18
19
DELIMITER ;

La función pretende recibir un código de tres caracteres como parámetro, que representan el código de un país (en world cada país tiene un código de 3 letras como PK), y luego devolver el promedio de población de sus ciudades.

En este ejemplo podemos ver que estamos usando el comando DELIMITER para enviar la definición entera al servidor.

Podemos ver que MySQL mismo aplica esta funcionalidad automáticamente al crear una función si usamos la opción “Create Function” de Workbench, como se ve a continuación:

Por otro lado, en este ejemplo, estamos utilizando una variable local, definida dentro de la función, llamada prom. Y, además, estamos utilizando una sentencia SELECT ... INTO para almacenar el resultado de la consulta dentro de la variable. Esto se debe a que no está permitido usar consultas que devuelvan result-sets dentro de una función, como dijimos antes.

Finalmente, utilizamos una sentencia IF por si el país no contiene ciudades, y por consiguiente no se puede calcular el promedio. En este caso la función AVG(), que usamos dentro de nuestra función, devolverá NULL. De ser así, queremos que nuestra función devuelva un 0 en su lugar.

Una vez ejecutada la sentencia de creación, el nombre de la función será conocido para la base de datos y podremos invocarla de la siguiente manera:

1
SELECT Name, promedio_pob(Code) AS Poblacion_promedio
2
FROM country;

O, en la cláusula WHERE:

1
SELECT Name
2
FROM country
3
WHERE promedio_pob(Code) > 500000;

Bibliografía

  1. https://dev.mysql.com/doc/refman/8.0/en/begin-end.html
  2. https://dev.mysql.com/doc/refman/8.0/en/stored-programs-defining.html
  3. https://dev.mysql.com/doc/refman/8.0/en/local-variable-scope.html