SQL
Tutorial SQL: Creación y uso de funciones
Aprende a crear y utilizar funciones definidas por el usuario (UDF) en SQL para mejorar la lógica y reutilización en bases de datos MySQL y PostgreSQL.
Aprende SQL y certifícateFunciones UDF
Las funciones definidas por el usuario (User-Defined Functions o UDF) son objetos de base de datos que encapsulan lógica personalizada y reutilizable dentro del entorno SQL. Estas funciones permiten extender las capacidades nativas del lenguaje SQL para resolver problemas específicos de negocio o simplificar operaciones complejas.
Concepto y propósito
Las funciones UDF actúan como bloques de código que aceptan parámetros, ejecutan una serie de instrucciones y devuelven un resultado. A diferencia de las funciones integradas de SQL (como COUNT, SUM o UPPER), las UDF son creadas por los desarrolladores para satisfacer necesidades particulares que no están cubiertas por la funcionalidad estándar.
Los principales beneficios de utilizar funciones UDF incluyen:
- Reutilización de código: Escribir una vez, usar muchas veces
- Encapsulación: Ocultar la complejidad detrás de una interfaz simple
- Mantenimiento: Centralizar la lógica para facilitar actualizaciones
- Legibilidad: Hacer que las consultas sean más claras y expresivas
Sintaxis básica para crear funciones UDF
La sintaxis para crear una función UDF varía ligeramente entre MySQL y PostgreSQL, pero mantiene una estructura general similar:
En MySQL:
CREATE FUNCTION nombre_funcion(parametro1 tipo1, parametro2 tipo2, ...)
RETURNS tipo_retorno
[características]
BEGIN
-- Cuerpo de la función
-- Lógica y operaciones
RETURN valor;
END;
En PostgreSQL:
CREATE OR REPLACE FUNCTION nombre_funcion(parametro1 tipo1, parametro2 tipo2, ...)
RETURNS tipo_retorno AS
$$
BEGIN
-- Cuerpo de la función
-- Lógica y operaciones
RETURN valor;
END;
$$ LANGUAGE plpgsql;
Tipos de funciones UDF
Dependiendo de su propósito y comportamiento, las funciones UDF se pueden clasificar en diferentes categorías:
- Funciones escalares: Devuelven un único valor por cada fila de entrada
- Funciones de tabla: Retornan un conjunto de resultados (tabla)
- Funciones de agregado: Operan sobre múltiples filas y devuelven un único resultado
Ejemplos prácticos
Función escalar simple en MySQL
Veamos una función que calcula el precio con descuento:
DELIMITER //
CREATE FUNCTION calcular_precio_descuento(precio DECIMAL(10,2), porcentaje_descuento DECIMAL(5,2))
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
DECLARE precio_final DECIMAL(10,2);
SET precio_final = precio - (precio * porcentaje_descuento / 100);
RETURN precio_final;
END //
DELIMITER ;
Para usar esta función:
SELECT
nombre_producto,
precio_original,
calcular_precio_descuento(precio_original, 15) AS precio_con_descuento
FROM productos;
Función escalar en PostgreSQL
Una función que convierte una cadena a formato de título (primera letra de cada palabra en mayúscula):
CREATE OR REPLACE FUNCTION formato_titulo(texto text)
RETURNS text AS
$$
DECLARE
resultado text := '';
palabra text;
palabras text[];
BEGIN
palabras := string_to_array(lower(texto), ' ');
FOREACH palabra IN ARRAY palabras LOOP
IF length(palabra) > 0 THEN
resultado := resultado || ' ' || upper(left(palabra, 1)) || right(palabra, -1);
END IF;
END LOOP;
RETURN trim(resultado);
END;
$$ LANGUAGE plpgsql;
Uso de la función:
SELECT
formato_titulo('el rápido zorro marrón') AS titulo_formateado;
-- Resultado: "El Rápido Zorro Marrón"
Funciones de tabla
Las funciones que retornan conjuntos de resultados son especialmente útiles para operaciones complejas:
En MySQL:
DELIMITER //
CREATE FUNCTION obtener_productos_categoria(cat_id INT)
RETURNS TABLE (
id INT,
nombre VARCHAR(100),
precio DECIMAL(10,2)
)
READS SQL DATA
BEGIN
RETURN TABLE (
SELECT producto_id, nombre_producto, precio
FROM productos
WHERE categoria_id = cat_id
);
END //
DELIMITER ;
En PostgreSQL:
CREATE OR REPLACE FUNCTION productos_por_rango_precio(precio_min DECIMAL, precio_max DECIMAL)
RETURNS TABLE (
id INTEGER,
nombre VARCHAR(100),
precio DECIMAL(10,2),
categoria VARCHAR(50)
) AS
$$
BEGIN
RETURN QUERY
SELECT
p.producto_id,
p.nombre_producto,
p.precio,
c.nombre_categoria
FROM
productos p
JOIN
categorias c ON p.categoria_id = c.categoria_id
WHERE
p.precio BETWEEN precio_min AND precio_max
ORDER BY
p.precio;
END;
$$ LANGUAGE plpgsql;
Para usar esta función:
SELECT * FROM productos_por_rango_precio(10.00, 50.00);
Variables y control de flujo
Las funciones UDF permiten declarar variables locales y utilizar estructuras de control como condicionales y bucles:
DELIMITER //
CREATE FUNCTION calcular_categoria_cliente(total_compras DECIMAL(10,2))
RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
DECLARE categoria VARCHAR(20);
IF total_compras > 10000 THEN
SET categoria = 'Premium';
ELSEIF total_compras > 5000 THEN
SET categoria = 'Gold';
ELSEIF total_compras > 1000 THEN
SET categoria = 'Silver';
ELSE
SET categoria = 'Regular';
END IF;
RETURN categoria;
END //
DELIMITER ;
Consideraciones de seguridad y rendimiento
Al trabajar con funciones UDF, es importante tener en cuenta:
- Características de seguridad: Especificar si la función accede a datos (READS SQL DATA) o los modifica (MODIFIES SQL DATA)
- Determinismo: Indicar si la función siempre devuelve el mismo resultado para los mismos parámetros (DETERMINISTIC)
- Índices: Las funciones en cláusulas WHERE pueden afectar el uso de índices
- Transacciones: Considerar el comportamiento dentro de transacciones
Gestión de funciones UDF
Para administrar las funciones UDF existentes:
Listar funciones en MySQL:
SHOW FUNCTION STATUS WHERE Db = 'nombre_base_datos';
Listar funciones en PostgreSQL:
SELECT routine_name
FROM information_schema.routines
WHERE routine_type = 'FUNCTION'
AND routine_schema = 'public';
Eliminar una función:
-- MySQL y PostgreSQL
DROP FUNCTION IF EXISTS nombre_funcion;
Modificar una función existente: En MySQL, es necesario eliminar y recrear la función. En PostgreSQL, se puede usar CREATE OR REPLACE FUNCTION.
Depuración de funciones UDF
Para facilitar la depuración durante el desarrollo, se pueden implementar técnicas como:
CREATE OR REPLACE FUNCTION funcion_con_debug(param1 INT)
RETURNS INT AS
$$
DECLARE
resultado INT;
BEGIN
-- Registrar valores para depuración
RAISE NOTICE 'Parámetro recibido: %', param1;
resultado := param1 * 2;
RAISE NOTICE 'Resultado calculado: %', resultado;
RETURN resultado;
END;
$$ LANGUAGE plpgsql;
Las funciones UDF son herramientas fundamentales para los desarrolladores SQL que necesitan implementar lógica de negocio personalizada directamente en la base de datos. Permiten encapsular operaciones complejas y reutilizar código, mejorando tanto la productividad como el rendimiento de las aplicaciones que interactúan con la base de datos.
Retorno de valores
El retorno de valores es un aspecto fundamental en las funciones definidas por el usuario (UDF) en SQL. Cuando creamos una función, necesitamos especificar explícitamente qué tipo de datos devolverá y asegurarnos de que la función efectivamente retorne un valor compatible con ese tipo.
Declaración del tipo de retorno
Al crear una función UDF, debemos indicar el tipo de dato que devolverá mediante la cláusula RETURNS
. Esta declaración es obligatoria y determina el tipo de valor que los usuarios de la función pueden esperar recibir:
En MySQL:
CREATE FUNCTION calcular_impuesto(precio DECIMAL(10,2))
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
RETURN precio * 0.21;
END;
En PostgreSQL:
CREATE OR REPLACE FUNCTION calcular_impuesto(precio DECIMAL)
RETURNS DECIMAL AS
$$
BEGIN
RETURN precio * 0.21;
END;
$$ LANGUAGE plpgsql;
Tipos de datos que pueden retornarse
Las funciones UDF pueden devolver prácticamente cualquier tipo de dato soportado por el sistema de gestión de bases de datos:
- Tipos escalares: Enteros (
INT
,BIGINT
), números decimales (DECIMAL
,FLOAT
), cadenas (VARCHAR
,TEXT
), fechas (DATE
,TIMESTAMP
), booleanos (BOOLEAN
), etc. - Tipos compuestos: Registros o filas completas
- Conjuntos de resultados: Tablas completas (solo en ciertos contextos)
- Tipos definidos por el usuario: Tipos personalizados creados con
CREATE TYPE
(principalmente en PostgreSQL)
La sentencia RETURN
La sentencia RETURN
es la que efectivamente devuelve un valor desde la función. Existen varias consideraciones importantes:
- Una función debe contener al menos una sentencia
RETURN
- El valor retornado debe ser compatible con el tipo declarado
- La ejecución de la función termina inmediatamente cuando se encuentra una sentencia
RETURN
CREATE FUNCTION clasificar_temperatura(temp DECIMAL)
RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
IF temp < 0 THEN
RETURN 'Congelado';
ELSEIF temp < 10 THEN
RETURN 'Muy frío';
ELSEIF temp < 20 THEN
RETURN 'Frío';
ELSEIF temp < 30 THEN
RETURN 'Templado';
ELSE
RETURN 'Caluroso';
END IF;
END;
Conversión implícita y explícita de tipos
En ocasiones, el valor que queremos retornar no coincide exactamente con el tipo declarado. SQL intentará realizar conversiones implícitas cuando sea posible:
CREATE FUNCTION sumar_uno(num INT)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
-- Conversión implícita de INT a DECIMAL
RETURN num + 1;
END;
Sin embargo, es recomendable realizar conversiones explícitas para evitar comportamientos inesperados:
CREATE FUNCTION formatear_precio(precio DECIMAL(10,2))
RETURNS VARCHAR(50)
DETERMINISTIC
BEGIN
-- Conversión explícita de DECIMAL a VARCHAR
RETURN CONCAT(CAST(precio AS CHAR), ' €');
END;
Retorno de valores NULL
Las funciones UDF pueden devolver valores NULL
, lo que resulta útil para manejar casos especiales o errores:
CREATE FUNCTION dividir_seguro(numerador DECIMAL, denominador DECIMAL)
RETURNS DECIMAL
DETERMINISTIC
BEGIN
IF denominador = 0 THEN
RETURN NULL;
ELSE
RETURN numerador / denominador;
END IF;
END;
Retorno de múltiples valores mediante tipos compuestos
En PostgreSQL, podemos devolver múltiples valores utilizando tipos compuestos:
CREATE TYPE info_producto AS (
nombre VARCHAR(100),
precio DECIMAL(10,2),
stock INT
);
CREATE OR REPLACE FUNCTION obtener_info_producto(prod_id INT)
RETURNS info_producto AS
$$
DECLARE
resultado info_producto;
BEGIN
SELECT nombre_producto, precio, cantidad_stock
INTO resultado.nombre, resultado.precio, resultado.stock
FROM productos
WHERE producto_id = prod_id;
RETURN resultado;
END;
$$ LANGUAGE plpgsql;
Para usar esta función:
SELECT * FROM obtener_info_producto(123);
Retorno de conjuntos de resultados (table functions)
Las funciones también pueden devolver conjuntos completos de resultados, lo que las convierte en funciones de tabla:
En PostgreSQL:
CREATE OR REPLACE FUNCTION productos_por_categoria(cat_id INT)
RETURNS TABLE (
id INT,
nombre VARCHAR(100),
precio DECIMAL(10,2)
) AS
$$
BEGIN
RETURN QUERY
SELECT producto_id, nombre_producto, precio
FROM productos
WHERE categoria_id = cat_id;
END;
$$ LANGUAGE plpgsql;
En MySQL:
CREATE FUNCTION productos_categoria(cat_id INT)
RETURNS TEXT
DETERMINISTIC
BEGIN
DECLARE resultado TEXT DEFAULT '';
DECLARE prod_nombre VARCHAR(100);
DECLARE prod_precio DECIMAL(10,2);
DECLARE fin_cursor BOOLEAN DEFAULT FALSE;
DECLARE cursor_productos CURSOR FOR
SELECT nombre_producto, precio
FROM productos
WHERE categoria_id = cat_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET fin_cursor = TRUE;
OPEN cursor_productos;
recorrer: LOOP
FETCH cursor_productos INTO prod_nombre, prod_precio;
IF fin_cursor THEN
LEAVE recorrer;
END IF;
SET resultado = CONCAT(resultado, prod_nombre, ': ', prod_precio, '€; ');
END LOOP;
CLOSE cursor_productos;
RETURN resultado;
END;
Variables de salida vs. valores de retorno
Es importante distinguir entre el valor de retorno de una función y los parámetros de salida que pueden tener los procedimientos almacenados:
-- Función con valor de retorno
CREATE FUNCTION calcular_total(subtotal DECIMAL, impuesto DECIMAL)
RETURNS DECIMAL
DETERMINISTIC
BEGIN
RETURN subtotal + (subtotal * impuesto / 100);
END;
-- Procedimiento con parámetros de salida (no es una función)
CREATE PROCEDURE calcular_totales(
IN subtotal DECIMAL,
IN impuesto DECIMAL,
OUT total DECIMAL,
OUT solo_impuesto DECIMAL
)
BEGIN
SET solo_impuesto = subtotal * impuesto / 100;
SET total = subtotal + solo_impuesto;
END;
Optimización del retorno de valores
Para mejorar el rendimiento, especialmente en funciones que devuelven grandes conjuntos de datos, podemos aplicar algunas técnicas:
- Retorno temprano: Devolver resultados tan pronto como sea posible
- Filtrado eficiente: Aplicar filtros antes de procesar grandes volúmenes de datos
- Uso de índices: Asegurar que las consultas dentro de la función utilicen índices
CREATE FUNCTION buscar_cliente(id_cliente INT)
RETURNS VARCHAR(100)
READS SQL DATA
BEGIN
DECLARE nombre_cliente VARCHAR(100);
-- Retorno temprano si el ID es inválido
IF id_cliente <= 0 THEN
RETURN NULL;
END IF;
SELECT nombre INTO nombre_cliente
FROM clientes
WHERE cliente_id = id_cliente
LIMIT 1; -- Optimización: solo necesitamos un registro
RETURN nombre_cliente;
END;
Captura y manejo de errores en el retorno
Podemos implementar mecanismos para capturar errores y devolver valores apropiados:
CREATE FUNCTION calcular_ratio_seguro(valor1 INT, valor2 INT)
RETURNS DECIMAL(10,2)
BEGIN
DECLARE resultado DECIMAL(10,2);
-- Manejo de error para división por cero
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
RETURN -1; -- Código de error
END;
IF valor2 = 0 THEN
SIGNAL SQLSTATE '22012' -- Estado SQL para división por cero
SET MESSAGE_TEXT = 'División por cero no permitida';
END IF;
SET resultado = valor1 / valor2;
RETURN resultado;
END;
El manejo adecuado del retorno de valores es esencial para crear funciones UDF robustas y útiles. Una función bien diseñada debe devolver resultados predecibles y manejar correctamente los casos especiales, proporcionando así una interfaz confiable para los desarrolladores que la utilizan en sus consultas SQL.
Funciones vs Procedimientos almacenados
Las bases de datos modernas ofrecen dos mecanismos principales para encapsular lógica de programación: funciones y procedimientos almacenados. Aunque ambos permiten ejecutar código SQL dentro del motor de la base de datos, existen diferencias fundamentales en su propósito, estructura y uso.
Diferencias estructurales
La distinción más evidente entre funciones y procedimientos almacenados radica en su estructura y comportamiento:
- Funciones: Están diseñadas para calcular y devolver un valor (o conjunto de valores) que puede utilizarse directamente en una expresión SQL.
- Procedimientos: Están orientados a ejecutar una serie de operaciones que pueden incluir modificaciones en la base de datos, sin necesidad de devolver un valor.
Veamos cómo se refleja esta diferencia en la sintaxis:
Función en MySQL:
CREATE FUNCTION calcular_edad(fecha_nacimiento DATE)
RETURNS INT
DETERMINISTIC
BEGIN
RETURN TIMESTAMPDIFF(YEAR, fecha_nacimiento, CURDATE());
END;
Procedimiento en MySQL:
CREATE PROCEDURE actualizar_inventario(
IN producto_id INT,
IN cantidad INT
)
BEGIN
UPDATE productos
SET stock = stock - cantidad
WHERE id = producto_id;
-- No hay sentencia RETURN
END;
Contexto de uso
El contexto en el que se pueden utilizar marca otra diferencia significativa:
- Funciones: Pueden utilizarse en consultas SELECT, dentro de expresiones, cláusulas WHERE, ORDER BY, etc.
- Procedimientos: Se ejecutan mediante la sentencia CALL y no pueden formar parte de expresiones SQL.
Ejemplos de uso:
-- Uso de función en una consulta
SELECT
nombre,
fecha_nacimiento,
calcular_edad(fecha_nacimiento) AS edad
FROM clientes
WHERE calcular_edad(fecha_nacimiento) >= 18;
-- Llamada a un procedimiento
CALL actualizar_inventario(101, 5);
Parámetros y valores de retorno
La gestión de parámetros y valores de retorno constituye otra diferencia clave:
Funciones:
Deben retornar un valor mediante la sentencia RETURN
Solo admiten parámetros de entrada (IN)
El tipo de retorno debe declararse explícitamente
Procedimientos:
No retornan valores (aunque pueden usar parámetros de salida)
Admiten tres tipos de parámetros: entrada (IN), salida (OUT) y entrada-salida (INOUT)
No requieren declaración de tipo de retorno
Ejemplo de procedimiento con parámetros de salida:
CREATE PROCEDURE calcular_estadisticas_ventas(
IN fecha_inicio DATE,
IN fecha_fin DATE,
OUT total_ventas DECIMAL(10,2),
OUT num_transacciones INT
)
BEGIN
SELECT
SUM(monto),
COUNT(*)
INTO
total_ventas,
num_transacciones
FROM ventas
WHERE fecha BETWEEN fecha_inicio AND fecha_fin;
END;
Para usar este procedimiento:
CALL calcular_estadisticas_ventas('2023-01-01', '2023-12-31', @total, @num);
SELECT @total AS total_ventas, @num AS transacciones;
Transacciones y control de flujo
Tanto funciones como procedimientos pueden contener estructuras de control de flujo (IF, CASE, WHILE, etc.), pero existen diferencias en cuanto al manejo de transacciones:
- Procedimientos: Tienen mayor flexibilidad para manejar transacciones. Pueden iniciar, confirmar o revertir transacciones explícitamente.
- Funciones: Generalmente tienen restricciones más estrictas respecto a las operaciones que pueden realizar dentro de transacciones.
Ejemplo de procedimiento con manejo de transacciones:
CREATE PROCEDURE transferir_fondos(
IN cuenta_origen INT,
IN cuenta_destino INT,
IN monto DECIMAL(10,2),
OUT resultado VARCHAR(100)
)
BEGIN
DECLARE saldo_actual DECIMAL(10,2);
-- Iniciar transacción
START TRANSACTION;
-- Verificar saldo suficiente
SELECT saldo INTO saldo_actual
FROM cuentas
WHERE cuenta_id = cuenta_origen;
IF saldo_actual < monto THEN
SET resultado = 'Saldo insuficiente';
ROLLBACK;
ELSE
-- Restar de cuenta origen
UPDATE cuentas
SET saldo = saldo - monto
WHERE cuenta_id = cuenta_origen;
-- Sumar a cuenta destino
UPDATE cuentas
SET saldo = saldo + monto
WHERE cuenta_id = cuenta_destino;
SET resultado = 'Transferencia exitosa';
COMMIT;
END IF;
END;
Operaciones permitidas
Las operaciones que pueden realizar también difieren:
Funciones: Están más limitadas en cuanto a las operaciones que pueden ejecutar:
En MySQL, por defecto no pueden modificar datos (INSERT, UPDATE, DELETE)
Deben declararse con características específicas (como DETERMINISTIC, NO SQL, etc.)
No pueden ejecutar sentencias de control de transacciones
Procedimientos: Tienen menos restricciones:
Pueden ejecutar cualquier tipo de sentencia SQL
Pueden modificar datos libremente
Pueden controlar transacciones
Rendimiento y optimización
Desde el punto de vista del rendimiento:
- Funciones: Al poder utilizarse en consultas, el optimizador de consultas puede trabajar con ellas, pero pueden afectar negativamente al rendimiento si no están bien diseñadas.
- Procedimientos: Al ejecutarse de forma independiente, tienen menos impacto en la optimización de consultas, pero pueden ser más eficientes para operaciones por lotes.
Casos de uso típicos
Cada uno tiene escenarios donde resulta más apropiado:
Funciones son ideales para:
- Cálculos reutilizables (impuestos, descuentos, edades)
- Transformaciones de datos (formateo, conversiones)
- Validaciones que devuelven un resultado
- Lógica de negocio que se usa en consultas
-- Función para calcular precio con descuento
CREATE FUNCTION precio_con_descuento(
precio DECIMAL(10,2),
descuento_porcentaje DECIMAL(5,2)
)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
RETURN precio - (precio * descuento_porcentaje / 100);
END;
-- Uso en una consulta
SELECT
nombre_producto,
precio,
precio_con_descuento(precio, 15) AS precio_oferta
FROM productos;
Procedimientos son ideales para:
- Operaciones que modifican datos (actualizaciones masivas)
- Procesos ETL (Extract, Transform, Load)
- Operaciones que requieren múltiples pasos
- Tareas administrativas
-- Procedimiento para actualizar precios por categoría
CREATE PROCEDURE actualizar_precios_categoria(
IN categoria_id INT,
IN porcentaje_aumento DECIMAL(5,2)
)
BEGIN
UPDATE productos
SET precio = precio * (1 + porcentaje_aumento/100)
WHERE categoria_id = categoria_id;
SELECT CONCAT('Precios actualizados: ', ROW_COUNT(), ' productos') AS resultado;
END;
Diferencias específicas en MySQL y PostgreSQL
Existen algunas diferencias en la implementación entre estos sistemas:
MySQL:
- Las funciones requieren especificar características como DETERMINISTIC, NO SQL, etc.
- Los procedimientos utilizan delimitadores alternativos durante su creación
PostgreSQL:
- Utiliza el mismo comando CREATE FUNCTION tanto para funciones como para procedimientos
- Desde PostgreSQL 11, introduce CREATE PROCEDURE específicamente
- Usa el lenguaje de procedimientos PL/pgSQL por defecto
Ejemplo en PostgreSQL:
-- Función en PostgreSQL
CREATE OR REPLACE FUNCTION calcular_impuesto(subtotal DECIMAL)
RETURNS DECIMAL AS
$$
BEGIN
RETURN subtotal * 0.21;
END;
$$ LANGUAGE plpgsql;
-- Procedimiento en PostgreSQL (desde v11)
CREATE OR REPLACE PROCEDURE registrar_venta(
cliente_id INT,
producto_id INT,
cantidad INT
)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO ventas (cliente_id, producto_id, cantidad, fecha)
VALUES (cliente_id, producto_id, cantidad, CURRENT_DATE);
UPDATE inventario
SET stock = stock - cantidad
WHERE producto_id = registrar_venta.producto_id;
COMMIT;
END;
$$;
Tabla comparativa
Característica | Funciones | Procedimientos |
---|---|---|
Propósito principal | Calcular y retornar valores | Ejecutar operaciones |
Uso en consultas | Sí (SELECT, WHERE, etc.) | No |
Forma de ejecución | Dentro de expresiones SQL | Mediante CALL |
Retorno de valores | Obligatorio (RETURN) | No retornan valores directamente |
Parámetros | Solo de entrada (IN) | Entrada (IN), salida (OUT), entrada-salida (INOUT) |
Modificación de datos | Limitada (según configuración) | Sin restricciones |
Manejo de transacciones | Limitado | Completo |
Uso típico | Cálculos, transformaciones | Procesos, actualizaciones masivas |
¿Cuándo elegir uno u otro?
La elección entre función y procedimiento debe basarse en:
- Propósito: ¿Necesitas calcular un valor o ejecutar una operación?
- Contexto de uso: ¿Se utilizará dentro de consultas o como una operación independiente?
- Complejidad: ¿Implica múltiples pasos, transacciones o modificaciones de datos?
- Parámetros: ¿Necesitas parámetros de salida además del valor de retorno?
-- Ejemplo: Función para validación
CREATE FUNCTION es_email_valido(email VARCHAR(255))
RETURNS BOOLEAN
DETERMINISTIC
BEGIN
RETURN email REGEXP '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}$';
END;
-- Ejemplo: Procedimiento para proceso complejo
CREATE PROCEDURE procesar_pedido(
IN pedido_id INT,
OUT resultado VARCHAR(100)
)
BEGIN
DECLARE items_disponibles BOOLEAN DEFAULT TRUE;
-- Verificar stock
SELECT NOT EXISTS (
SELECT 1 FROM items_pedido ip
JOIN productos p ON ip.producto_id = p.id
WHERE ip.pedido_id = pedido_id
AND ip.cantidad > p.stock
) INTO items_disponibles;
IF items_disponibles THEN
START TRANSACTION;
-- Actualizar inventario
UPDATE productos p
JOIN items_pedido ip ON p.id = ip.producto_id
SET p.stock = p.stock - ip.cantidad
WHERE ip.pedido_id = pedido_id;
-- Marcar pedido como procesado
UPDATE pedidos
SET estado = 'Procesado', fecha_proceso = NOW()
WHERE id = pedido_id;
COMMIT;
SET resultado = 'Pedido procesado correctamente';
ELSE
SET resultado = 'Stock insuficiente para algunos productos';
END IF;
END;
Entender las diferencias entre funciones y procedimientos almacenados permite a los desarrolladores SQL elegir la herramienta adecuada para cada tarea, mejorando tanto la estructura como el rendimiento de sus aplicaciones de base de datos.
Otras lecciones de SQL
Accede a todas las lecciones de SQL y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Sql
Introducción Y Entorno
Ddl Y Dml
Introducción Y Entorno
Instalación De Mysql
Introducción Y Entorno
Instalación De Postgresql
Introducción Y Entorno
Tipos De Datos
Introducción Y Entorno
Bases De Datos Y Tablas
Introducción Y Entorno
Sistemas De Gestión De Bases De Datos
Introducción Y Entorno
Tipos De Bases De Datos
Introducción Y Entorno
Creación De Bases De Datos Y Tablas: Create Database, Create Table
Sintaxis Dml Crud
Consultas Básicas De Selección: Select Y Where
Sintaxis Dml Crud
Inserción De Datos: Insert Into
Sintaxis Dml Crud
Actualización De Datos: Update
Sintaxis Dml Crud
Eliminación De Datos: Delete
Sintaxis Dml Crud
Introducción A Dml
Sintaxis Dml Crud
Consultar Datos: Select
Sintaxis Dml Crud
Clasificación De Resultados Con Order By
Filtros Y Clasificación
Filtrado De Valores Únicos Con Distinct
Filtros Y Clasificación
Paginación Con Limit Y Offset
Filtros Y Clasificación
Alterar La Estructura De Tablas Existentes: Alter Table
Sintaxis Ddl
Renombrar Tablas Y Bases De Datos: Rename
Sintaxis Ddl
Vaciar Tablas Y Bases De Datos: Drop
Sintaxis Ddl
Uso De Funciones Agregadas: Count, Sum, Avg, Max, Min
Funciones Y Agrupación
Agrupación De Resultados Con Group By
Funciones Y Agrupación
Filtrado De Grupos De Resultados Con Having
Funciones Y Agrupación
Funciones Numéricas Y Matemáticas
Funciones Y Agrupación
Funciones De Fecha Y Hora
Funciones Y Agrupación
Funciones De Texto
Funciones Y Agrupación
Many To One
Asociaciones Entre Tablas
One To Many
Asociaciones Entre Tablas
One To One
Asociaciones Entre Tablas
Many To Many
Asociaciones Entre Tablas
Relaciones Entre Tablas
Joins Y Subqueries
Uso De Inner Join, Left Join, Right Join, Full Join
Joins Y Subqueries
Creación Y Uso De Subqueries
Joins Y Subqueries
Left Join Y Right Join
Joins Y Subqueries
Full Join
Joins Y Subqueries
Cross Join Y Self Join
Joins Y Subqueries
Optimización De Consultas
Sintaxis Avanzada
Uso De Índices Y Particiones
Sintaxis Avanzada
Uso De Vistas
Sintaxis Avanzada
Triggers Y Eventos
Sintaxis Avanzada
Particiones
Sintaxis Avanzada
Restricciones E Integridad
Sintaxis Avanzada
Transacciones
Sintaxis Avanzada
Vistas Materializadas
Sintaxis Avanzada
Rollback
Sintaxis Avanzada
Vistas Con Create View
Sintaxis Avanzada
Principios Acid
Sintaxis Avanzada
Manejo De Errores Y Excepciones
Sintaxis Avanzada
Funciones Ventana
Sintaxis Avanzada
Índices
Sintaxis Avanzada
Expresiones De Tabla Comunes (Cte) Con With
Sintaxis Avanzada
Creación Y Uso De Funciones
Programación En Sql
Creación Y Uso De Procedimientos Almacenados
Programación En Sql
Variables Y Control De Flujo
Programación En Sql
Creación Y Manejo De Usuarios Y Roles
Seguridad Y Administración
Asignación Y Gestión De Permisos
Seguridad Y Administración
Copias De Seguridad Y Restauración De Bases De Datos
Seguridad Y Administración
Ejercicios de programación de SQL
Evalúa tus conocimientos de esta lección Creación y uso de funciones con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Tipos de datos
Inserción de datos: INSERT INTO
Filtrado de grupos de resultados con HAVING
Uso de índices y particiones
Renombrar tablas y bases de datos: RENAME
Uso de vistas
Uso de INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN
Agrupación de resultados con GROUP BY
Creación y uso de subqueries
Sentencias INSERT
Copias de seguridad y restauración de bases de datos
Uso de INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN
Instalación de MySQL
Relaciones entre tablas
Eliminación de datos: DELETE
Creación de bases de datos y tablas: CREATE DATABASE, CREATE TABLE
Creación y uso de funciones
Creación de tablas e inserción de datos con SQL
Uso de funciones agregadas: COUNT, SUM, AVG, MAX, MIN
Optimización de consultas
Introducción a SQL
Triggers y eventos
Clasificación de resultados con ORDER BY
Alterar la estructura de tablas existentes: ALTER TABLE
Eliminación de datos: DELETE
Instalación de PostgreSQL
Creación y uso de procedimientos almacenados
Consultas básicas de selección: SELECT y WHERE
Vaciar tablas y bases de datos: DROP
Actualización de datos: UPDATE
Creación y manejo de usuarios y roles
Consultas básicas de selección SELECT y WHERE
Creación de bases de datos y tablas
Bases de datos y tablas
Actualización de datos: UPDATE
Relaciones entre tablas
Filtrado de valores únicos con DISTINCT
Asignación y gestión de permisos
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender qué son las funciones definidas por el usuario (UDF) y sus beneficios.
- Aprender la sintaxis básica para crear funciones UDF en MySQL y PostgreSQL.
- Diferenciar entre funciones escalares, de tabla y de agregado.
- Entender cómo declarar y manejar el retorno de valores en funciones.
- Conocer las diferencias estructurales y de uso entre funciones y procedimientos almacenados.