Antes de meternos en el tema principal, vamos a pararnos en los errores y descuidos más comunes con los que te puedes topar. Porque los errores en SQL son el dolor de cabeza de cualquier dev, y normalmente aparecen en el peor momento posible.
1. Errores de sintaxis: "se me olvidó cerrar el IF"
Los errores de sintaxis son lo más básico, pero pasan más de lo que crees. Por ejemplo, si te olvidas de cerrar un bloque condicional IF con END IF;, el compilador te va a regañar al instante.
Ejemplo de error:
CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
IF num > 0 THEN
RETURN 'Positivo';
ELSE
RETURN 'Negativo';
-- por aquí se perdió el END IF;
END;
$$ LANGUAGE plpgsql;
Si intentas ejecutar este código, te va a saltar el error: ERROR: syntax error at or near "END". ¿Por qué? Porque el bloque IF quedó abierto.
¿Cómo evitar este tipo de errores?
Usa siempre una estructura clara en tu código. Cuando abras un bloque (por ejemplo, IF), escribe el cierre de inmediato. Aquí tienes el ejemplo corregido:
CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
IF num > 0 THEN
RETURN 'Positivo';
ELSE
RETURN 'Negativo';
END IF; -- no te olvides de cerrar el bloque
END;
$$ LANGUAGE plpgsql;
2. Olvidar manejar todos los casos en CASE: "¿Y si no entra en ningún caso?"
Cuando usas CASE, pon siempre una rama ELSE para manejar comportamientos inesperados. Si no la pones, puedes acabar devolviendo un NULL sin querer.
Ejemplo de error:
CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
RETURN CASE grade
WHEN 'A' THEN 'Excelente'
WHEN 'B' THEN 'Bueno'
WHEN 'C' THEN 'Normal'
-- ¿Y si grade = 'D' u otra nota?
END;
END;
$$ LANGUAGE plpgsql;
Si le pasas el valor D, la función devuelve NULL, lo que puede liarte el código.
Versión corregida:
CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
RETURN CASE grade
WHEN 'A' THEN 'Excelente'
WHEN 'B' THEN 'Bueno'
WHEN 'C' THEN 'Normal'
ELSE 'Nota desconocida' -- Capturamos todos los demás casos
END;
END;
$$ LANGUAGE plpgsql;
3. Problemas con bucles infinitos: "¿Por qué se ha colgado el servidor?"
Si usas un bucle LOOP, es fácil olvidarse de poner una condición de salida. Esto puede acabar en una ejecución infinita:
Ejemplo de error:
CREATE OR REPLACE FUNCTION infinite_loop_demo()
RETURNS VOID AS $$
DECLARE
i INTEGER := 1;
BEGIN
LOOP
i := i + 1;
-- ¡No hay condición de salida!
END LOOP;
END;
$$ LANGUAGE plpgsql;
Este código va a colgar el servidor porque el bucle nunca termina.
¿Cómo arreglarlo?
Pon una condición de salida usando EXIT:
CREATE OR REPLACE FUNCTION finite_loop_demo()
RETURNS VOID AS $$
DECLARE
i INTEGER := 1;
BEGIN
LOOP
i := i + 1;
IF i > 10 THEN
EXIT; -- Condición de salida
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
4. Saltarse iteraciones en bucles: "¿Y los datos que faltan?"
Si usas CONTINUE para saltarte iteraciones, puedes liarla si no tienes en cuenta todos los casos posibles. Por ejemplo:
Ejemplo de error:
CREATE OR REPLACE FUNCTION skip_even()
RETURNS VOID AS $$
DECLARE
i INTEGER := 0;
BEGIN
WHILE i < 10 LOOP
i := i + 1;
IF i % 2 = 0 THEN
CONTINUE; -- Saltamos los pares sin más
END IF;
RAISE NOTICE 'Número impar: %', i;
END LOOP;
END;
$$ LANGUAGE plpgsql;
¿Y si todos los números son pares? El servidor funciona, pero no ves ningún resultado.
¿Cómo arreglarlo?
Asegúrate de manejar todos los datos bien y mete logs para controlar lo que pasa:
CREATE OR REPLACE FUNCTION skip_even_logging()
RETURNS VOID AS $$
DECLARE
i INTEGER := 0;
BEGIN
WHILE i < 10 LOOP
i := i + 1;
IF i % 2 = 0 THEN
RAISE NOTICE 'Saltando número par: %', i;
CONTINUE;
END IF;
RAISE NOTICE 'Número impar: %', i;
END LOOP;
END;
$$ LANGUAGE plpgsql;
Ahora ves qué números se han saltado.
5. Manejo incorrecto de errores: "¿Dónde está mi RAISE EXCEPTION?"
Manejar errores con RAISE EXCEPTION es muy potente, pero puedes liarla fácil si lo usas mal.
Ejemplo de error:
CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
IF num < 0 THEN
RAISE '¡No se permite número negativo!';
END IF;
RETURN num * num;
END;
$$ LANGUAGE plpgsql;
Este código da error porque la sintaxis de RAISE es incorrecta (falta el nivel del mensaje).
Versión corregida:
CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
IF num < 0 THEN
RAISE EXCEPTION '¡No se permite número negativo!';
END IF;
RETURN num * num;
END;
$$ LANGUAGE plpgsql;
6. Errores al hacer logging: "¿Por qué mis errores no se escriben en error_log?"
Un mal insert en la tabla error_log puede pasar por errores en las consultas INSERT INTO.
Ejemplo de error:
CREATE OR REPLACE FUNCTION log_error(err_msg TEXT)
RETURNS VOID AS $$
BEGIN
INSERT INTO error_log (error_message, error_time)
VALUES (err_msg, CURRENT_TIMESTAMP); -- ¿Y si hay un error en los nombres de columnas?
END;
$$ LANGUAGE plpgsql;
Si en la tabla error_log cambiaste el nombre de la columna (por ejemplo, a error_msg), esto va a dar error.
¿Cómo evitarlo?
Revisa siempre la estructura de la tabla o usa un esquema estricto para manejar los datos.
7. Despistes y "factor humano"
Los errores no son solo técnicos, también pueden ser por despiste. Dejar debug, variables sin usar o no formatear el código puede convertir tu función en un caos.
Ejemplo:
DECLARE
i INTEGER; -- ¿Para qué, si no se usa la variable?
Solución: borra las partes que no necesitas para que el código quede limpio y fácil de entender.
Ahora ya puedes evitar los errores más comunes en PL/pgSQL y escribir código que dé más alegría que dolores de cabeza. No te olvides de testear, loggear y arreglar bugs a tiempo: ¡te vas a ahorrar muchos nervios y llamadas de clientes!
GO TO FULL VERSION