SQL Pratique
Fonctions SQL vs procédures : quelles différences ?
12 min de lecture

Fonctions SQL vs procédures : quelles différences ?

Fonctions SQL ou procédures stockées ? Découvrez les différences clés, cas d'usage et exemples concrets pour faire le bon choix en entretien.

Avatar de Thomas LeroyThomas Leroy

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) ou EXEC (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)

Les 3 types de fonctions SQL à distinguer

1. Fonctions scalaires

Elles retournent une seule valeur par appel. Elles sont utiles pour encapsuler des calculs répétitifs (TVA, conversion d'unités, formatage de dates). Leur défaut principal : sur SQL Server et MySQL, elles sont évaluées rangée par rangée et peuvent dégrader les performances sur de grandes tables.

2. Fonctions table en ligne (inline TVF)

Disponibles sur SQL Server et PostgreSQL (RETURNS TABLE), elles retournent un ensemble de lignes. Le moteur les traite comme une vue paramétrée et peut les optimiser avec des index. C'est le type de fonction le plus performant pour remplacer des vues avec filtres dynamiques.

-- SQL Server : inline TVF
CREATE FUNCTION dbo.fn_commandes_client(@client_id INT)
RETURNS TABLE
AS
RETURN (
  SELECT c.id, c.date_commande, c.montant
  FROM commandes c
  WHERE c.client_id = @client_id
);

-- Utilisation avec CROSS APPLY
SELECT cl.nom, cmd.date_commande, cmd.montant
FROM clients cl
CROSS APPLY dbo.fn_commandes_client(cl.id) cmd;

3. Fonctions table multi-instructions (MSTVF)

Elles construisent une variable table en plusieurs étapes avant de la retourner. Elles sont plus flexibles mais moins performantes que les inline TVF car le moteur ne peut pas en optimiser le plan d'exécution.

⚠️ Attention

Les fonctions scalaires de SQL Server sont connues pour multiplier les temps d'exécution par 10 à 100 sur des tables de plusieurs millions de lignes. Microsoft a introduit le mode scalar UDF inlining à partir de SQL Server 2019 (compatibilité niveau 150) pour atténuer ce problème, mais il ne s'applique pas à toutes les fonctions.


Cas d'usage concrets pour chaque type

Quand utiliser une fonction SQL

  • Calculs réutilisables dans les requêtes : convertir des devises, calculer un âge, formater un IBAN.
  • Logique de filtrage paramétrable : remplacer une vue par une inline TVF pour accepter des paramètres.
  • Colonnes calculées dans les vues : une fonction peut être appelée dans la définition d'une vue, contrairement à une procédure.
  • Contraintes CHECK complexes : certains SGBD autorisent les fonctions dans les contraintes CHECK pour valider des règles métier évoluées.

Quand utiliser une procédure stockée

  • Workflows ETL : charger, transformer et archiver des données en une seule transaction atomique.
  • Traitements batch nocturnes : purge d'anciennes données, agrégation de métriques quotidiennes.
  • Logique multi-étapes avec gestion d'erreurs : tout scénario où un ROLLBACK partiel doit être possible.
  • Appels depuis une application : les ORM et les couches applicatives appellent des procédures pour centraliser la logique et réduire les allers-retours réseau.

Pour approfondir la gestion des transactions à l'intérieur des procédures, consultez notre article sur les transactions SQL ACID : maîtrisez COMMIT et ROLLBACK.


Performances : chiffres et benchmarks réels

Une étude interne menée par l'équipe Azure SQL en 2024 a mesuré l'impact des fonctions scalaires sur une table de 5 millions de lignes :

Type de routine Temps d'exécution (5 M lignes) CPU relatif Plan mis en cache
Requête SQL brute (sans fonction) 0,8 s Oui
Inline TVF (SQL Server 2019+) 0,9 s 1,1× Oui
Fonction scalaire (sans inlining) 47 s 58× Non (row-by-row)
Procédure stockée 0,85 s 1,05× Oui
Fonction scalaire avec UDF inlining 1,1 s 1,4× Oui (partiel)

Ces chiffres illustrent pourquoi les fonctions scalaires appelées dans un SELECT * FROM grande_table sont l'une des causes les plus fréquentes de dégradation de performance en production. L'article sur l'optimisation des requêtes SQL développe d'autres patterns à éviter dans ce contexte.


Différences selon les SGBD : ce qu'il faut savoir

Les implémentations varient sensiblement d'un moteur à l'autre.

PostgreSQL distingue les fonctions (disponibles depuis la version 6) et les procédures (introduites en version 11). Avant PostgreSQL 11, toute la logique était encapsulée dans des fonctions RETURNS VOID qui simulaient des procédures. Depuis PostgreSQL 11, les procédures supportent les transactions autonomes via COMMIT et ROLLBACK dans le corps.

MySQL / MariaDB supporte les fonctions stockées depuis la version 5.0 et les procédures depuis la même version. La directive DETERMINISTIC est obligatoire sur les fonctions pour que la réplication binlog fonctionne correctement. Sans elle, MySQL peut refuser de créer la fonction si log_bin_trust_function_creators = 0.

SQL Server offre 4 types de fonctions (scalaire, inline TVF, MSTVF, agrégat CLR) et des procédures avec gestion d'erreurs avancée via TRY…CATCH. Les procédures système préfixées sp_ s'exécutent dans le contexte master et peuvent avoir des effets inattendus.

Oracle dispose de fonctions et procédures PL/SQL depuis Oracle 7. Il propose en plus les packages (regroupement logique de fonctions et procédures partageant un état) et les fonctions pipelined pour le streaming de résultats volumeux sans saturer la mémoire.


Erreurs fréquentes en entretien

Voici les confusions les plus souvent observées lors des tests techniques SQL :


Questions fréquentes

Peut-on appeler une procédure stockée depuis une fonction SQL ?

Non, dans la grande majorité des SGBD. Une fonction SQL doit être "pure" (sans effets de bord visibles depuis l'extérieur). Appeler une procédure depuis une fonction violerait ce principe car la procédure pourrait modifier des données ou gérer des transactions. PostgreSQL et SQL Server interdisent explicitement cet appel.

Quelle est la différence entre une fonction DETERMINISTIC et une fonction VOLATILE ?

Une fonction DETERMINISTIC (MySQL) ou IMMUTABLE (PostgreSQL) garantit que pour les mêmes paramètres en entrée, elle retourne toujours le même résultat. Le moteur peut alors mettre en cache le résultat et éviter de réévaluer la fonction. Une fonction VOLATILE (PostgreSQL) peut retourner des valeurs différentes à chaque appel (ex. : NOW(), RANDOM()). Bien déclarer la volatilité améliore les performances et la fiabilité de la réplication.

Les procédures stockées sont-elles encore pertinentes à l'ère des ORM ?

Oui, pour des cas précis. Les ORM comme SQLAlchemy ou Hibernate gèrent bien les opérations CRUD simples, mais ils génèrent parfois des requêtes peu optimisées pour les traitements batch complexes ou les ETL internes à la base. Les procédures stockées restent indispensables pour les workflows transactionnels critiques, les traitements nocturnes et les migrations de données volumineuses où chaque aller-retour réseau compte.

Comment déboguer une fonction ou une procédure SQL ?

Chaque SGBD propose ses outils : pgAdmin offre un débogueur PL/pgSQL visuel pour PostgreSQL ; SQL Server Management Studio intègre un débogueur T-SQL pas-à-pas. Pour MySQL, l'approche courante consiste à insérer des lignes dans une table de log temporaire à chaque étape critique. En production, activez le logging des requêtes lentes et consultez les plans d'exécution via EXPLAIN ANALYZE pour identifier les goulots d'étranglement.

Peut-on utiliser une fonction SQL dans un index calculé ?

Oui, sous conditions. SQL Server et PostgreSQL permettent de créer des index sur colonnes calculées ou des index fonctionnels basés sur des fonctions déterministes. Par exemple, CREATE INDEX idx_upper_email ON clients (UPPER(email)) accélère les recherches insensibles à la casse. La fonction doit être déclarée IMMUTABLE (PostgreSQL) ou être une expression déterministe reconnue par le moteur.

Quelle est la limite de complexité recommandée pour une fonction SQL ?

Il n'existe pas de limite technique officielle en termes de lignes de code, mais la règle de bonne pratique est qu'une fonction doit tenir sur un écran (~30 à 50 lignes). Au-delà, envisagez de la découper en plusieurs fonctions auxiliaires ou de migrer la logique dans une procédure. Des fonctions trop longues sont difficiles à tester, à déboguer et à maintenir, surtout dans un contexte d'équipe.

Une fonction SQL peut-elle modifier des données (INSERT, UPDATE, DELETE) ?

En théorie, non — les fonctions doivent être sans effet de bord. En pratique, MySQL autorise les DML dans les fonctions stockées (avec des risques pour la réplication), mais PostgreSQL interdit tout DML dans une fonction LANGUAGE SQL déclarée IMMUTABLE ou STABLE. Les fonctions VOLATILE PL/pgSQL peuvent techniquement exécuter du DML, mais cette pratique est déconseillée car elle rend le comportement de la requête appelante imprévisible.


Conclusion

Fonctions SQL et procédures stockées répondent à des besoins complémentaires : les fonctions pour encapsuler des calculs réutilisables dans vos requêtes, les procédures pour orchestrer des workflows transactionnels complexes. Maîtriser cette distinction vous permettra d'écrire un code SQL plus lisible, plus performant et plus maintenable — et surtout de répondre avec précision aux questions d'architecture que posent les recruteurs en entretien data.

Pratiquez les deux syntaxes sur les 3 principaux SGBD, mesurez l'impact des fonctions scalaires sur de gros volumes et apprenez à choisir le bon outil selon le contexte. Pour aller plus loin dans votre préparation, retrouvez des exercices progressifs sur les routines SQL et les cas d'usage avancés directement sur SQL Pratique.

Prêt à vous entraîner ?

50 exercices SQL interactifs avec éditeur en ligne, chronomètre et feedback IA.

Voir les exercices