Procedimientos almacenados en MySql: qué son y cómo crearlos

D
DanisCh
(Actualizado: ) • 17 min de lectura
Procedimientos almacenados en MySql: qué son y cómo crearlos
SQL Conceptos de Base de Datos

Conforme tus aplicaciones crecen, empiezas a encontrar operaciones que se repiten constantemente y que implican varias sentencias SQL seguidas: registrar una venta y descontar el stock al mismo tiempo, validar datos antes de insertarlos, calcular estadísticas complejas que se consultan desde distintos puntos del sistema.

Los procedimientos almacenados (stored procedures) son la herramienta de SQL que te permite guardar ese conjunto de instrucciones en la base de datos con un nombre, y ejecutarlas todas de una sola llamada. Son como funciones, pero que viven dentro del motor de base de datos.

En este artículo aprenderás qué son, cómo crearlos paso a paso en MySQL, cómo usar parámetros de entrada y salida, estructuras de control, manejo de errores y cuándo tiene sentido usarlos.

Qué es un procedimiento almacenado

Un procedimiento almacenado es un bloque de código SQL con un nombre que se guarda en la base de datos y se puede ejecutar cuando sea necesario. A diferencia de una consulta normal que se envía desde la aplicación cada vez que se necesita, el procedimiento ya está compilado y optimizado dentro del servidor de base de datos.

Sus características principales son:

  • Se guarda en el servidor de base de datos, no en el código de la aplicación.
  • Se puede llamar desde cualquier cliente: aplicación Java, Python, PHP, o directamente desde un cliente SQL.
  • Acepta parámetros de entrada, de salida o ambos.
  • Puede contener lógica condicional, bucles, variables y manejo de errores.
  • Reduce el tráfico de red: en lugar de enviar múltiples sentencias SQL, se envía una sola llamada.
  • Centraliza la lógica de negocio en la base de datos.

Diferencia entre procedimiento y función

En MySQL existen los procedimientos almacenados y las funciones almacenadas. Aunque son parecidos, tienen diferencias importantes:

CaracterísticaProcedimientoFunción
Devuelve valoresA través de parámetros OUTCon RETURN (un solo valor)
Se puede usar en SELECTNoSí
Cómo se llamaCon CALLComo parte de una expresión
Puede modificar datosSíGeneralmente no (depende del tipo)
Manejo de transaccionesSíNo

En este artículo nos enfocamos en los procedimientos. Las funciones almacenadas siguen una lógica similar pero con las restricciones de la tabla anterior.

El delimitador: por qué es necesario

Antes de crear tu primer procedimiento, necesitas entender el concepto de delimitador. Normalmente MySQL usa el punto y coma ; para separar sentencias. Pero dentro de un procedimiento hay muchas sentencias con punto y coma, y MySQL las ejecutaría antes de terminar de leer el procedimiento completo.

La solución es cambiar temporalmente el delimitador a otro símbolo, definir el procedimiento completo, y luego restaurar el delimitador original.

-- Cambiar el delimitador a //
DELIMITER //

CREATE PROCEDURE mi_procedimiento()
BEGIN
  SELECT 'Hola desde el procedimiento';
  SELECT CURDATE() AS fecha_actual;
END //

-- Restaurar el delimitador original
DELIMITER ;

El símbolo // es el más común, aunque también verás $$ en muchos ejemplos. Lo importante es que sea diferente al punto y coma.

Tu primer procedimiento almacenado

Usaremos el mismo esquema de tienda online del artículo anterior para todos los ejemplos:

-- Tablas: clientes, productos, pedidos, detalle_pedidos

Empecemos con un procedimiento simple que lista todos los productos:

DELIMITER //

CREATE PROCEDURE sp_listar_productos()
BEGIN
  SELECT
    id,
    nombre,
    precio,
    stock,
    categoria
  FROM productos
  ORDER BY nombre;
END //

DELIMITER ;

Para ejecutarlo se usa la sentencia CALL:

CALL sp_listar_productos();

Nota la convención de nombrar los procedimientos con el prefijo sp_ (stored procedure). Es una práctica común que hace fácil identificarlos en el catálogo de la base de datos.

Parámetros de entrada: IN

Los parámetros IN permiten pasar valores al procedimiento desde fuera. Son los más comunes y funcionan como los argumentos de una función.

DELIMITER //

CREATE PROCEDURE sp_buscar_por_categoria(
  IN p_categoria VARCHAR(50)
)
BEGIN
  SELECT
    id,
    nombre,
    precio,
    stock
  FROM productos
  WHERE categoria = p_categoria
  ORDER BY precio ASC;
END //

DELIMITER ;
-- Llamar con distintos valores
CALL sp_buscar_por_categoria('Electrónica');
CALL sp_buscar_por_categoria('Periféricos');
CALL sp_buscar_por_categoria('Audio');

Es buena práctica usar un prefijo para los parámetros (como p_) para distinguirlos de los nombres de columnas y evitar ambigüedades.

Múltiples parámetros de entrada

DELIMITER //

CREATE PROCEDURE sp_productos_por_rango_precio(
  IN p_precio_min DECIMAL(10, 2),
  IN p_precio_max DECIMAL(10, 2),
  IN p_categoria  VARCHAR(50)
)
BEGIN
  SELECT
    id,
    nombre,
    precio,
    stock,
    categoria
  FROM productos
  WHERE precio BETWEEN p_precio_min AND p_precio_max
    AND (p_categoria IS NULL OR categoria = p_categoria)
  ORDER BY precio;
END //

DELIMITER ;
-- Buscar productos entre 50 y 200 dólares en todas las categorías
CALL sp_productos_por_rango_precio(50.00, 200.00, NULL);

-- Buscar solo electrónica entre 300 y 1500 dólares
CALL sp_productos_por_rango_precio(300.00, 1500.00, 'Electrónica');

Parámetros de salida: OUT

Los parámetros OUT permiten que el procedimiento devuelva valores a quien lo llamó. Se definen con la palabra clave OUT y dentro del procedimiento se les asigna un valor.

DELIMITER //

CREATE PROCEDURE sp_contar_productos(
  IN  p_categoria VARCHAR(50),
  OUT p_total     INT,
  OUT p_valor_inventario DECIMAL(10, 2)
)
BEGIN
  SELECT
    COUNT(*),
    SUM(precio * stock)
  INTO p_total, p_valor_inventario
  FROM productos
  WHERE p_categoria IS NULL OR categoria = p_categoria;
END //

DELIMITER ;
-- Llamar y capturar los valores de salida en variables de sesión
CALL sp_contar_productos('Electrónica', @total, @valor);

-- Leer los valores retornados
SELECT @total AS productos_electronicos, @valor AS valor_inventario;

-- Para todas las categorías
CALL sp_contar_productos(NULL, @total, @valor);
SELECT @total AS total_productos, @valor AS valor_total_inventario;

Parámetros de entrada y salida: INOUT

Un parámetro INOUT funciona en ambas direcciones: entra con un valor y puede modificarse para devolver un resultado diferente.

DELIMITER //

CREATE PROCEDURE sp_aplicar_descuento(
  INOUT p_precio  DECIMAL(10, 2),
  IN    p_porcentaje DECIMAL(5, 2)
)
BEGIN
  SET p_precio = p_precio - (p_precio * p_porcentaje / 100);
  SET p_precio = ROUND(p_precio, 2);
END //

DELIMITER ;
-- El precio entra como 1299.99 y sale con el descuento aplicado
SET @precio = 1299.99;
CALL sp_aplicar_descuento(@precio, 15);
SELECT @precio AS precio_con_descuento; -- 1104.99

Variables locales

Dentro de un procedimiento puedes declarar variables locales con DECLARE. Solo existen durante la ejecución del procedimiento y no son visibles desde fuera.

DELIMITER //

CREATE PROCEDURE sp_resumen_cliente(
  IN  p_id_cliente INT
)
BEGIN
  -- Declarar variables locales
  DECLARE v_nombre        VARCHAR(100);
  DECLARE v_total_pedidos INT;
  DECLARE v_gasto_total   DECIMAL(10, 2);
  DECLARE v_ultimo_pedido DATE;

  -- Obtener datos del cliente
  SELECT nombre INTO v_nombre
  FROM clientes
  WHERE id = p_id_cliente;

  -- Calcular estadísticas
  SELECT
    COUNT(DISTINCT p.id),
    SUM(dp.cantidad * dp.precio_unit),
    MAX(p.fecha)
  INTO
    v_total_pedidos,
    v_gasto_total,
    v_ultimo_pedido
  FROM pedidos p
  JOIN detalle_pedidos dp ON dp.id_pedido = p.id
  WHERE p.id_cliente = p_id_cliente;

  -- Mostrar el resumen
  SELECT
    v_nombre                                       AS cliente,
    COALESCE(v_total_pedidos, 0)                   AS total_pedidos,
    COALESCE(v_gasto_total, 0.00)                  AS gasto_total,
    COALESCE(v_ultimo_pedido, 'Sin pedidos')        AS ultimo_pedido;
END //

DELIMITER ;

CALL sp_resumen_cliente(1);
CALL sp_resumen_cliente(3);

Estructuras de control: IF y CASE

Los procedimientos pueden contener lógica condicional igual que cualquier lenguaje de programación.

IF / ELSEIF / ELSE

DELIMITER //

CREATE PROCEDURE sp_clasificar_cliente(
  IN  p_id_cliente INT,
  OUT p_segmento   VARCHAR(20)
)
BEGIN
  DECLARE v_gasto DECIMAL(10, 2);

  SELECT COALESCE(SUM(dp.cantidad * dp.precio_unit), 0)
  INTO v_gasto
  FROM pedidos p
  JOIN detalle_pedidos dp ON dp.id_pedido = p.id
  WHERE p.id_cliente = p_id_cliente
    AND p.estado = 'completado';

  IF v_gasto >= 3000 THEN
    SET p_segmento = 'VIP';
  ELSEIF v_gasto >= 1000 THEN
    SET p_segmento = 'Premium';
  ELSEIF v_gasto > 0 THEN
    SET p_segmento = 'Estándar';
  ELSE
    SET p_segmento = 'Inactivo';
  END IF;
END //

DELIMITER ;

CALL sp_clasificar_cliente(1, @segmento);
SELECT @segmento;

CASE

DELIMITER //

CREATE PROCEDURE sp_estado_stock(
  IN  p_id_producto INT,
  OUT p_estado      VARCHAR(30)
)
BEGIN
  DECLARE v_stock INT;

  SELECT stock INTO v_stock
  FROM productos
  WHERE id = p_id_producto;

  CASE
    WHEN v_stock = 0     THEN SET p_estado = 'Agotado';
    WHEN v_stock < 10    THEN SET p_estado = 'Crítico';
    WHEN v_stock < 50    THEN SET p_estado = 'Bajo';
    WHEN v_stock < 100   THEN SET p_estado = 'Normal';
    ELSE                      SET p_estado = 'Abundante';
  END CASE;
END //

DELIMITER ;

CALL sp_estado_stock(1, @estado);
SELECT @estado;

Bucles: WHILE, REPEAT y LOOP

Los procedimientos admiten tres tipos de bucles para repetir instrucciones.

WHILE

DELIMITER //

CREATE PROCEDURE sp_generar_serie(
  IN p_inicio INT,
  IN p_fin    INT
)
BEGIN
  DECLARE v_actual INT DEFAULT p_inicio;

  -- Tabla temporal para guardar los resultados
  CREATE TEMPORARY TABLE IF NOT EXISTS serie (numero INT);
  TRUNCATE TABLE serie;

  WHILE v_actual <= p_fin DO
    INSERT INTO serie VALUES (v_actual);
    SET v_actual = v_actual + 1;
  END WHILE;

  SELECT numero FROM serie;
  DROP TEMPORARY TABLE serie;
END //

DELIMITER ;

CALL sp_generar_serie(1, 10);

REPEAT (equivalente a do-while)

DELIMITER //

CREATE PROCEDURE sp_sumar_hasta(
  IN  p_limite INT,
  OUT p_suma   INT
)
BEGIN
  DECLARE v_contador INT DEFAULT 1;
  SET p_suma = 0;

  REPEAT
    SET p_suma = p_suma + v_contador;
    SET v_contador = v_contador + 1;
  UNTIL v_contador > p_limite
  END REPEAT;
END //

DELIMITER ;

CALL sp_sumar_hasta(100, @resultado);
SELECT @resultado; -- 5050

LOOP con LEAVE (salida controlada)

DELIMITER //

CREATE PROCEDURE sp_buscar_primer_disponible(
  IN  p_categoria VARCHAR(50),
  OUT p_id_producto INT,
  OUT p_nombre      VARCHAR(100)
)
BEGIN
  DECLARE v_done    INT DEFAULT 0;
  DECLARE v_id      INT;
  DECLARE v_nombre  VARCHAR(100);
  DECLARE v_stock   INT;

  DECLARE cur CURSOR FOR
    SELECT id, nombre, stock
    FROM productos
    WHERE categoria = p_categoria
    ORDER BY stock DESC;

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = 1;

  SET p_id_producto = NULL;
  SET p_nombre = NULL;

  OPEN cur;

  busqueda: LOOP
    FETCH cur INTO v_id, v_nombre, v_stock;

    IF v_done = 1 THEN
      LEAVE busqueda;
    END IF;

    IF v_stock > 0 THEN
      SET p_id_producto = v_id;
      SET p_nombre = v_nombre;
      LEAVE busqueda;
    END IF;
  END LOOP busqueda;

  CLOSE cur;
END //

DELIMITER ;

CALL sp_buscar_primer_disponible('Electrónica', @id, @nombre);
SELECT @id, @nombre;

Cursores: recorrer resultados fila por fila

Un cursor te permite recorrer el resultado de una consulta fila por fila dentro de un procedimiento. Son útiles cuando necesitas procesar cada registro de forma individual.

DELIMITER //

CREATE PROCEDURE sp_actualizar_precios_categoria(
  IN p_categoria  VARCHAR(50),
  IN p_porcentaje DECIMAL(5, 2)
)
BEGIN
  DECLARE v_done      INT DEFAULT 0;
  DECLARE v_id        INT;
  DECLARE v_precio    DECIMAL(10, 2);
  DECLARE v_nuevo     DECIMAL(10, 2);
  DECLARE v_contador  INT DEFAULT 0;

  -- Declarar el cursor
  DECLARE cur CURSOR FOR
    SELECT id, precio
    FROM productos
    WHERE categoria = p_categoria;

  -- Handler para cuando no hay más filas
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = 1;

  OPEN cur;

  proceso: LOOP
    FETCH cur INTO v_id, v_precio;

    IF v_done THEN
      LEAVE proceso;
    END IF;

    SET v_nuevo = ROUND(v_precio * (1 + p_porcentaje / 100), 2);

    UPDATE productos SET precio = v_nuevo WHERE id = v_id;

    SET v_contador = v_contador + 1;
  END LOOP proceso;

  CLOSE cur;

  SELECT CONCAT(v_contador, ' productos actualizados en categoría: ', p_categoria) AS resultado;
END //

DELIMITER ;

-- Aumentar un 10% los precios de Electrónica
CALL sp_actualizar_precios_categoria('Electrónica', 10);

-- Reducir un 5% los precios de Periféricos
CALL sp_actualizar_precios_categoria('Periféricos', -5);

Manejo de errores con DECLARE HANDLER

Los procedimientos pueden capturar errores y reaccionar ante ellos de forma controlada usando DECLARE HANDLER.

DELIMITER //

CREATE PROCEDURE sp_registrar_pedido(
  IN  p_id_cliente  INT,
  IN  p_id_producto INT,
  IN  p_cantidad    INT,
  OUT p_resultado   VARCHAR(100)
)
BEGIN
  DECLARE v_stock       INT;
  DECLARE v_precio      DECIMAL(10, 2);
  DECLARE v_id_pedido   INT;
  DECLARE v_error       INT DEFAULT 0;

  -- Capturar cualquier error SQL
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_error = 1;

  -- Iniciar transacción
  START TRANSACTION;

  -- Verificar stock disponible
  SELECT stock, precio
  INTO v_stock, v_precio
  FROM productos
  WHERE id = p_id_producto;

  IF v_stock IS NULL THEN
    SET p_resultado = 'Error: el producto no existe';
    ROLLBACK;
  ELSEIF v_stock < p_cantidad THEN
    SET p_resultado = CONCAT('Error: stock insuficiente. Disponible: ', v_stock);
    ROLLBACK;
  ELSE
    -- Crear el pedido
    INSERT INTO pedidos (id_cliente, fecha, estado)
    VALUES (p_id_cliente, CURDATE(), 'pendiente');

    SET v_id_pedido = LAST_INSERT_ID();

    -- Agregar el detalle
    INSERT INTO detalle_pedidos (id_pedido, id_producto, cantidad, precio_unit)
    VALUES (v_id_pedido, p_id_producto, p_cantidad, v_precio);

    -- Descontar el stock
    UPDATE productos
    SET stock = stock - p_cantidad
    WHERE id = p_id_producto;

    IF v_error THEN
      ROLLBACK;
      SET p_resultado = 'Error inesperado al registrar el pedido';
    ELSE
      COMMIT;
      SET p_resultado = CONCAT('Pedido #', v_id_pedido, ' registrado correctamente');
    END IF;
  END IF;
END //

DELIMITER ;

-- Registrar un pedido válido
CALL sp_registrar_pedido(2, 2, 3, @resultado);
SELECT @resultado;

-- Intentar pedir más de lo que hay en stock
CALL sp_registrar_pedido(1, 1, 9999, @resultado);
SELECT @resultado;

Procedimiento completo de ejemplo: proceso de ventas

Un procedimiento que integra todo lo aprendido: validaciones, transacciones, variables, condicionales y manejo de errores.

DELIMITER //

CREATE PROCEDURE sp_procesar_venta(
  IN  p_id_cliente  INT,
  IN  p_productos   JSON,
  OUT p_id_pedido   INT,
  OUT p_total       DECIMAL(10, 2),
  OUT p_mensaje     VARCHAR(200)
)
BEGIN
  DECLARE v_error       INT DEFAULT 0;
  DECLARE v_i           INT DEFAULT 0;
  DECLARE v_count       INT;
  DECLARE v_id_prod     INT;
  DECLARE v_cantidad    INT;
  DECLARE v_precio      DECIMAL(10, 2);
  DECLARE v_stock       INT;

  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
  BEGIN
    SET v_error = 1;
  END;

  SET p_id_pedido = 0;
  SET p_total = 0.00;
  SET p_mensaje = '';

  -- Verificar que el cliente existe
  IF NOT EXISTS (SELECT 1 FROM clientes WHERE id = p_id_cliente) THEN
    SET p_mensaje = 'Error: el cliente no existe';
    LEAVE sp_procesar_venta;
  END IF;

  START TRANSACTION;

  -- Crear el pedido
  INSERT INTO pedidos (id_cliente, fecha, estado)
  VALUES (p_id_cliente, CURDATE(), 'pendiente');

  SET p_id_pedido = LAST_INSERT_ID();

  -- Procesar cada producto del JSON
  SET v_count = JSON_LENGTH(p_productos);

  WHILE v_i < v_count DO
    SET v_id_prod  = JSON_UNQUOTE(JSON_EXTRACT(p_productos, CONCAT('$[', v_i, '].id')));
    SET v_cantidad = JSON_UNQUOTE(JSON_EXTRACT(p_productos, CONCAT('$[', v_i, '].cantidad')));

    -- Obtener precio y stock actuales
    SELECT precio, stock
    INTO v_precio, v_stock
    FROM productos
    WHERE id = v_id_prod;

    IF v_stock < v_cantidad THEN
      ROLLBACK;
      SET p_mensaje = CONCAT('Stock insuficiente para el producto ID: ', v_id_prod);
      SET p_id_pedido = 0;
      LEAVE sp_procesar_venta;
    END IF;

    -- Insertar detalle
    INSERT INTO detalle_pedidos (id_pedido, id_producto, cantidad, precio_unit)
    VALUES (p_id_pedido, v_id_prod, v_cantidad, v_precio);

    -- Actualizar stock
    UPDATE productos SET stock = stock - v_cantidad WHERE id = v_id_prod;

    -- Acumular total
    SET p_total = p_total + (v_precio * v_cantidad);
    SET v_i = v_i + 1;
  END WHILE;

  IF v_error THEN
    ROLLBACK;
    SET p_mensaje = 'Error inesperado durante el procesamiento';
    SET p_id_pedido = 0;
    SET p_total = 0.00;
  ELSE
    -- Actualizar estado del pedido
    UPDATE pedidos SET estado = 'completado' WHERE id = p_id_pedido;
    COMMIT;
    SET p_mensaje = CONCAT('Venta procesada. Pedido #', p_id_pedido,
                           '. Total: $', FORMAT(p_total, 2));
  END IF;

END //

DELIMITER ;

-- Llamada con un JSON de productos
CALL sp_procesar_venta(
  1,
  '[{"id": 2, "cantidad": 2}, {"id": 4, "cantidad": 1}]',
  @pedido, @total, @mensaje
);

SELECT @pedido AS id_pedido, @total AS total, @mensaje AS resultado;

Gestionar procedimientos almacenados

Ver los procedimientos existentes

-- Listar todos los procedimientos de la base de datos actual
SHOW PROCEDURE STATUS WHERE Db = 'tienda_java';

-- Ver el código fuente de un procedimiento
SHOW CREATE PROCEDURE sp_listar_productos;

-- Consultar desde el catálogo del sistema
SELECT routine_name, created, last_altered
FROM information_schema.routines
WHERE routine_type = 'PROCEDURE'
  AND routine_schema = 'tienda_java';

Modificar un procedimiento

MySQL no tiene ALTER PROCEDURE para cambiar el cuerpo del procedimiento. Para modificarlo hay que eliminarlo y recrearlo:

DROP PROCEDURE IF EXISTS sp_listar_productos;

DELIMITER //

CREATE PROCEDURE sp_listar_productos()
BEGIN
  SELECT id, nombre, precio, stock, categoria
  FROM productos
  WHERE stock > 0  -- nueva condición agregada
  ORDER BY nombre;
END //

DELIMITER ;

Eliminar un procedimiento

-- Eliminar un procedimiento
DROP PROCEDURE sp_listar_productos;

-- Eliminar solo si existe (evita error si no existe)
DROP PROCEDURE IF EXISTS sp_listar_productos;

Llamar procedimientos desde Java

Desde JDBC, los procedimientos almacenados se llaman usando CallableStatement:

import java.sql.*;

public class LlamarProcedimiento {
  public static void main(String[] args) {

    String url = "jdbc:mysql://localhost:3306/tienda_java?useSSL=false&serverTimezone=UTC";

    try (Connection con = DriverManager.getConnection(url, "root", "tu_password")) {

      // Llamar procedimiento con parámetros IN y OUT
      String sql = "{CALL sp_contar_productos(?, ?, ?)}";

      try (CallableStatement stmt = con.prepareCall(sql)) {

        // Parámetro IN
        stmt.setString(1, "Electrónica");

        // Registrar parámetros OUT
        stmt.registerOutParameter(2, Types.INTEGER);
        stmt.registerOutParameter(3, Types.DECIMAL);

        stmt.execute();

        // Leer los valores OUT
        int total  = stmt.getInt(2);
        double valor = stmt.getDouble(3);

        System.out.println("Productos electrónicos: " + total);
        System.out.printf("Valor del inventario: $%.2f%n", valor);
      }

    } catch (SQLException e) {
      System.out.println("Error: " + e.getMessage());
    }
  }
}

Cuándo usar procedimientos almacenados

Los procedimientos almacenados son una herramienta poderosa, pero no son siempre la mejor opción. Úsalos cuando:

  • Necesitas ejecutar varias sentencias SQL como una unidad atómica y quieres centralizar esa lógica en la base de datos.
  • La misma lógica se llama desde múltiples aplicaciones o lenguajes distintos. Un procedimiento en la base de datos es neutral al lenguaje.
  • Quieres reducir el tráfico de red entre la aplicación y el servidor de base de datos en operaciones que implican muchas sentencias.
  • Necesitas controlar el acceso a los datos sin exponer la estructura real de las tablas.
  • Tienes operaciones de mantenimiento periódico como limpiar registros antiguos, recalcular estadísticas o archivar datos.

Evítalos cuando:

  • La lógica de negocio cambia frecuentemente y prefieres que esté en el código de la aplicación donde es más fácil versionar y desplegar.
  • Tu equipo no tiene experiencia sólida en SQL procedural y el mantenimiento se vuelve costoso.
  • Usas un ORM como Hibernate o JPA, que gestiona el acceso a datos de forma más abstracta.
  • Necesitas escalar horizontalmente la base de datos, ya que los procedimientos almacenados dificultan algunas estrategias de escalabilidad.

Buenas prácticas

  • Usa el prefijo sp_ en todos los nombres para identificarlos fácilmente.
  • Usa el prefijo p_ en parámetros y v_ en variables locales para evitar conflictos con nombres de columnas.
  • Siempre usa transacciones cuando el procedimiento ejecuta más de una operación de escritura que debe ser atómica.
  • Documenta el propósito, los parámetros y el comportamiento esperado con comentarios dentro del procedimiento.
  • Maneja los errores explícitamente con DECLARE HANDLER en lugar de dejar que los errores propaguen de forma silenciosa.
  • Prueba cada procedimiento de forma aislada antes de integrarlo con la aplicación, usando distintos valores de entrada incluyendo casos límite y errores esperados.

Conclusión

Los procedimientos almacenados son una pieza clave del desarrollo con bases de datos relacionales. Te permiten encapsular lógica compleja en la capa de datos, reutilizarla desde cualquier aplicación y ejecutarla de forma eficiente y segura.

Dominar su sintaxis, los tipos de parámetros, las estructuras de control, los cursores y el manejo de errores te da un nivel de control sobre la base de datos que va mucho más allá de simples consultas SELECT. Son especialmente valiosos en sistemas donde la integridad de los datos es crítica y varias aplicaciones comparten el mismo motor de base de datos.

Para seguir profundizando en SQL, te recomendamos leer nuestros artículos sobre qué son las vistas en SQL y cuándo usarlas y sobre transacciones en SQL: qué son ACID y cómo usarlas correctamente, que complementan perfectamente lo que aprendiste aquí.

Etiquetas: SQL Mylsq

¿Te ha gustado esta entrada?

Compártela con tus compañeros para que también sigan aprendiendo.

Comunidad y Comentarios

0 COMENTARIOS

No hay comentarios todavía. Sé el primero en compartir tu opinión.

Escribe tu opinión
Respondiendo a