Les fonctions SQL et les procédures stockées sont deux outils distincts que tout data analyst doit maîtriser, mais ils sont souvent confondus en entretien technique. Une fonction SQL retourne toujours une valeur et peut être utilisée dans un SELECT ; une procédure stockée exécute un bloc de logique métier et ne retourne pas nécessairement de résultat. Cette distinction, simple en apparence, cache des différences profondes en termes de comportement, de gestion des transactions et de performances. Comprendre quand utiliser l'un ou l'autre vous permettra non seulement de structurer du code SQL plus robuste, mais aussi de répondre avec précision aux questions d'entretien qui portent sur l'architecture d'une base de données.
📌 Ce qu'il faut retenir
- Une fonction SQL retourne obligatoirement une valeur (scalaire ou table) et peut être appelée dans un SELECT, WHERE ou JOIN.
- Une procédure stockée exécute une suite d'instructions SQL, gère des transactions et peut retourner 0, 1 ou plusieurs résultats via des paramètres OUT.
- Les fonctions sont déterministes (même entrée → même sortie) ; les procédures peuvent avoir des effets de bord.
- En entretien, la question "fonctions vs procédures" teste votre compréhension de l'architecture SQL, pas seulement de la syntaxe.
Ce que la norme SQL entend par "routine"
Le standard SQL regroupe fonctions et procédures sous le terme générique de routines stockées (stored routines). Les deux sont compilées une fois et stockées dans le catalogue de la base de données. Mais leurs contrats d'interface diffèrent radicalement.
Une fonction (User-Defined Function, UDF) :
- accepte 0 ou plusieurs paramètres en entrée (IN uniquement),
- retourne exactement une valeur (scalaire) ou un ensemble de lignes (table),
- peut être invoquée partout où une expression SQL est valide.
Une procédure (Stored Procedure) :
- accepte des paramètres IN, OUT et INOUT,
- est appelée via
CALL(MySQL/PostgreSQL) ouEXEC(SQL Server), - peut exécuter des instructions DDL, gérer des transactions (
COMMIT,ROLLBACK) et lever des exceptions.
Cette distinction est fondamentale : une fonction ne peut pas appeler COMMIT ou modifier l'état transactionnel en PostgreSQL et SQL Server, contrairement à une procédure.
Syntaxe comparée sur les 3 SGBD majeurs
PostgreSQL
-- Fonction scalaire
CREATE OR REPLACE FUNCTION calcul_tva(prix NUMERIC, taux NUMERIC DEFAULT 0.20)
RETURNS NUMERIC
LANGUAGE SQL
IMMUTABLE
AS $$
SELECT ROUND(prix * taux, 2);
$$;
-- Appel dans un SELECT
SELECT produit, prix_ht, calcul_tva(prix_ht) AS tva
FROM catalogue;
-- Procédure stockée (PostgreSQL 11+)
CREATE OR REPLACE PROCEDURE archiver_commandes(p_date_limite DATE)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO commandes_archivees
SELECT * FROM commandes WHERE date_commande < p_date_limite;
DELETE FROM commandes WHERE date_commande < p_date_limite;
COMMIT;
END;
$$;
-- Appel
CALL archiver_commandes('2026-01-01');
MySQL / MariaDB
-- Fonction
DELIMITER $$
CREATE FUNCTION age_client(date_naissance DATE)
RETURNS INT
DETERMINISTIC
BEGIN
RETURN TIMESTAMPDIFF(YEAR, date_naissance, CURDATE());
END$$
DELIMITER ;
-- Procédure avec paramètre OUT
DELIMITER $$
CREATE PROCEDURE stats_ventes(
IN p_annee INT,
OUT p_total DECIMAL(15,2)
)
BEGIN
SELECT SUM(montant) INTO p_total
FROM ventes
WHERE YEAR(date_vente) = p_annee;
END$$
DELIMITER ;
-- Appel
CALL stats_ventes(2026, @resultat);
SELECT @resultat;
SQL Server (T-SQL)
-- Fonction scalaire
CREATE FUNCTION dbo.fn_categorie_prix(@prix MONEY)
RETURNS VARCHAR(20)
AS
BEGIN
RETURN CASE
WHEN @prix < 50 THEN 'Entrée de gamme'
WHEN @prix < 200 THEN 'Milieu de gamme'
ELSE 'Premium'
END;
END;
-- Procédure
CREATE PROCEDURE dbo.usp_transfert_stock
@produit_id INT,
@depot_source INT,
@depot_dest INT,
@quantite INT
AS
BEGIN
BEGIN TRANSACTION;
BEGIN TRY
UPDATE stock SET qte = qte - @quantite
WHERE produit_id = @produit_id AND depot_id = @depot_source;
UPDATE stock SET qte = qte + @quantite
WHERE produit_id = @produit_id AND depot_id = @depot_dest;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
THROW;
END CATCH;
END;
💡 Bon à savoir
En SQL Server, les fonctions scalaires appelées dans un SELECT peuvent provoquer des problèmes de performance sévères car elles s'exécutent ligne par ligne (évaluation en mode "row-based"). Privilégiez les fonctions table en ligne (inline table-valued functions) qui sont optimisées par le moteur comme une vue paramétrée.
Tableau comparatif : fonctions vs procédures
| Critère | Fonction (UDF) | Procédure stockée |
|---|---|---|
| Valeur de retour | Obligatoire (scalaire ou table) | Optionnelle (paramètres OUT) |
| Appel SQL | Dans SELECT, WHERE, JOIN | Via CALL / EXEC uniquement |
| Transactions (COMMIT/ROLLBACK) | Interdit (PostgreSQL, SQL Server) | Autorisé |
| Instructions DDL (CREATE, DROP…) | Interdit dans la plupart des SGBD | Autorisé |
| Paramètres IN / OUT | IN uniquement | IN, OUT, INOUT |
| Gestion d'exceptions | Limitée | Complète (BEGIN TRY…CATCH) |
| Effets de bord (DML) | Interdit (fonctions pures) | Autorisé (INSERT, UPDATE, DELETE) |
| Utilisation dans une vue | Oui | Non |
| Performance typique | Variable (inline = rapide, scalaire = lent) | Bonne (plan mis en cache) |
