I cicli ti permettono di eseguire un blocco di codice più volte di fila, finché si verifica una certa condizione oppure mentre fai un'iterazione su un set di dati. È super utile per automatizzare task, lavorare con grandi quantità di dati o fare operazioni ripetitive.
Immagina di dover dare le caramelle a mano a tutti i bambini di un gruppo. Sarebbe un casino! Invece puoi semplicemente scorrere la lista dei bambini e dare una caramella a ciascuno, uno dopo l'altro. In questo scenario, lo "scorrere la lista" è proprio un ciclo.
In PostgreSQL ci sono diversi tipi di cicli:
LOOP— ciclo universale che va avanti finché non lo fermi esplicitamente.FOR— ciclo con un numero definito di iterazioni su un range di numeri o sul risultato di una query.WHILE— ciclo che continua finché la condizione è vera.
Dai, vediamo ogni tipo uno per uno.
Ciclo infinito: LOOP
LOOP è la forma base del ciclo in PL/pgSQL, che ripete l'esecuzione di un blocco di codice. Questo ciclo va avanti all'infinito, e devi fermarlo manualmente con il comando EXIT.
Sintassi:
LOOP
-- Il tuo codice qui
END LOOP;
Ecco un esempio. Calcoliamo la somma dei numeri da 1 a 10 usando LOOP:
DO $$
DECLARE
counter INT := 1;
sum INT := 0;
BEGIN
LOOP
sum := sum + counter; -- aggiungiamo il valore attuale del contatore
counter := counter + 1; -- aumentiamo il contatore
-- Fermiamo il ciclo se il contatore è maggiore di 10
IF counter > 10 THEN
EXIT;
END IF;
END LOOP;
RAISE NOTICE 'Somma dei numeri da 1 a 10: %', sum;
END $$;
- La variabile
counterviene incrementata a ogni iterazione. - La condizione
IF counter > 10 THEN EXIT;ferma il ciclo quando il contatore supera 10. - Alla fine viene stampata la somma dei numeri.
Ciclo su un range o su un set di dati: FOR
Il secondo tipo di ciclo, FOR, si usa per iterare su:
- Un range di numeri.
- Il risultato di una query SQL.
Ciclo su un range di numeri
Sintassi:
FOR variable IN [REVERSE] start..end LOOP
-- Il tuo codice qui
END LOOP;
Stampiamo i numeri da 1 a 5:
DO $$
BEGIN
FOR i IN 1..5 LOOP
RAISE NOTICE 'Valore attuale: %', i;
END LOOP;
END $$;
Esempio con ordine inverso:
DO $$
BEGIN
FOR i IN REVERSE 5..1 LOOP
RAISE NOTICE 'Ordine inverso: %', i;
END LOOP;
END $$;
Ciclo sul risultato di una query SQL
Questa variante è utile per lavorare sulle righe di una tabella.
Sintassi:
FOR variable IN QUERY (SELECT ...) LOOP
-- Il tuo codice qui
END LOOP;
Ecco un esempio di iterazione sulle righe della tabella students:
DO $$
DECLARE
student_name TEXT;
BEGIN
FOR student_name IN QUERY (SELECT name FROM students) LOOP
RAISE NOTICE 'Ciao, %!', student_name;
END LOOP;
END $$;
Ciclo condizionale: WHILE
WHILE viene eseguito finché la condizione specificata è vera.
Sintassi:
WHILE condizione LOOP
-- Il tuo codice qui
END LOOP;
Calcoliamo la somma dei numeri da 1 a 10 usando WHILE:
DO $$
DECLARE
counter INT := 1;
sum INT := 0;
BEGIN
WHILE counter <= 10 LOOP
sum := sum + counter;
counter := counter + 1;
END LOOP;
RAISE NOTICE 'Somma dei numeri da 1 a 10: %', sum;
END $$;
Esempi dalla vita reale
Ora che abbiamo capito le basi dei cicli, vediamo qualche esempio pratico di come usarli.
Esempio 1: generazione della tabella pitagorica
DO $$
DECLARE
i INT;
j INT;
BEGIN
FOR i IN 1..5 LOOP
FOR j IN 1..5 LOOP
RAISE NOTICE '% x % = %', i, j, i * j;
END LOOP;
END LOOP;
END $$;
Esempio 2: iterazione sui risultati di una query. Supponiamo di avere una tabella products con i campi id e price. Aggiorniamo tutti i prezzi aumentandoli del 10%.
DO $$
DECLARE
prod RECORD;
BEGIN
FOR prod IN QUERY (SELECT id, price FROM products) LOOP
UPDATE products
SET price = prod.price * 1.1
WHERE id = prod.id;
END LOOP;
END $$;
Errori tipici e come evitarli
Ciclo infinito in LOOP o WHILE. Se ti dimentichi di aggiungere una condizione di uscita (EXIT o una condizione corretta in WHILE), il ciclo non finirà mai. È un po' come guidare senza freni.
Errore durante l'iterazione sul risultato di una query. Se la struttura dei dati risultanti non è quella che ti aspetti, puoi beccarti un errore nel ciclo FOR IN QUERY.
Query non ottimizzate dentro i cicli. Per esempio, fare un UPDATE a ogni iterazione può rallentare un sacco l'esecuzione. In questi casi, meglio usare una singola query SQL invece di un ciclo.
GO TO FULL VERSION