Operatori RAISE NOTICE, RETURN QUERY
Nel mondo della programmazione ci sono due cose fondamentali: capire cosa sta succedendo (soprattutto quando tutto va storto) e restituire dati utili. Questo è ancora più vero in PL/pgSQL, perché tutto gira lato server e il debug non è sempre una passeggiata. Per fortuna ci sono strumenti integrati che ci aiutano:
RAISE NOTICE — è il modo per mostrare messaggi durante l'esecuzione di una funzione. Pensalo come console.log in JavaScript o print in Python. Puoi mostrare valori di variabili, lo stato corrente dell'esecuzione o semplicemente lasciare un "ciao" per il te stesso del futuro.
RETURN QUERY — è il modo per restituire un set di dati, tipo un'intera tabella o il risultato di una query complessa. Grazie a lui, le funzioni PL/pgSQL diventano quasi come vere query SQL.
Comando RAISE NOTICE
RAISE NOTICE ti permette di mostrare messaggi a schermo mentre la funzione gira. Il formato è questo:
RAISE NOTICE 'Messaggio: %', valore;
%— è un placeholder per una variabile, simile aprintfin C.- Dopo il testo del messaggio puoi elencare le variabili che vuoi inserire.
Esempio di utilizzo
Immagina di scrivere una funzione che conta il numero di studenti in diversi gruppi. Vuoi vedere i valori intermedi per capire se tutto fila liscio.
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;
-- Mostra i risultati
RAISE NOTICE 'Gruppo: %, Numero di studenti: %', group_name, student_count;
END LOOP;
END;
$$ LANGUAGE plpgsql;
Quando chiami questa funzione:
SELECT count_students_in_groups();
Vedrai messaggi simili nei log:
NOTICE: Gruppo: Matematica, Numero di studenti: 30
NOTICE: Gruppo: Filosofia, Numero di studenti: 25
NOTICE: Gruppo: Biologia, Numero di studenti: 18
Nota che la funzione non restituisce nulla (è creata con RETURNS VOID), ma RAISE NOTICE ci mostra come procede il ciclo.
Trucchetti utili con RAISE
Oltre a NOTICE, puoi usare anche altri livelli di messaggio:
RAISE DEBUG— per info extra (si vede solo se il livello di log è DEBUG).RAISE INFO— per info generali.RAISE WARNING— per avvisi.RAISE EXCEPTION— per generare errori, che vedremo più avanti.
Per il debug, meglio usare NOTICE o DEBUG, perché sono comodi e non bloccano l'esecuzione della funzione.
Comando RETURN QUERY: restituisci dati come un pro
RETURN QUERY si usa in PL/pgSQL per restituire un set di righe. Così puoi restituire il risultato di una query SQL direttamente da una funzione. La sintassi è questa:
RETURN QUERY <query SQL>;
Puoi anche combinare più query:
RETURN QUERY <query SQL 1>;
RETURN QUERY <query SQL 2>;
Esempio 1: funzione con RETURN QUERY
Scriviamo una funzione che restituisce la lista degli studenti di un certo gruppo.
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;
Ora chiamiamo questa funzione:
SELECT * FROM get_students_by_group('Matematica');
Per testare la funzione, prima creiamo la tabella students e aggiungiamo dei dati:
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', 'Fisica'),
('Alex Lin', 'Matematica'),
('Anna Vel', 'Matematica'),
('Maria Chi', 'Storia');
Risultato:
| id | name |
|---|---|
| 2 | Alex Lin |
| 3 | Anna Vel |
Come vedi, la funzione funziona come una normale query SQL.
Esempio 2: Unire più query
E se volessimo restituire dati uniti da più tabelle? Vediamo come restituire la lista di studenti e i corsi a cui sono iscritti.
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;
Per prima cosa creiamo tre tabelle: students, courses ed enrollments, poi aggiungiamo qualche dato:
-- Tabella studenti
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Tabella corsi
CREATE TABLE courses (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Tabella iscrizioni ai corsi (di collegamento)
CREATE TABLE enrollments (
student_id INT REFERENCES students(id),
course_id INT REFERENCES courses(id)
);
-- Aggiungiamo studenti
INSERT INTO students (name) VALUES
('Otto Song'),
('Alex Lin'),
('Anna Vel'),
('Maria Chi');
-- Aggiungiamo corsi
INSERT INTO courses (name) VALUES
('Matematica'),
('Fisica'),
('Storia');
-- Aggiungiamo iscrizioni ai corsi
INSERT INTO enrollments (student_id, course_id) VALUES
(1, 2), -- Otto -> Fisica
(2, 1), -- Alex -> Matematica
(3, 1), -- Anna -> Matematica
(4, 3); -- Maria -> Storia
In questo caso, chiamando la funzione:
SELECT * FROM get_students_and_courses();
otterrai questo risultato:
| student_name | course_name |
|---|---|
| Otto Song | Fisica |
| Alex Lin | Matematica |
| Anna Vel | Matematica |
| Maria Chi | Storia |
La funzione unisce in modo pulito i dati di tre tabelle e mostra chi è iscritto a quale corso.
Unire RAISE NOTICE e RETURN QUERY
A volte RETURN QUERY e RAISE NOTICE possono convivere nella stessa funzione, così puoi controllare l'esecuzione e vedere i risultati intermedi.
Ecco un esempio di funzione che restituisce dati sugli studenti e allo stesso tempo mostra messaggi per farti vedere come procede:
CREATE OR REPLACE FUNCTION debug_students()
RETURNS TABLE(student_id INT, student_name TEXT) AS $$
DECLARE
count_students INT;
BEGIN
-- Contiamo il numero di studenti
SELECT COUNT(*) INTO count_students FROM students;
RAISE NOTICE 'Totale studenti: %', count_students;
-- Restituiamo i dati degli studenti
RETURN QUERY
SELECT id, name FROM students;
RAISE NOTICE 'La funzione ha finito.';
END;
$$ LANGUAGE plpgsql;
Se la tabella students non esiste ancora, creala e inserisci i dati:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
INSERT INTO students (name) VALUES
('Otto Song'),
('Alex Lin'),
('Anna Vel'),
('Maria Chi');
Ora, chiamando la funzione:
SELECT * FROM debug_students();
Otterrai sia i dati che i messaggi:
| student_id | student_name |
|---|---|
| 1 | Otto Song |
| 2 | Alex Lin |
| 3 | Anna Vel |
| 4 | Maria Chi |
Messaggi in console:
NOTICE: Totale studenti: 4
NOTICE: La funzione ha finito.
Errori tipici nell'uso
Errore con le variabili in RAISE NOTICE: se ti dimentichi di dichiarare una variabile o sbagli il nome, otterrai l'errore variable does not exist. Controlla sempre che le variabili siano dichiarate correttamente.
Errore con il tipo di ritorno: se usi RETURN QUERY ma non specifichi RETURNS TABLE quando crei la funzione, PostgreSQL ti darà errore. Assicurati che i tipi di ritorno corrispondano ai dati restituiti.
Errore con i placeholder in RAISE: se il numero di placeholder % non corrisponde al numero di variabili, avrai un errore. Ad esempio:
RAISE NOTICE 'Valore: %, %', value1;
Questo causerà un errore perché manca la seconda variabile.
GO TO FULL VERSION