
4.2 Funciones Almacenadas
Las funciones almacenadas en MySQL son similares a los procedimientos almacenados, pero con algunas diferencias clave. Una función almacenada es un bloque de código SQL que realiza un cálculo o una operación y devuelve un valor único. Las funciones se pueden utilizar en consultas SQL como si fueran funciones integradas, lo que permite encapsular lógica de negocio y cálculos repetitivos de manera eficiente.
4.2.1 ¿Qué es una Función Almacenada?
Una función almacenada es un conjunto de instrucciones SQL que se guarda en la base de datos y que devuelve un valor único. Las funciones pueden aceptar parámetros de entrada y se pueden utilizar en consultas, cláusulas `WHERE`, `SELECT`, `ORDER BY`, etc.
Ventajas de Usar Funciones Almacenadas:
- Encapsulación de Lógica: Las funciones almacenadas permiten encapsular lógica compleja y reutilizable en un solo lugar.
- Reutilización: Una función puede ser utilizada en múltiples consultas, lo que reduce la duplicación de código.
- Simplicidad: Facilitan la escritura de consultas SQL más simples y legibles, delegando la lógica a funciones almacenadas.
- Rendimiento: Como las funciones están precompiladas, pueden ejecutar más rápido que una serie de instrucciones SQL ad-hoc.
4.2.2 Creación de una Función Almacenada
La creación de una función almacenada en MySQL se realiza utilizando el comando `CREATE FUNCTION`, seguido de la definición de los parámetros de entrada, el tipo de dato de retorno, y el cuerpo de la función.
Sintaxis Básica:
CREATE FUNCTION nombre_funcion (parametros)
RETURNS tipo_dato
BEGIN
-- Código de la función
RETURN valor;
END;
Ejemplo de Función Simple:
Supongamos que deseas crear una función que calcule el IVA de un precio dado:
DELIMITER //
CREATE FUNCTION calcular_iva (precio DECIMAL(10, 2))
RETURNS DECIMAL(10, 2)
BEGIN
DECLARE iva DECIMAL(10, 2);
SET iva = precio * 0.21; -- Supongamos que el IVA es del 21%
RETURN iva;
END //
DELIMITER ;
En este ejemplo:
- La función `calcular_iva` toma un parámetro `precio` de tipo `DECIMAL` y devuelve el IVA calculado como un `DECIMAL`.
- La función realiza un simple cálculo multiplicando el precio por la tasa de IVA (21%) y devuelve el valor.
Llamar a una Función Almacenada:
Una vez creada, puedes utilizar la función en tus consultas SQL como cualquier otra función integrada:
SELECT nombre, precio, calcular_iva(precio) AS iva
FROM productos;
Esta consulta devuelve el nombre, el precio y el IVA calculado para cada producto en la tabla `productos`.
4.2.3 Diferencias entre Procedimientos y Funciones
Aunque los procedimientos y las funciones almacenadas pueden parecer similares, existen diferencias clave entre ellos:
- Retorno de Valor:
- Función: Siempre devuelve un valor, y ese valor debe ser del tipo especificado en la declaración de la función.
- Procedimiento: No está obligado a devolver un valor, pero puede devolver múltiples valores mediante parámetros de salida.
- Uso en Consultas:
- Función: Puede ser utilizada en consultas SQL como si fuera una función integrada (`SELECT`, `WHERE`, `ORDER BY`, etc.).
- Procedimiento: No se puede utilizar directamente en consultas SQL. Se ejecuta utilizando el comando `CALL`.
- Propósito:
- Función: Generalmente utilizada para realizar cálculos y devolver un resultado.
- Procedimiento: Utilizado para ejecutar una serie de operaciones, que pueden incluir múltiples consultas y operaciones de manipulación de datos.
4.2.4 Parámetros en Funciones Almacenadas
Las funciones almacenadas pueden aceptar uno o más parámetros de entrada. Estos parámetros permiten pasar información a la función para que realice cálculos específicos.
Ejemplo con Múltiples Parámetros:
Supongamos que quieres calcular el precio total de un producto después de aplicar un descuento:
DELIMITER //
CREATE FUNCTION calcular_precio_final (
precio DECIMAL(10, 2),
descuento DECIMAL(5, 2)
)
RETURNS DECIMAL(10, 2)
BEGIN
DECLARE precio_final DECIMAL(10, 2);
SET precio_final = precio - (precio * descuento / 100);
RETURN precio_final;
END //
DELIMITER ;
En este ejemplo:
- La función `calcular_precio_final` toma dos parámetros: `precio` y `descuento`.
- La función calcula el precio final después de aplicar el descuento y lo devuelve.
Uso de la Función en una Consulta:
SELECT nombre, precio, calcular_precio_final(precio, 10) AS precio_con_descuento
FROM productos;
Esta consulta devuelve el nombre, el precio original y el precio con un 10% de descuento para cada producto en la tabla `productos`.
4.2.5 Manejo de Errores en Funciones Almacenadas
Al igual que en los procedimientos almacenados, puedes manejar errores en funciones almacenadas utilizando `DECLARE ... HANDLER`. Sin embargo, dado que las funciones deben devolver un valor, es importante asegurarse de que siempre lo hagan, incluso si se produce un error.
Ejemplo de Manejo de Errores:
DELIMITER //
CREATE FUNCTION dividir_numeros (
numerador DECIMAL(10, 2),
denominador DECIMAL(10, 2)
)
RETURNS DECIMAL(10, 2)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
RETURN NULL;
IF denominador = 0 THEN
RETURN NULL; -- Evitar división por cero
ELSE
RETURN numerador / denominador;
END IF;
END //
DELIMITER ;
En este ejemplo:
- La función `dividir_numeros` devuelve `NULL` si se intenta dividir por cero o si ocurre algún error SQL.
- Se declara un manejador de errores para capturar excepciones SQL y devolver `NULL` en lugar de causar un error en la consulta.
4.2.6 Funciones de Agregación Personalizadas
Una de las aplicaciones avanzadas de las funciones almacenadas es la creación de funciones de agregación personalizadas. Aunque MySQL tiene funciones de agregación integradas como `SUM`, `AVG`, `COUNT`, etc., puedes crear tus propias funciones de agregación cuando necesites un comportamiento específico.
Ejemplo de Función de Agregación Personalizada:
Supongamos que necesitas una función que calcule la mediana de un conjunto de valores. Aunque MySQL no tiene una función de mediana integrada, puedes crear una función almacenada para calcularla.
DELIMITER //
CREATE FUNCTION calcular_mediana (
valores TEXT
)
RETURNS DECIMAL(10, 2)
BEGIN
DECLARE median_value DECIMAL(10, 2);
DECLARE count INT;
DECLARE sorted_values TEXT;
-- Ordenar los valores
SET sorted_values = (SELECT GROUP_CONCAT(val ORDER BY val) FROM STRING_SPLIT(valores, ','));
-- Contar los valores
SET count = (SELECT COUNT(*) FROM STRING_SPLIT(valores, ','));
-- Calcular la mediana
IF count % 2 = 1 THEN
-- Si es impar, la mediana es el valor del medio
SET median_value = (SELECT val FROM STRING_SPLIT(sorted_values, ',') LIMIT (count/2), 1);
ELSE
-- Si es par, la mediana es el promedio de los dos valores centrales
SET median_value = (SELECT AVG(val) FROM (SELECT val FROM STRING_SPLIT(sorted_values, ',') LIMIT (count/2)-1, 2));
END IF;
RETURN median_value;
END //
DELIMITER ;
Este ejemplo es un poco más complejo y depende de la capacidad de manejar cadenas de texto como conjuntos de datos (esto se haría más fácilmente en bases de datos que permiten la manipulación avanzada de arrays o conjuntos). Aquí, la función `calcular_mediana` intenta ordenar los valores y calcular la mediana.
4.2.7 Limitaciones de las Funciones Almacenadas
Aunque las funciones almacenadas son muy poderosas, tienen algunas limitaciones en comparación con los procedimientos almacenados:
- No pueden realizar operaciones DML (Data Manipulation Language) directamente: Las funciones no pueden ejecutar `INSERT`, `UPDATE`, `DELETE` o `MERGE` dentro de su cuerpo. Están limitadas a operaciones de consulta y cálculos.
- Obligación de devolver un valor: Una función debe devolver un valor. Si no hay un valor válido para devolver, se debe manejar la situación (por ejemplo, devolviendo `NULL`).
- No pueden manejar transacciones: A diferencia de los procedimientos almacenados, las funciones no pueden iniciar ni gestionar transacciones.
Resumen
En el punto 4.2 Funciones Almacenadas, aprenderás a crear y utilizar funciones almacenadas en MySQL para realizar cálculos, transformaciones y operaciones específicas de manera eficiente dentro de la base de datos. Las funciones almacenadas te permiten encapsular lógica reutilizable que se puede integrar directamente en consultas SQL, mejorando la claridad y el rendimiento del código. Sin embargo, es importante comprender sus limitaciones y usarlas de manera adecuada para obtener el máximo beneficio.
No hay comentarios