Informatique · PL/pgSQL (PostgreSQL)

Les bases de PL/pgSQL

Une requête SQL répond à une question. Mais pour calculer une moyenne élève par élève, décider d'une mention ou refuser une note hors de l'échelle, il faut des variables, des conditions et des boucles. C'est le rôle de PL/pgSQL, le langage procédural de PostgreSQL : le code s'exécute dans le serveur, au plus près des données.

application DO $$ … $$ NOTICE serveur PostgreSQL FOR r IN SELECT … LOOP IF r.moyenne < 4 THEN v_nb := v_nb + 1; END IF; END LOOP; eleves Léa · Noah … notes 5.5 · 3 · 6 …
En SQL, BEGIN ouvre une transaction. Et le BEGIN d'un bloc PL/pgSQL, il fait pareil ? Garde ta réponse en tête : on la vérifie dans la notion 2.

Après cette fiche, tu sais

  • écrire un bloc anonyme DO et nommer ses parties : DECLARE, BEGIN, EXCEPTION, END ;
  • déclarer des variables et des constantes, leur donner une valeur avec := ou SELECT … INTO ;
  • choisir entre IF et CASE, et entre les boucles LOOP, WHILE et FOR ;
  • afficher un message ou lever une erreur avec RAISE, et déjouer les pièges du NULL.
1Notion 1 · Pourquoi PL/pgSQL

Le code va vers les données

SQL est un langage déclaratif : une requête décrit le résultat voulu, et le serveur choisit comment l'obtenir. Entre deux requêtes, SQL n'a ni variable, ni boucle, ni « si… alors ». PL/pgSQL (Procedural Language/PostgreSQL) ajoute ces outils et regroupe calculs et requêtes à l'intérieur du serveur : pas d'allers-retours supplémentaires entre le client et le serveur, pas de résultats intermédiaires à transférer, des requêtes analysées une seule fois.1

Le code PL/pgSQL se range dans un bloc anonyme (DO, exécuté une fois), une fonction, une procédure ou un déclencheur.1 Cette fiche travaille avec le bloc anonyme ; les autres ont leur fiche dans la série.

Les tables des exempleseleves(id, prenom, classe) : 1 Léa 2M3, 2 Noah 2M3, 3 Zoé 2M3, 4 Elias 2M1. notes(eleve_id, branche, note), notes de 1 à 6 : Léa 5.5 et 5, Noah 3 et 4.5, Zoé 6 et 5.5, Elias 4. Tous les résultats indiqués en commentaire ont été obtenus avec ces données dans PostgreSQL 18.
Scène 1

Quatre allers-retours, ou un seul

Fais défiler : l'application cherche les élèves de 2M3 dont la moyenne est sous 4, d'abord requête par requête, puis avec un bloc PL/pgSQL.

Scène 1 · Allers-retours

Sans PL/pgSQL : une requête à la fois

application allers-retours 0 requête réponse serveur PostgreSQL Léa Noah Zoé requête

Une seule requête suffit parfoisUne jointure avec GROUP BY et HAVING avg(note) < 4 trouverait la même liste en un seul aller-retour. PL/pgSQL devient utile quand la logique a besoin de variables, de conditions et de boucles qu'une requête seule n'exprime pas.
2Notion 2 · Le bloc

DECLARE, BEGIN, END : l'anatomie d'un bloc

Tout code PL/pgSQL est rangé dans un bloc. Le plus simple à lancer est le bloc anonyme : la commande DO l'exécute une seule fois, sans rien enregistrer dans la base.3

Un premier blocPL/pgSQL
DO $$
DECLARE
    v_prenom TEXT := 'Léa';      -- une variable et sa valeur de départ
BEGIN
    RAISE NOTICE 'Bonjour %', v_prenom;
END $$;
NOTICE:  Bonjour Léa
DO

Exécute un bloc anonyme, traité comme le corps d'une fonction sans paramètre qui ne renvoie rien. Langage par défaut : plpgsql. DO n'existe pas dans la norme SQL.3

$$ … $$

Le corps est une chaîne délimitée par des dollars : les apostrophes qu'elle contient n'ont pas à être doublées. On peut l'étiqueter : $corps$ … $corps$.3

Point-virgule

Chaque déclaration et chaque instruction se termine par ;. Un bloc placé dans un autre bloc prend aussi un ; après son END.1

Commentaires et casse

-- jusqu'à la fin de la ligne, /* … */ sur plusieurs lignes. Les mots-clés ignorent la casse : begin vaut BEGIN.1

Piège : BEGIN n'ouvre pas de transaction

Dans un bloc PL/pgSQL, BEGIN et END servent seulement à regrouper des instructions : ils ne démarrent ni ne terminent aucune transaction, contrairement aux commandes SQL BEGIN et COMMIT.1

Réponse à ma question : non. Le BEGIN d'un bloc regroupe des instructions, c'est tout. Valider ou annuler une transaction, c'est le travail de COMMIT et ROLLBACK, permis seulement dans les procédures et les blocs DO, et sous conditions.

Un bloc complet

Ce bloc compte les élèves. S'il ne trouve pas la table, il ne plante pas : sa section EXCEPTION prend le relais.

Les cinq partiesPL/pgSQL
DO $$
DECLARE
    v_nb INTEGER;
BEGIN
    SELECT count(*) INTO v_nb FROM eleves;
    RAISE NOTICE '% élèves', v_nb;
EXCEPTION
    WHEN undefined_table THEN
        RAISE NOTICE 'Table eleves absente';
END $$;
NOTICE:  4 élèves
Scène 2

Le bloc éclaté

Fais défiler : les cinq parties du bloc se séparent et se nomment, puis on ne garde que les parties obligatoires.

Scène 2 · Vue éclatée

Un bloc complet

Exercice · remettre dans l'ordre

Reconstruis le bloc

Les six lignes du premier bloc ont été mélangées : remets-les dans l'ordre.

3Notion 3 · Variables

Variables, constantes et types

Une variable se déclare dans la section DECLARE : un nom, un type SQL, et éventuellement une valeur de départ. On lui donne ensuite une valeur avec := (le signe = est aussi accepté).2

nom [CONSTANT] type [NOT NULL] [:= valeur];

Exemple : trois articles à 12.50 CHF, avec le taux normal de la TVA suisse, 8,1 %.5

Calculer un total TTCPL/pgSQL
DO $$
DECLARE
    c_tva    CONSTANT NUMERIC := 0.081;   -- taux normal de la TVA suisse
    v_prix   NUMERIC := 12.50;
    v_qte    INTEGER := 3;
    v_total  NUMERIC;                     -- pas de valeur : NULL
BEGIN
    v_total := v_prix * v_qte;                     -- 37.50
    v_total := round(v_total * (1 + c_tva), 2);    -- 40.54
    RAISE NOTICE 'Total TTC : % CHF', v_total;
END $$;
NOTICE:  Total TTC : 40.54 CHF
Scène 3

La mémoire du bloc

Fais défiler : le bloc s'exécute ligne par ligne. En dessous, chaque variable naît, change de valeur, puis disparaît avec le bloc.

Scène 3 · Mémoire

Le bloc démarre

mémoire du bloc NOTICE: Total TTC : 40.54 CHF

:= (affectation)

L'expression de droite est calculée par le moteur SQL, puis rangée dans la variable de gauche. Elle doit donner une seule valeur.2

NULL par défaut

Une variable déclarée sans valeur vaut NULL, la valeur « inconnue » de SQL.1

CONSTANT

La valeur fixée à la déclaration ne change plus pendant le bloc. Toute affectation est refusée : variable "c_tva" is declared CONSTANT.1

NOT NULL

Affecter NULL provoque une erreur ; la variable doit donc recevoir une valeur de départ non nulle.1

Quel type choisir ?

TypeContientExemple
INTEGERun entier3
NUMERICun nombre exact : montants, notes12.50
TEXTdu texte'Léa'
BOOLEANvrai ou fauxtrue
DATEune date du calendrier'2026-10-01'

Deux raccourcis évitent de recopier les types des tables : %TYPE reprend le type d'une colonne, %ROWTYPE déclare une ligne entière, dont on lit les champs avec un point.1

%TYPE et %ROWTYPEPL/pgSQL
DO $$
DECLARE
    v_prenom  eleves.prenom%TYPE;      -- le type de la colonne prenom
    v_eleve   eleves%ROWTYPE;          -- une ligne entière de la table
BEGIN
    SELECT * INTO v_eleve FROM eleves WHERE id = 3;
    v_prenom := v_eleve.prenom;
    RAISE NOTICE '% est en %', v_prenom, v_eleve.classe;
END $$;
NOTICE:  Zoé est en 2M3
Piège : NULL contamine les calculs

Après v_total NUMERIC;, l'instruction v_total := v_total + 10; laisse v_total à NULL, car NULL + 10 donne NULL ; RAISE affiche alors <NULL>. On initialise donc sommes et compteurs : v_total NUMERIC := 0;

Piège : la division entière

Entre deux entiers, / tronque le résultat : 7 / 2 vaut 3. Pour obtenir 3.5, l'un des deux doit être un NUMERIC : v_a::numeric / v_b.3

Exercice · à toi

Que va afficher ce bloc ?

Quatre blocs courts, tous exécutés dans PostgreSQL 18. Lis-les comme le ferait le serveur.

4Notion 4 · SELECT INTO

Lire la base dans des variables

Dans un bloc, une requête qui renvoie des lignes doit dire où ranger son résultat : c'est la clause INTO. Les colonnes du SELECT remplissent les variables dans l'ordre.2

La moyenne de NoahPL/pgSQL
DO $$
DECLARE
    v_prenom  eleves.prenom%TYPE;
    v_moyenne NUMERIC;
BEGIN
    SELECT e.prenom, round(avg(n.note), 2)
    INTO v_prenom, v_moyenne
    FROM eleves e JOIN notes n ON n.eleve_id = e.id
    WHERE e.id = 2
    GROUP BY e.prenom;

    RAISE NOTICE '% : moyenne %', v_prenom, v_moyenne;
END $$;
NOTICE:  Noah : moyenne 3.75

Que se passe-t-il si la requête ne trouve rien, ou trouve trop ? Fais défiler : cinq requêtes, cinq réactions de PostgreSQL.

eleves idprenomclasse v_prenom FOUND
Étape 1 sur 5 · une ligne

WHERE id = 2 trouve exactement une ligne : v_prenom reçoit 'Noah' et la variable spéciale FOUND passe à vrai.2

Étape 2 sur 5 · aucune ligne

WHERE id = 9 ne trouve rien. Aucune erreur : v_prenom passe à NULL et FOUND à faux. En Oracle PL/SQL, le même SELECT INTO lèverait l'exception NO_DATA_FOUND.4

Étape 3 sur 5 · plusieurs lignes

Trois élèves en 2M3 : sans STRICT, PostgreSQL garde la première ligne et ignore les autres. Sans ORDER BY, « la première » n'est pas définie.2

Étape 4 sur 5 · STRICT, trop de lignes

Avec INTO STRICT, il faut exactement une ligne. Trois lignes : erreur TOO_MANY_ROWS, message query returned more than one row.

Étape 5 sur 5 · STRICT, aucune ligne

Aucune ligne avec STRICT : erreur NO_DATA_FOUND, message query returned no rows. Une section EXCEPTION peut rattraper l'une ou l'autre.2

Retiens la différence avec Oracle : PostgreSQL ne proteste pas quand SELECT INTO ne trouve rien. Si l'absence de ligne est une erreur pour toi, écris STRICT, ou teste FOUND juste après.
Tester FOUNDPL/pgSQL
DO $$
DECLARE
    v_prenom TEXT;
BEGIN
    SELECT prenom INTO v_prenom FROM eleves WHERE id = 9;
    IF NOT FOUND THEN
        RAISE NOTICE 'Aucun élève avec l''id 9';
    END IF;
END $$;
NOTICE:  Aucun élève avec l'id 9
Piège : le SELECT sans INTO

Dans un bloc, SELECT prenom FROM eleves; est refusé : query has no destination for result data. Pour exécuter une requête en ignorant son résultat, on remplace SELECT par PERFORM.2

Après un UPDATE, un INSERT ou un DELETE, GET DIAGNOSTICS donne le nombre de lignes traitées par la dernière commande.2

Fin d'année : la 2M3 devient la 3M3PL/pgSQL
DO $$
DECLARE
    v_n INTEGER;
BEGIN
    UPDATE eleves SET classe = '3M3' WHERE classe = '2M3';
    GET DIAGNOSTICS v_n = ROW_COUNT;
    RAISE NOTICE '% élève(s) passent en 3M3', v_n;
END $$;
NOTICE:  3 élève(s) passent en 3M3
5Notion 5 · Conditions

IF et CASE : choisir un chemin

IF teste ses conditions dans l'ordre et exécute la première branche vraie ; les conditions suivantes ne sont même pas testées. ELSIF (qu'on peut aussi écrire ELSEIF) ajoute un test, ELSE attrape tout le reste, END IF; ferme la structure.2

Une mention selon la notePL/pgSQL
DO $$
DECLARE
    v_note    NUMERIC := 4.5;
    v_mention TEXT;
BEGIN
    IF v_note >= 5.5 THEN
        v_mention := 'très bien';
    ELSIF v_note >= 5 THEN
        v_mention := 'bien';
    ELSIF v_note >= 4 THEN
        v_mention := 'suffisant';
    ELSE
        v_mention := 'insuffisant';
    END IF;
    RAISE NOTICE 'Note % : %', v_note, v_mention;
END $$;
NOTICE:  Note 4.5 : suffisant
Scène 4

La première branche vraie

Fais défiler : la note monte de 1 à 6 et la branche exécutée suit. Puis on inverse l'ordre des tests, pour voir le piège.

Scène 4 · IF … ELSIF … ELSE

Tests du plus exigeant au moins exigeant

Piège : l'ordre des tests

Si v_note >= 4 est testé en premier, une note de 5.5 s'arrête là : « suffisant ». On teste du plus exigeant au moins exigeant.

Piège : la condition qui vaut NULL

Une comparaison avec NULL donne NULL, et une condition NULL n'est pas vraie : si v_note vaut NULL, IF v_note >= 4 passe dans le ELSE, sans erreur.

CASE

CASE choisit une branche selon une valeur (CASE simple : CASE v_classe WHEN '2M1' THEN …) ou selon des conditions (CASE recherché). Si aucune branche ne convient et qu'il n'y a pas de ELSE, PostgreSQL lève l'erreur CASE_NOT_FOUND.2

CASE recherchéPL/pgSQL
DO $$
DECLARE
    v_note   NUMERIC := 3.5;
    v_statut TEXT;
BEGIN
    CASE
        WHEN v_note >= 4 THEN v_statut := 'réussi';
        WHEN v_note < 4 THEN v_statut := 'échoué';
    END CASE;
    RAISE NOTICE 'Statut : %', v_statut;
END $$;
NOTICE:  Statut : échoué
Piège : le CASE sans ELSE

Les deux branches semblent couvrir toutes les notes. Pourtant, avec v_note à NULL, aucune n'est vraie : le bloc s'arrête sur l'erreur case not found. Un ELSE règle le problème.

6Notion 6 · Boucles

LOOP, WHILE, FOR : répéter

Trois boucles pour une même somme, 1 + 2 + 3 + 4 + 5 = 15.

Trois façons de compterPL/pgSQL
DO $$
DECLARE
    v_i     INTEGER := 1;
    v_somme INTEGER := 0;
BEGIN
    LOOP                                -- 1. boucle simple
        v_somme := v_somme + v_i;
        v_i := v_i + 1;
        EXIT WHEN v_i > 5;              -- sans EXIT : boucle infinie
    END LOOP;
    RAISE NOTICE 'LOOP : %', v_somme;

    v_i := 1;  v_somme := 0;
    WHILE v_i <= 5 LOOP                 -- 2. tant que la condition est vraie
        v_somme := v_somme + v_i;
        v_i := v_i + 1;
    END LOOP;
    RAISE NOTICE 'WHILE : %', v_somme;

    v_somme := 0;
    FOR i IN 1..5 LOOP                  -- 3. i est déclaré automatiquement
        v_somme := v_somme + i;
    END LOOP;
    RAISE NOTICE 'FOR : %', v_somme;
END $$;
NOTICE:  LOOP : 15
NOTICE:  WHILE : 15
NOTICE:  FOR : 15
LOOP

Répète sans fin. EXIT ou EXIT WHEN condition en sort ; CONTINUE WHEN condition passe au tour suivant.2

WHILE

Teste la condition avant chaque tour : si elle est fausse dès le départ, la boucle ne tourne pas.2

FOR sur des entiers

Compte d'une borne à l'autre, par pas de 1 ou avec BY. La variable de boucle est déclarée automatiquement comme entier et n'existe que dans la boucle.2

FOR sur une requête

Parcourt les lignes d'un SELECT, une par tour, dans une variable RECORD ou %ROWTYPE.2

Scène 5

La trace d'une boucle FOR

Fais défiler : la boucle de 1 à 5 tour après tour, puis à rebours avec REVERSE, puis un tour sur deux avec BY 2.

Scène 5 · FOR

FOR i IN 1..5

touriv_somme tours effectués 0

Et en Oracle PL/SQL ?Avec REVERSE, Oracle garde les bornes dans l'ordre croissant : FOR i IN REVERSE 1..5 compte de 5 à 1.4 PostgreSQL attend la borne haute en premier, REVERSE 5..1 ; écrit REVERSE 1..5, la boucle n'y fait aucun tour, et aucune erreur n'est levée.2
C'est le piège classique quand on passe d'Oracle à PostgreSQL : même mot-clé, bornes inversées. Si une boucle REVERSE ne fait rien, vérifie l'ordre des bornes.

Parcourir le résultat d'une requête

Une ligne par tourPL/pgSQL
DO $$
DECLARE
    r RECORD;
BEGIN
    FOR r IN SELECT prenom, classe FROM eleves ORDER BY prenom LOOP
        RAISE NOTICE '% (%)', r.prenom, r.classe;
    END LOOP;
END $$;
NOTICE:  Elias (2M1)
NOTICE:  Léa (2M3)
NOTICE:  Noah (2M3)
NOTICE:  Zoé (2M3)
Piège : la variable de boucle non déclarée

Pour FOR i IN 1..5, i est déclaré tout seul. Pour FOR r IN SELECT …, r doit être déclarée (RECORD ou %ROWTYPE), sinon le bloc est refusé : loop variable of loop over rows must be a record variable or list of scalar variables.

Piège : MOD n'est pas un opérateur

En PostgreSQL, le reste d'une division s'écrit i % 2 ou mod(i, 2). CONTINUE WHEN i MOD 2 = 0; provoque une erreur de syntaxe.3

Exercice · prévoir

Combien de tours ?

Cinq débuts de boucle, en PostgreSQL. Combien de fois le corps de la boucle s'exécute-t-il ?

7Notion 7 · RAISE

Afficher un message, lever une erreur

RAISE envoie un message de niveau DEBUG, LOG, INFO, NOTICE ou WARNING, ou lève une erreur avec EXCEPTION, le niveau par défaut. Chaque % du texte est remplacé par l'argument suivant, %% affiche un % ; s'il manque un argument, le bloc est refusé avant même de s'exécuter.3

Par défaut, le client reçoit INFO, NOTICE et WARNING, mais pas DEBUG ni LOG : c'est le réglage client_min_messages, qui vaut NOTICE.3

Refuser une note impossiblePL/pgSQL
DO $$
DECLARE
    v_note NUMERIC := 7;
BEGIN
    IF v_note NOT BETWEEN 1 AND 6 THEN
        RAISE EXCEPTION 'Note % hors de l''échelle 1 à 6', v_note;
    END IF;
    RAISE NOTICE 'Note acceptée';
END $$;
ERROR:  Note 7 hors de l'échelle 1 à 6

L'erreur arrête le bloc : « Note acceptée » ne s'affiche jamais. Pour rattraper une erreur, le bloc reçoit une section EXCEPTION, qui nomme les erreurs attendues.2

Rattraper NO_DATA_FOUNDPL/pgSQL
DO $$
DECLARE
    v_prenom TEXT;
BEGIN
    SELECT prenom INTO STRICT v_prenom FROM eleves WHERE id = 9;
    RAISE NOTICE 'Trouvé : %', v_prenom;
EXCEPTION
    WHEN no_data_found THEN
        RAISE NOTICE 'Aucun élève avec l''id 9';
END $$;
NOTICE:  Aucun élève avec l'id 9
La suite de la sérieLa fiche Procédures et fonctions détaille la section EXCEPTION : le chemin d'une erreur, son coût, les conditions qu'on peut nommer.
Exercice · classer

Accepté ou refusé par PostgreSQL ?

Chaque ligne est placée dans un bloc DO par ailleurs correct, où les variables sont déclarées et où c_tva est une constante. Toutes ont été testées dans PostgreSQL 18. Range chacune.

Habitudes de pro

Sept bonnes pratiques

  • préfixer les noms : v_ pour les variables, c_ pour les constantes ; ils ne se confondent plus avec les colonnes ;
  • initialiser sommes et compteurs (:= 0) : NULL contamine les calculs ;
  • déclarer avec %TYPE : la variable suit le type de la colonne s'il change ;
  • écrire STRICT ou tester FOUND quand l'absence d'une ligne compte ;
  • ordonner les tests d'un IF du plus exigeant au moins exigeant, et prévoir un ELSE dans chaque CASE ;
  • donner à chaque LOOP une sortie claire (EXIT WHEN) ;
  • choisir NUMERIC pour l'argent et les notes, et se méfier de la division entière.
Entraînement

Trois exercices corrigés

Avec les tables eleves et notes de la fiche. Tous les corrigés ont été exécutés dans PostgreSQL 18.

1Écris un bloc qui affiche la table de multiplication de 7, de « 7 x 1 = 7 » à « 7 x 10 = 70 ».Voir le corrigé
DO $$
BEGIN
    FOR i IN 1..10 LOOP
        RAISE NOTICE '7 x % = %', i, 7 * i;
    END LOOP;
END $$;

FOR convient : on connaît le nombre de tours. La variable i n'a pas besoin d'être déclarée.

2Avec une boucle WHILE, calcule 10! (1 × 2 × … × 10) et affiche le résultat.Voir le corrigé
DO $$
DECLARE
    v_n        INTEGER := 10;
    v_resultat BIGINT := 1;
BEGIN
    WHILE v_n > 1 LOOP
        v_resultat := v_resultat * v_n;
        v_n := v_n - 1;
    END LOOP;
    RAISE NOTICE '10! = %', v_resultat;
END $$;
NOTICE:  10! = 3628800

Le produit démarre à 1, pas à NULL ni à 0. BIGINT voit loin : avec INTEGER, 13! (6 227 020 800) provoque déjà l'erreur integer out of range.

3Ce bloc doit compter les élèves dont la moyenne est sous 4. Il contient trois erreurs : trouve-les.Voir le corrigé
DO $$
DECLARE
    v_nb INTEGER;
BEGIN
    FOR r IN SELECT e.prenom, avg(n.note) AS moyenne
             FROM eleves e JOIN notes n ON n.eleve_id = e.id
             GROUP BY e.prenom LOOP
        IF r.moyenne < 4
            v_nb := v_nb + 1;
        END IF;
    END LOOP;
    RAISE NOTICE '% élève(s) sous 4', v_nb;
END $$;

1) r n'est pas déclarée : il faut r RECORD; dans DECLARE. 2) Il manque THEN après la condition. 3) v_nb vaut NULL au départ : le résultat afficherait <NULL>. Version corrigée :

DO $$
DECLARE
    r    RECORD;
    v_nb INTEGER := 0;
BEGIN
    FOR r IN SELECT e.prenom, avg(n.note) AS moyenne
             FROM eleves e JOIN notes n ON n.eleve_id = e.id
             GROUP BY e.prenom LOOP
        IF r.moyenne < 4 THEN
            v_nb := v_nb + 1;
        END IF;
    END LOOP;
    RAISE NOTICE '% élève(s) sous 4', v_nb;
END $$;
NOTICE:  1 élève(s) sous 4
À retenir

La fiche en huit lignes

BlocDO $$ [DECLARE …] BEGIN … [EXCEPTION …] END $$; exécuté une fois, rien n'est stocké.
BEGINregroupe des instructions ; il n'ouvre aucune transaction.
Variablesnom type := valeur ; sans valeur, NULL ; CONSTANT interdit toute affectation.
Types%TYPE copie le type d'une colonne, %ROWTYPE une ligne entière ; NUMERIC pour les montants.
SELECT INTOaucune ligne : NULL et FOUND faux ; plusieurs : la première ; STRICT exige une seule ligne.
ConditionsIF teste dans l'ordre, la première branche vraie gagne ; CASE sans ELSE peut lever CASE_NOT_FOUND.
BouclesLOOP + EXIT WHEN, WHILE, FOR i IN 1..5 ; REVERSE 5..1 en PostgreSQL, REVERSE 1..5 en Oracle.
RAISENOTICE affiche, EXCEPTION (par défaut) arrête le bloc ; un % par argument.
Dernière étape : le quiz. Douze questions tirées au hasard, différentes à chaque partie. Si tu te trompes, lis bien l'explication.
Quiz final

Teste-toi

Sources

  1. PostgreSQL 18 Documentation, PL/pgSQL : Overview (avantages du langage), Structure of PL/pgSQL (blocs, point-virgule, BEGIN sans transaction), Declarations (NULL par défaut, CONSTANT, NOT NULL, %TYPE, %ROWTYPE, RECORD, variable de boucle). vue d'ensemble, structure, déclarations (postgresql.org)
  2. PostgreSQL 18 Documentation, PL/pgSQL : Basic Statements (affectation, SELECT INTO et STRICT, FOUND, PERFORM, GET DIAGNOSTICS) et Control Structures (IF, CASE, LOOP, WHILE, FOR, REVERSE, interception des erreurs). instructions de base, structures de contrôle (postgresql.org)
  3. PostgreSQL 18 Documentation : DO, Lexical Structure (chaînes entre dollars), Mathematical Functions and Operators (division entière, %, mod), PL/pgSQL Errors and Messages (RAISE) et client_min_messages. DO, syntaxe, opérateurs, RAISE, client_min_messages (postgresql.org)
  4. Oracle, Database PL/SQL Language Reference 19c : « Block », « FOR LOOP Statement » (REVERSE), « SELECT INTO Statement » (NO_DATA_FOUND). bloc, FOR LOOP, SELECT INTO (docs.oracle.com)
  5. Administration fédérale des contributions (AFC), Taux de TVA en Suisse : taux normal de 8,1 % depuis le 1er janvier 2024. estv.admin.ch

Fiche écrite et sourcée en octobre 2026. Tout le code a été exécuté dans PostgreSQL 18.

Glisser pour continuer vers Procédures et fonctions
Bachelor Informatique