Il y a quelques niveaux, on a déjà parlé des procédures et fonctions dans PostgreSQL. Il est temps de creuser un peu plus.
Les fonctions et les procédures peuvent bosser chacune dans leur coin, mais en vrai, c'est souvent leur interaction qui fait que tout roule dans le système. Le gros avantage, c'est qu'on peut appeler une fonction depuis une autre, passer des données et même récupérer le résultat.
Fonctions vs Procédures : c'est quoi la diff ?
Petit rappel sur ce qui distingue les fonctions des procédures dans PostgreSQL :
Fonctions (
FUNCTION) :- Renvoient des valeurs.
- Peuvent être utilisées dans un
SELECT. - Souvent utilisées pour faire des calculs ou transformer des données.
Procédures (
PROCEDURE) :- Ne renvoient pas de valeur directement.
- Servent à faire des opérations comme insérer, mettre à jour ou supprimer des données.
- S'appellent avec la commande
CALL.
Passage de données entre fonctions
Passons à la pratique avec un exemple basique de passage de données entre une fonction et une procédure. En gros, les données passent entre fonctions via les paramètres et les valeurs de retour.
Voilà à quoi ressemble l'appel d'une fonction dans une autre fonction :
CREATE OR REPLACE FUNCTION get_student_name(student_id INT)
RETURNS TEXT AS $$
DECLARE
student_name TEXT;
BEGIN
-- On récupère le nom de l'étudiant par son ID
SELECT nom INTO student_name FROM students WHERE id = student_id;
-- On retourne le nom
RETURN student_name;
END;
$$ LANGUAGE plpgsql;
Tu peux appeler cette fonction depuis une autre fonction :
CREATE OR REPLACE FUNCTION welcome_student(student_id INT)
RETURNS TEXT AS $$
DECLARE
message TEXT;
BEGIN
-- On récupère le nom de l'étudiant avec une autre fonction
message := 'Bienvenue, ' || get_student_name(student_id) || ' !';
-- On retourne le message de bienvenue
RETURN message;
END;
$$ LANGUAGE plpgsql;
- La fonction
get_student_namerenvoie le nom de l'étudiant à partir de son identifiant (student_id). - Dans l'autre fonction —
welcome_student— ce nom sert à créer un message de bienvenue.
Remarque : Récupérer des données avec SELECT INTO permet de stocker le résultat de la requête dans une variable PL/pgSQL.
Exemple d'appel de procédures depuis des fonctions
Voyons maintenant comment appeler une procédure depuis une fonction. Imaginons qu'on a une procédure qui enregistre l'heure d'entrée d'un étudiant dans le système :
CREATE OR REPLACE PROCEDURE log_student_entry(student_id INT)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO log_entries(student_id, entry_time)
VALUES (student_id, NOW());
END;
$$;
On va maintenant appeler cette procédure depuis une fonction, qui va enregistrer l'entrée et retourner un message :
CREATE OR REPLACE FUNCTION student_login(student_id INT)
RETURNS TEXT AS $$
BEGIN
-- On appelle la procédure pour logger l'entrée
CALL log_student_entry(student_id);
-- On retourne le message
RETURN 'Connexion de l\'étudiant enregistrée avec succès.';
END;
$$ LANGUAGE plpgsql;
Exemples pratiques d'interaction
Exemple 1 : calcul du total de commande et log de la commande
Imagine que tu bosses sur un système de commandes en ligne. Pour calculer le total d'une commande, tu as une fonction :
CREATE OR REPLACE FUNCTION calculate_order_total(order_id INT)
RETURNS NUMERIC AS $$
DECLARE
total NUMERIC;
BEGIN
-- On additionne toutes les lignes de la commande
SELECT SUM(prix * quantite) INTO total
FROM order_items
WHERE order_id = order_id;
RETURN total;
END;
$$ LANGUAGE plpgsql;
Pour sauvegarder le total de la commande, on utilise une procédure :
CREATE OR REPLACE PROCEDURE log_order_total(order_id INT, total NUMERIC)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO order_totals(order_id, total)
VALUES (order_id, total);
END;
$$;
On les relie maintenant ensemble :
CREATE OR REPLACE FUNCTION process_order(order_id INT)
RETURNS TEXT AS $$
DECLARE
total NUMERIC;
BEGIN
-- On appelle la fonction pour calculer le total
total := calculate_order_total(order_id);
-- On log le total via la procédure
CALL log_order_total(order_id, total);
RETURN 'Commande traitée avec succès.';
END;
$$ LANGUAGE plpgsql;
Exemple 2 : obtenir la note max d'un étudiant et mettre à jour son profil
Fonction pour obtenir la note maximale :
CREATE OR REPLACE FUNCTION get_highest_rating(student_id INT)
RETURNS INT AS $$
DECLARE
max_rating INT;
BEGIN
-- On cherche la note max de l'étudiant
SELECT MAX(note) INTO max_rating
FROM ratings
WHERE student_id = student_id;
RETURN max_rating;
END;
$$ LANGUAGE plpgsql;
Procédure pour mettre à jour le profil de l'étudiant :
CREATE OR REPLACE PROCEDURE update_student_profile(student_id INT, max_rating INT)
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE students
SET highest_rating = max_rating
WHERE id = student_id;
END;
$$;
Fonction pour appeler ces opérations :
CREATE OR REPLACE FUNCTION refresh_student_profile(student_id INT)
RETURNS TEXT AS $$
DECLARE
max_rating INT;
BEGIN
-- On récupère la note max
max_rating := get_highest_rating(student_id);
-- On met à jour le profil de l'étudiant
CALL update_student_profile(student_id, max_rating);
RETURN 'Profil mis à jour avec succès.';
END;
$$ LANGUAGE plpgsql;
Erreurs typiques lors de l'interaction
Une des erreurs les plus courantes, c'est le mauvais type de données entre la fonction et la procédure. Par exemple, si ta procédure attend un paramètre de type NUMERIC et que tu lui passes un INTEGER, PostgreSQL va râler à cause du type. Vérifie toujours que les types correspondent.
Une autre erreur, c'est l'appel cyclique de fonctions, genre la fonction A appelle la fonction B, qui rappelle A, etc. Ça finit en boucle infinie et crash du système.
Pourquoi c'est utile ?
Pourquoi on a besoin de ce genre d'interaction ? Dans la vraie vie, fonctions et procédures sont comme des "briques" pour construire des systèmes complexes. Ça permet de découper le code en morceaux indépendants, ce qui rend le débogage, la réutilisation et les tests beaucoup plus simples. Par exemple :
- En entretien, on peut te demander d'écrire une fonction qui appelle une procédure pour faire une opération compliquée. Montrer que tu sais faire ça, c'est un gros plus.
- Quand tu développes des vraies applis, genre des boutiques en ligne, des systèmes de logs ou des CRM, bien organiser la logique avec des fonctions et procédures rend le code beaucoup plus propre.
Pour aller plus loin sur l'interaction entre fonctions et procédures, tu peux jeter un œil à la doc officielle de PL/pgSQL.
GO TO FULL VERSION