Andiamo a scavare un po’ più a fondo in PL/pgSQL e iniziamo a usarlo sul serio.
Blocco di codice
Un blocco di codice in PL/pgSQL è il mattone fondamentale del linguaggio. Puoi pensarlo come lo scheletro su cui si reggono funzioni, procedure e tutta la magia che ci serve. Il blocco gestisce la logica, l’elaborazione dei dati, la gestione degli errori, tutto dentro un unico “contenitore”.
I blocchi PL/pgSQL sono strutturati e hanno tre parti principali:
DECLARE: dichiarazione delle variabili (opzionale).BEGIN ... END: il blocco principale dove gira la logica.EXCEPTION: gestione degli errori (opzionale).
Per chi ama le analogie: pensa a una ricetta di cucina. Anche se la ricetta inizia con la lista degli ingredienti, la vera magia succede durante la preparazione. In termini PL/pgSQL:
DECLARE— è la lista degli ingredienti (le variabili).BEGIN ... END— è dove si mescola, si frigge e si bolle.EXCEPTION— è il piano B se qualcosa si brucia.
Sintassi di un blocco PL/pgSQL
Prima guardiamo la struttura generale del blocco, tipo lo “scheletro”. Poi ci mettiamo la carne (o il formaggio veg, se preferisci) — cioè la logica vera e propria.
DO $$
DECLARE
-- Qui si dichiarano le variabili
student_count INT;
BEGIN
-- Qui va la logica
SELECT COUNT(*) INTO student_count FROM students;
RAISE NOTICE 'Numero totale di studenti: %', student_count;
EXCEPTION
-- Qui si gestiscono gli errori
WHEN OTHERS THEN
RAISE NOTICE 'Si è verificato un errore.';
END;
$$;
Vediamo passo passo cosa succede qui.
DECLARE— qui dichiariamo le nostre variabili. La cosa bella è che PL/pgSQL supporta quasi tutti i tipi di dato di PostgreSQL — dai sempliciINTEGERai più esotici JSONB. Per dichiarare una variabile, basta scrivere il nome, il tipo di dato e, se vuoi, un valore iniziale.
Esempio:
DECLARE
student_name TEXT; -- Variabile per il nome dello studente
course_count INT := 0; -- Impostiamo il valore iniziale a 0
is_graduated BOOLEAN; -- Variabile booleana
Nota che le variabili possono essere inizializzate (come course_count) oppure no.
BEGIN ... END— il blocco principale di esecuzione.
Questa parte del blocco si occupa della logica vera e propria. Qui puoi:
- Eseguire query SQL (
SELECT,INSERT, ecc.). - Manipolare i dati.
- Usare strutture di controllo (
IF,LOOP, ecc.). - Stampare messaggi di debug con
RAISE.
Esempio:
BEGIN
SELECT COUNT(*) INTO student_count FROM students;
IF student_count > 0 THEN
RAISE NOTICE 'Abbiamo degli studenti!';
ELSE
RAISE NOTICE 'Nessuno studente trovato.';
END IF;
END;
EXCEPTION— gestione degli errori (opzionale).
Se durante l’esecuzione del blocco succede un errore, la sezione EXCEPTION ti permette di intercettarlo e fare qualcosa di utile — tipo stampare un messaggio o eseguire codice alternativo.
Esempio:
BEGIN
SELECT COUNT(*) INTO student_count FROM non_existing_table; -- Errore!
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Ops, qualcosa è andato storto!';
END;
Esempio reale: conteggio degli studenti
Ora mettiamo tutto insieme in un esempio che può tornare utile davvero. Scriviamo un blocco PL/pgSQL che conta quanti studenti ci sono nella tabella students e stampa un messaggio.
DO $$
DECLARE
total_students INT; -- Variabile per il numero di studenti
BEGIN
-- Contiamo il numero di studenti
SELECT COUNT(*) INTO total_students FROM students;
-- Stampiamo il messaggio col risultato
RAISE NOTICE 'Numero di studenti: %', total_students;
EXCEPTION
-- Gestiamo eventuali errori, tipo se la tabella non esiste
WHEN OTHERS THEN
RAISE NOTICE 'Si è verificato un errore durante il conteggio degli studenti.';
END;
$$;
L’esecuzione di questo blocco stampa un messaggio in console. Tipo: Numero di studenti: 42.
Particolarità nell’uso delle variabili
Vediamo qualche punto importante:
Assegnare valori alle variabili. Per mettere dati in una variabile, puoi usare l’operatore SELECT INTO:
SELECT COUNT(*) INTO total_students FROM students;
Inizializzazione delle variabili. Se non assegni un valore alla variabile quando la dichiari, il suo valore di default sarà NULL.
Esempio:
DECLARE
my_var INT; -- Valore NULL
Variabili di tipo RECORD. Questo è un tipo di variabile universale, dove puoi mettere una riga di una tabella. Esempio:
DECLARE
student RECORD;
BEGIN
SELECT * INTO student FROM students WHERE id = 1;
RAISE NOTICE 'Nome studente: %, Età: %', student.name, student.age;
END;
Esempio: conteggio dei corsi per uno studente
Ora risolviamo un problema pratico: contare quanti corsi sono iscritti a uno studente e stampare il risultato.
DO $$
DECLARE
student_id INT := 1; -- ID dello studente
course_count INT; -- Variabile per il numero di corsi
BEGIN
-- Contiamo il numero di corsi
SELECT COUNT(*) INTO course_count
FROM enrollments
WHERE student_id = student_id;
-- Stampiamo il messaggio
RAISE NOTICE 'Lo studente con ID % è iscritto a % corsi.', student_id, course_count;
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Si è verificato un errore durante l\'elaborazione dello studente ID %', student_id;
END;
$$;
Questo blocco è flessibile: puoi cambiare student_id per vedere quanti corsi sono iscritti studenti diversi.
Errori e come evitarli
Se dentro di te PL/pgSQL sta già saltando come un hot dog nel microonde, tranquillo. All’inizio è normale beccarsi i “classici” errori. Ecco qualche esempio:
Dimenticare di dichiarare una variabile. Se ti scordi di dichiarare una variabile con DECLARE, PL/pgSQL ti dirà che la variabile “non esiste”.
Usare NULL come valore. Se la variabile è dichiarata ma non ha un valore, sarà NULL. Questo può portare a comportamenti strani. Esempio:
IF my_var = NULL THEN -- NON funziona!
Usa IS NULL:
IF my_var IS NULL THEN
Uso sbagliato della sezione EXCEPTION. A volte i programmatori intercettano tutti gli errori (WHEN OTHERS), ma non scrivono cosa fare. Così rischi di nascondere il vero problema. Meglio stampare un messaggio d’errore:
RAISE NOTICE 'Errore: %', SQLERRM;
GO TO FULL VERSION