Le SQL dynamique en PL/SQL : EXECUTE IMMEDIATE (guide complet)

Le SQL dynamique en PL/SQL Oracle : EXECUTE IMMEDIATE, USING, INTO, DDL dynamique, sécurité anti-injection et DBMS_SQL, avec exemples concrets.

Illustration : SQL dynamique EXECUTE IMMEDIATE en PL/SQL

Le SQL dynamique permet de construire et d’exécuter des requêtes dont le texte n’est connu qu’à l’exécution. En PL/SQL, on l’utilise via EXECUTE IMMEDIATE (et DBMS_SQL pour les cas avancés). Indispensable pour le DDL, les noms de tables variables ou les filtres dynamiques — mais à manier avec rigueur pour éviter l’injection SQL.

Publicité

🧪 Envie de pratiquer ? Exécutez les exemples de cet article dans notre SQL Playground gratuit — aucun logiciel à installer.

Pourquoi le SQL dynamique ?

Le PL/SQL « statique » ne permet pas certaines choses :

  • exécuter du DDL (CREATE, ALTER, TRUNCATE) dans une procédure ;
  • changer le nom de la table/colonne au moment de l’exécution ;
  • construire un WHERE selon des critères optionnels.

EXECUTE IMMEDIATE : la base

BEGIN
  -- DDL (impossible en PL/SQL statique)
  EXECUTE IMMEDIATE 'TRUNCATE TABLE logs_temp';
END;

Récupérer une valeur : INTO

DECLARE
  v_nb NUMBER;
  v_table VARCHAR2(30) := 'CLIENTS';
BEGIN
  EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || v_table INTO v_nb;
  DBMS_OUTPUT.put_line(v_nb);
END;

Passer des paramètres : USING (à TOUJOURS privilégier)

DECLARE
  v_nom clients.nom%TYPE;
BEGIN
  EXECUTE IMMEDIATE
    'SELECT nom FROM clients WHERE id = :1'
    INTO v_nom
    USING p_id;           -- bind variable, pas de concaténation
END;

Les bind variables (:1 + USING) protègent contre l’injection SQL et améliorent les performances (réutilisation des plans).

⚠️ Sécurité : éviter l’injection SQL

-- ❌ DANGER : concaténer une valeur utilisateur
EXECUTE IMMEDIATE 'SELECT * FROM clients WHERE nom = ''' || p_nom || '''';

-- ✅ paramètre lié
EXECUTE IMMEDIATE 'SELECT * FROM clients WHERE nom = :1' USING p_nom;

Règle : les valeurs passent par USING. Seuls les identifiants (nom de table/colonne) se concatènent — et uniquement après validation (liste blanche, DBMS_ASSERT.SQL_OBJECT_NAME).

v_table := DBMS_ASSERT.SQL_OBJECT_NAME(v_table);  -- valide le nom d'objet

DML dynamique et nombre de lignes

DECLARE
  v_maj NUMBER;
BEGIN
  EXECUTE IMMEDIATE
    'UPDATE comptes SET solde = solde * :taux WHERE actif = :a'
    USING 1.01, 'O';
  v_maj := SQL%ROWCOUNT;
  DBMS_OUTPUT.put_line(v_maj || ' comptes mis à jour');
END;

WHERE dynamique (filtres optionnels)

DECLARE
  v_sql  VARCHAR2(4000) := 'SELECT * FROM clients WHERE 1=1';
  v_cur  SYS_REFCURSOR;
BEGIN
  IF p_ville IS NOT NULL THEN
    v_sql := v_sql || ' AND ville = :v';
  END IF;
  -- ... ouverture avec les bons USING selon les filtres
END;

Pour des cas très dynamiques (nombre de colonnes inconnu), passez à DBMS_SQL, plus verbeux mais totalement flexible.

EXECUTE IMMEDIATE vs DBMS_SQL

  • EXECUTE IMMEDIATE : simple, rapide, couvre 90% des besoins (structure connue à l’écriture).
  • DBMS_SQL : pour le « method 4 » — nombre de colonnes/binds inconnu à l’avance.

Bonnes pratiques

  1. Valeurs → USING ; jamais de concaténation de données utilisateur.
  2. Identifiants concaténés → valider avec DBMS_ASSERT.
  3. Le SQL dynamique est plus difficile à maintenir : ne l’utilisez que lorsque le statique ne suffit pas.

FAQ

Pourquoi utiliser EXECUTE IMMEDIATE plutôt qu’une requête normale ?

Uniquement quand le texte SQL n’est pas connu à l’écriture : DDL, nom d’objet variable, filtres optionnels. Sinon, le SQL statique est plus sûr et plus lisible.

EXECUTE IMMEDIATE protège-t-il de l’injection SQL ?

Seulement si vous passez les valeurs par USING (bind variables). La concaténation de données utilisateur reste vulnérable.

Peut-on faire un COMMIT dans du SQL dynamique ?

Oui, mais le DDL (CREATE/ALTER/TRUNCATE) effectue de toute façon un COMMIT implicite — attention aux transactions en cours.

Un nouveau tutoriel SQL par semaine

Nous ne spammons pas ! Consultez notre politique de confidentialité pour plus d’informations.

Publicité

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Publicité