En programación hay dos cosas clave: entender qué está pasando (sobre todo cuando todo va al revés de lo que planeaste) y devolver datos útiles. Esto es especialmente cierto en PL/pgSQL, porque todo ocurre del lado del servidor, así que hacer debug no siempre es fácil. Por suerte, hay herramientas integradas que ayudan:
RAISE NOTICE — es una forma de mostrar mensajes mientras se ejecuta una función. Piénsalo como un console.log en JavaScript o un print en Python. Puedes mostrar valores de variables, el estado actual de la ejecución o simplemente dejar un "saludo" para tu yo del futuro.
RETURN QUERY — es una forma de devolver un conjunto de datos, como una tabla entera o el resultado de una consulta compleja. Gracias a esto, las funciones PL/pgSQL se parecen mucho a las consultas SQL normales.
Comando RAISE NOTICE
RAISE NOTICE te permite mostrar mensajes en pantalla mientras se ejecuta la función. El formato es así:
RAISE NOTICE 'Mensaje: %', valor;
%— es un placeholder para una variable, parecido aprintfen C.- Después del texto del mensaje puedes poner las variables que quieras mostrar.
Ejemplo de uso
Imagina que escribes una función que cuenta cuántos estudiantes hay en diferentes grupos. Quieres ver los valores intermedios para comprobar que todo va bien.
CREATE OR REPLACE FUNCTION count_students_in_groups() RETURNS VOID AS $$
DECLARE
group_name TEXT;
student_count INT;
BEGIN
FOR group_name IN SELECT DISTINCT group_name FROM students LOOP
SELECT COUNT(*) INTO student_count
FROM students WHERE group_name = group_name;
-- Mostrar resultados
RAISE NOTICE 'Grupo: %, Cantidad de estudiantes: %', group_name, student_count;
END LOOP;
END;
$$ LANGUAGE plpgsql;
Cuando llames a esta función:
SELECT count_students_in_groups();
Vas a ver mensajes como estos en los logs:
NOTICE: Grupo: Matemáticas, Cantidad de estudiantes: 30
NOTICE: Grupo: Filosofía, Cantidad de estudiantes: 25
NOTICE: Grupo: Biología, Cantidad de estudiantes: 18
Fíjate que la función no devuelve nada (se crea con RETURNS VOID), pero RAISE NOTICE nos muestra cómo va el ciclo.
Trucos útiles con RAISE
Además de NOTICE, puedes usar otros niveles de mensajes:
RAISE DEBUG— para info extra (solo se muestra si el nivel de logs está en DEBUG).RAISE INFO— para información general.RAISE WARNING— para advertencias.RAISE EXCEPTION— para lanzar errores, lo veremos más adelante.
Para debug, lo mejor es usar NOTICE o DEBUG, porque son cómodos y no paran la función.
Comando RETURN QUERY: devuelve datos como un pro
RETURN QUERY se usa en PL/pgSQL para devolver un conjunto de filas. Así puedes devolver el resultado de una consulta SQL directamente desde la función. El formato es:
RETURN QUERY <consulta SQL>;
También puedes combinar varias consultas:
RETURN QUERY <consulta SQL 1>;
RETURN QUERY <consulta SQL 2>;
Ejemplo 1: función con RETURN QUERY
Vamos a escribir una función que devuelve la lista de estudiantes de un grupo dado.
CREATE OR REPLACE FUNCTION get_students_by_group(group_name TEXT)
RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT id, name
FROM students
WHERE group_name = group_name;
END;
$$ LANGUAGE plpgsql;
Ahora llamamos a la función:
SELECT * FROM get_students_by_group('Matemáticas');
Para probar la función, primero crea la tabla students y mete algunos datos:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
group_name TEXT NOT NULL
);
INSERT INTO students (name, group_name) VALUES
('Otto Song', 'Física'),
('Alex Lin', 'Matemáticas'),
('Anna Vel', 'Matemáticas'),
('Maria Chi', 'Historia');
Resultado:
| id | name |
|---|---|
| 2 | Alex Lin |
| 3 | Anna Vel |
Como ves, la función funciona igual que una consulta SQL normal.
Ejemplo 2: Combinando varias consultas
¿Y si queremos devolver datos combinados de varias tablas? Vamos a devolver la lista de estudiantes y los cursos en los que están inscritos.
CREATE OR REPLACE FUNCTION get_students_and_courses()
RETURNS TABLE(student_name TEXT, course_name TEXT) AS $$
BEGIN
RETURN QUERY
SELECT s.name, c.name
FROM students s
JOIN enrollments e ON s.id = e.student_id
JOIN courses c ON e.course_id = c.id;
END;
$$ LANGUAGE plpgsql;
Primero crea tres tablas: students, courses y enrollments, y mete algunos datos:
-- Tabla de estudiantes
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Tabla de cursos
CREATE TABLE courses (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Tabla de inscripciones (relación)
CREATE TABLE enrollments (
student_id INT REFERENCES students(id),
course_id INT REFERENCES courses(id)
);
-- Añadir estudiantes
INSERT INTO students (name) VALUES
('Otto Song'),
('Alex Lin'),
('Anna Vel'),
('Maria Chi');
-- Añadir cursos
INSERT INTO courses (name) VALUES
('Matemáticas'),
('Física'),
('Historia');
-- Añadir inscripciones
INSERT INTO enrollments (student_id, course_id) VALUES
(1, 2), -- Otto -> Física
(2, 1), -- Alex -> Matemáticas
(3, 1), -- Anna -> Matemáticas
(4, 3); -- Maria -> Historia
En este caso, al llamar a la función:
SELECT * FROM get_students_and_courses();
vas a obtener este resultado:
| student_name | course_name |
|---|---|
| Otto Song | Física |
| Alex Lin | Matemáticas |
| Anna Vel | Matemáticas |
| Maria Chi | Historia |
La función junta los datos de tres tablas y muestra en qué curso está cada estudiante.
Combinando RAISE NOTICE y RETURN QUERY
A veces RETURN QUERY y RAISE NOTICE pueden ir juntos en una función, así puedes controlar la ejecución y ver resultados intermedios.
Aquí tienes un ejemplo de función que devuelve datos de estudiantes y al mismo tiempo muestra mensajes para ver el progreso:
CREATE OR REPLACE FUNCTION debug_students()
RETURNS TABLE(student_id INT, student_name TEXT) AS $$
DECLARE
count_students INT;
BEGIN
-- Contar estudiantes
SELECT COUNT(*) INTO count_students FROM students;
RAISE NOTICE 'Total de estudiantes: %', count_students;
-- Devolver datos de estudiantes
RETURN QUERY
SELECT id, name FROM students;
RAISE NOTICE 'La función ha terminado.';
END;
$$ LANGUAGE plpgsql;
Si la tabla students aún no existe, créala y mete algunos datos:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
INSERT INTO students (name) VALUES
('Otto Song'),
('Alex Lin'),
('Anna Vel'),
('Maria Chi');
Ahora, al llamar a la función:
SELECT * FROM debug_students();
Vas a ver tanto los datos como los mensajes:
| student_id | student_name |
|---|---|
| 1 | Otto Song |
| 2 | Alex Lin |
| 3 | Anna Vel |
| 4 | Maria Chi |
Salida de mensajes en consola:
NOTICE: Total de estudiantes: 4
NOTICE: La función ha terminado.
Errores típicos al usar estas funciones
Error con variables en RAISE NOTICE: si te olvidas de declarar una variable o te equivocas en el nombre, te saldrá el error variable does not exist. Siempre revisa que las variables estén bien declaradas.
Error con el tipo de retorno: si usas RETURN QUERY pero no pones RETURNS TABLE al crear la función, PostgreSQL dará error. Asegúrate de que los tipos de retorno coincidan con los datos que devuelves.
Error con los placeholders en RAISE: si el número de % no coincide con el número de variables, tendrás un error. Por ejemplo:
RAISE NOTICE 'Valor: %, %', valor1;
Esto dará error porque falta la segunda variable.
GO TO FULL VERSION