Sentencia CASE

La sentencia CASE proporciona una forma limpia de manejar múltiples condiciones. Hay dos formas: el CASE simple que compara un valor con opciones, y el CASE buscado que evalúa condiciones booleanas.

CASE simple

Compara una expresión con valores concretos:

CASE expresion
    WHEN valor1 THEN sentencias;
    WHEN valor2 THEN sentencias;
    ...
    ELSE sentencias;
END CASE;
DELIMITER //
 
CREATE PROCEDURE estado_pedido(IN ped_id INT)
BEGIN
    DECLARE v_estado VARCHAR(20);
    DECLARE v_descripcion VARCHAR(100);
 
    SELECT estado INTO v_estado FROM pedidos WHERE id = ped_id;
 
    CASE v_estado
        WHEN 'pendiente' THEN
            SET v_descripcion = 'El pedido está esperando ser procesado';
        WHEN 'enviado' THEN
            SET v_descripcion = 'El pedido está en camino';
        WHEN 'entregado' THEN
            SET v_descripcion = 'El pedido ha sido entregado';
        WHEN 'cancelado' THEN
            SET v_descripcion = 'El pedido fue cancelado';
        ELSE
            SET v_descripcion = 'Estado desconocido';
    END CASE;
 
    SELECT ped_id AS pedido, v_estado AS estado, v_descripcion AS descripcion;
END //
 
DELIMITER ;
CALL estado_pedido(1);
pedidoestadodescripcion
1entregadoEl pedido ha sido entregado
CALL estado_pedido(23);
pedidoestadodescripcion
23pendienteEl pedido está esperando ser procesado

CASE buscado

Evalúa condiciones booleanas independientes:

CASE
    WHEN condicion1 THEN sentencias;
    WHEN condicion2 THEN sentencias;
    ...
    ELSE sentencias;
END CASE;
DELIMITER //
 
CREATE PROCEDURE clasificar_cliente(IN cli_id INT)
BEGIN
    DECLARE v_nombre VARCHAR(100);
    DECLARE v_total_pedidos INT;
    DECLARE v_total_gastado DECIMAL(10,2);
    DECLARE v_clasificacion VARCHAR(20);
 
    SELECT nombre INTO v_nombre FROM clientes WHERE id = cli_id;
 
    SELECT COUNT(*), COALESCE(SUM(total), 0)
    INTO v_total_pedidos, v_total_gastado
    FROM pedidos WHERE cliente_id = cli_id;
 
    CASE
        WHEN v_total_gastado > 5000 THEN
            SET v_clasificacion = 'VIP';
        WHEN v_total_gastado > 2000 THEN
            SET v_clasificacion = 'Premium';
        WHEN v_total_gastado > 500 THEN
            SET v_clasificacion = 'Regular';
        WHEN v_total_pedidos > 0 THEN
            SET v_clasificacion = 'Nuevo';
        ELSE
            SET v_clasificacion = 'Sin compras';
    END CASE;
 
    SELECT v_nombre AS cliente,
           v_total_pedidos AS pedidos,
           v_total_gastado AS total_gastado,
           v_clasificacion AS clasificacion;
END //
 
DELIMITER ;
CALL clasificar_cliente(1);
clientepedidostotal_gastadoclasificacion
María33899.97Premium

CASE con múltiples sentencias

Cada rama WHEN puede contener múltiples sentencias:

DELIMITER //
 
CREATE PROCEDURE procesar_devolucion(IN ped_id INT)
BEGIN
    DECLARE v_estado VARCHAR(20);
    DECLARE v_mensaje VARCHAR(200);
 
    SELECT estado INTO v_estado FROM pedidos WHERE id = ped_id;
 
    CASE v_estado
        WHEN 'entregado' THEN
            UPDATE pedidos SET estado = 'cancelado' WHERE id = ped_id;
            SET v_mensaje = 'Devolución procesada correctamente';
        WHEN 'enviado' THEN
            UPDATE pedidos SET estado = 'cancelado' WHERE id = ped_id;
            SET v_mensaje = 'Envío interceptado y cancelado';
        WHEN 'pendiente' THEN
            UPDATE pedidos SET estado = 'cancelado' WHERE id = ped_id;
            SET v_mensaje = 'Pedido cancelado antes del envío';
        WHEN 'cancelado' THEN
            SET v_mensaje = 'El pedido ya estaba cancelado';
        ELSE
            SET v_mensaje = 'No se puede procesar la devolución';
    END CASE;
 
    SELECT v_mensaje AS resultado;
END //
 
DELIMITER ;

CASE simple vs CASE buscado

CaracterísticaCASE simpleCASE buscado
ComparaUn valor con opcionesCondiciones booleanas
FlexibilidadMenor, solo igualdadMayor, cualquier condición
LegibilidadMás limpio para valores discretosMejor para rangos
RendimientoSimilarSimilar

CASE vs IF

EscenarioRecomendación
Valor con múltiples opcionesCASE simple
Rangos numéricosCASE buscado o IF
Dos opcionesIF...ELSE
Lógica compleja con anidamientoIF

Importante: ELSE en CASE

Si ninguna condición WHEN coincide y no hay ELSE, MySQL genera un error:

-- Esto genera error si v_estado no coincide con ningún WHEN
CASE v_estado
    WHEN 'activo' THEN SET x = 1;
    WHEN 'inactivo' THEN SET x = 0;
    -- Sin ELSE: Error 1339 - Case not found for CASE statement
END CASE;

Siempre incluye una cláusula ELSE para evitar este error.

Limpieza

DROP PROCEDURE IF EXISTS estado_pedido;
DROP PROCEDURE IF EXISTS clasificar_cliente;
DROP PROCEDURE IF EXISTS procesar_devolucion;

En el siguiente artículo veremos el bucle LOOP para repetir sentencias dentro de un procedimiento.

Escrito por Eduardo Lázaro