Aller au contenu
guide

Le text-to-SQL expliqué : du langage naturel à la requête SQL

Ce qu’exige un text-to-SQL fiable : la requête est construite à partir du contexte de schéma, vérifiée par un validateur en lecture seule, puis livrée avec ses preuves.

Par l'équipe Datarelix · Publié le · Mis à jour le · Vérifié le

Le text-to-SQL, aussi écrit « langage naturel vers SQL », consiste à transformer une question formulée en langage courant en une requête de base de données. En production, un text-to-SQL fiable n’est pas un prompt unique qui produit du SQL. C’est un flux de travail gouverné : le modèle reçoit votre question et la structure de votre schéma et renvoie un plan structuré, un validateur en lecture seule contrôle la requête générée avant toute exécution, une couche d’exécution distincte la lance sur votre base de données, et la réponse arrive avec les preuves nécessaires pour la vérifier.

La distinction essentielle : un générateur SQL par IA face à un pipeline gouverné

La version naïve du text-to-SQL tient en un seul appel : vous envoyez la question et un peu de texte de schéma à un modèle, vous récupérez une chaîne SQL, vous l’exécutez. Cette conception pose deux problèmes structurels. D’abord, ce que le modèle écrit est exactement ce qui s’exécute, y compris un DROP TABLE qu’il a halluciné ou une jointure qui balaie un milliard de lignes. Ensuite, rien ne relie la réponse à la requête, donc personne ne peut vérifier ce qui a réellement été mesuré.

Un système de production sépare les responsabilités. Le rôle du modèle se limite à proposer. Décider si la proposition est sûre, l’exécuter et consigner ce qui s’est passé reviennent à d’autres composants, sur lesquels le modèle n’a aucune prise.

À qui s’adresse cette explication du mécanisme

Les responsables data qui évaluent des outils d’analytique conversationnelle et veulent savoir ce qui se passe réellement entre la question et le graphique. Les ingénieurs analytics à qui l’on demandera de connecter une base de données et qui doivent raisonner sur ce que le modèle reçoit et ce qu’il peut faire. Toute personne qui a vu une démo où une question en langage courant devient du SQL et qui veut le mécanisme plutôt que la magie.

Le pipeline, étape par étape

1. Contexte de schéma : ce que le modèle reçoit

Le modèle ne peut pas écrire du SQL correct sur des tables qu’il ne connaît pas : la première étape assemble donc le contexte de schéma — noms de tables et de colonnes, types de données, clés primaires et étrangères, et les descriptions rédigées qui leur sont attachées. La structure seulement : aucune ligne d’exemple, aucune valeur de cellule. Les identifiants de connexion ne font partie de ce contexte à aucune étape ; ils restent dans la couche d’exécution, sujet de comment les identifiants restent hors du modèle.

2. Génération du plan : le modèle propose, rien de plus

À partir de la question et du contexte de schéma, le modèle renvoie un plan structuré plutôt que des actions libres. Le modèle lui-même n’exécute rien. C’est important parce qu’un plan est inerte : il peut être inspecté, validé par rapport à un schéma strict, et rejeté avant que la moindre de ses parties n’atteigne une base de données.

3. Validation en lecture seule : appliquée avant l’exécution

Chaque instruction générée est analysée en arbre syntaxique complet et rejetée si ce n’est pas une lecture — comment fonctionne le validateur. Les instructions SELECT, les CTE et les opérations ensemblistes passent ; UPDATE, DELETE, INSERT, le DDL et les commandes d’administration n’ont aucune voie de passage. Les langages de requête qui ne sont pas du SQL, comme KQL et ES|QL, passent par des validateurs dédiés qui leur sont propres. Des limites de lignes automatiques s’appliquent à chaque requête : une question sans borne ne peut pas renvoyer un résultat sans borne.

4. Exécution : un service de requêtes isolé détient la connexion

La requête validée s’exécute dans un service de requêtes isolé, le seul composant qui détient la connexion à la base de données. Les identifiants sont déchiffrés au moment de l’exécution uniquement et n’entrent jamais dans le contexte du modèle — la frontière des identifiants.

5. Corriger et réessayer, dans des limites strictes

Les schémas réels produisent de vraies erreurs : une colonne mal orthographiée, un type incompatible, une particularité de dialecte. Quand une requête échoue, l’erreur de la base repart vers le modèle, qui corrige la requête et réessaie automatiquement, dans des limites strictes, chaque tentative passant par la même validation en lecture seule que la première.

6. Interprétation et preuves

Le résultat revient accompagné de la requête exécutée, des tables lues, du nombre de lignes et du temps d’exécution — ce que chacun des quatre vous apprend. Les tables de résultats ne repartent pas vers le modèle. Une exception : une valeur de réponse sur une seule ligne peut être reprise dans le contexte des questions suivantes, pour qu’un « et par rapport à l’an dernier ? » ait du sens — ce qui entre dans le contexte.

Pourquoi une même question peut produire des SQL différents

Le langage naturel est sous-spécifié, et le modèle doit trancher pour une lecture. Les deux lectures ci-dessous donnent du SQL défendable — c’est précisément pour cela que le système doit vous montrer la requête qu’il a choisie.

QuestionLecture ALecture B
« Meilleurs clients »Classés par chiffre d’affaires : SUM(quantity * unit_price)Classés par volume : COUNT(DISTINCT order_id)
« Le trimestre dernier »Trimestre civil précédent : Apr 1 – Jun 3090 jours glissants à partir d’aujourd’hui
« Utilisateurs actifs »Connectés récemment : last_login_at >= …Ayant acheté récemment : EXISTS (SELECT … FROM orders …)
« Chiffre d’affaires »Brut : somme de toutes les lignes de commandes terminéesNet : brut moins les lignes remboursées

Aucune de ces lectures n’est fausse ; elles mesurent des choses différentes. Un système qui cache son SQL vous oblige à deviner laquelle vous avez obtenue. Un système qui l’affiche vous laisse confirmer la lecture d’un coup d’œil — l’habitude décrite dans comment vérifier les réponses d’une IA sur vos données.

D’une question en langage courant au SQL : un exemple détaillé

Les exemples ci-dessous utilisent le schéma de démonstration d’un détaillant fictif — customers, orders, order_items — et sont illustratifs : ce ne sont pas les sorties d’un système en production.

Question : « Quels ont été nos 10 meilleurs clients par chiffre d’affaires au T2 2026 ? »

Sur PostgreSQL, une requête générée plausible ressemble à ceci :

SELECT
  c.customer_id,
  c.name,
  SUM(oi.quantity * oi.unit_price) AS revenue
FROM customers AS c
JOIN orders AS o ON o.customer_id = c.customer_id
JOIN order_items AS oi ON oi.order_id = o.order_id
WHERE o.status = 'completed'
  AND o.ordered_at >= DATE '2026-04-01'
  AND o.ordered_at < DATE '2026-07-01'
GROUP BY c.customer_id, c.name
ORDER BY revenue DESC
LIMIT 10;

La même question sur BigQuery produit une requête structurellement identique, avec des différences de dialecte :

SELECT
  c.customer_id,
  c.name,
  SUM(oi.quantity * oi.unit_price) AS revenue
FROM `demo_retail.customers` AS c
JOIN `demo_retail.orders` AS o ON o.customer_id = c.customer_id
JOIN `demo_retail.order_items` AS oi ON oi.order_id = o.order_id
WHERE o.status = 'completed'
  AND DATE(o.ordered_at) >= '2026-04-01'
  AND DATE(o.ordered_at) < '2026-07-01'
GROUP BY c.customer_id, c.name
ORDER BY revenue DESC
LIMIT 10;

Les différences sont minimes mais bloquantes : BigQuery qualifie les tables avec un dataset et des accents graves, les horodatages demandent souvent une conversion DATE() explicite, et les fonctions de date divergent — PostgreSQL écrit date_trunc('quarter', ordered_at) là où BigQuery écrit DATE_TRUNC(ordered_at, QUARTER), arguments inversés. Un système text-to-SQL de production doit générer pour le dialecte précis auquel il est connecté, et son validateur doit lui aussi comprendre ce dialecte. Prendre en charge un moteur, cela veut dire un générateur spécifique au dialecte et un validateur qui connaît ce dialecte.

Contexte sémantique : pourquoi les descriptions rédigées changent les résultats

La structure du schéma indique au modèle ce qui existe ; elle ne dit pas ce que les choses signifient. Une colonne nommée status peut contenir des états de commande, de paiement ou de livraison. Une table nommée orders_v2 peut être la table en service ou une migration abandonnée. Les descriptions rédigées comblent cet écart : une note d’une ligne comme « status : cycle de vie de la commande — ‘completed’ signifie payée et expédiée ; à utiliser pour le chiffre d’affaires » change le filtre que le modèle écrit. La méthode de rédaction — quelles colonnes décrire en premier, et comment garder les descriptions exactes à mesure que le schéma évolue — se trouve dans pourquoi le contexte sémantique compte.

Comment évaluer un outil text-to-SQL

Les classements de précision mesurent des schémas de référence, pas le vôtre. Évaluez le flux de travail qualitativement :

CritèreCe qu’il faut attendre
Affiche la requêteLe SQL exécuté exact est visible sur chaque réponse, et non sur demande
Valide avant d’exécuterLes instructions générées sont analysées et contrôlées avant de s’exécuter, celles qui modifient les données étant rejetées
Lecture seule par conceptionLa garantie de lecture est appliquée dans une couche de validation, pas demandée dans un prompt
Expose les sources et le temps d’exécutionLes tables sources, le nombre de lignes et le temps d’exécution accompagnent chaque résultat
Traite l’ambiguïté honnêtementLes questions ambiguës donnent une interprétation inspectable, pour que vous voyiez quelle lecture a été retenue
Comportement en cas d’erreurLes requêtes en échec sont corrigées et relancées dans des limites strictes, chaque tentative étant revalidée

Là où le pipeline échoue

Une question ambiguë s’exécute selon une lecture précise, et si vous ne vérifiez pas la requête, vous pouvez repartir avec un chiffre qui mesure quelque chose de voisin de ce que vous vouliez. La qualité des réponses suit la qualité du schéma : des noms de colonnes cryptiques et des descriptions absentes dégradent les résultats dans n’importe quel système. La couverture des dialectes se fait moteur par moteur : un système solide sur PostgreSQL ne l’est pas automatiquement sur Kusto. Et certains travaux n’ont tout simplement pas la bonne forme. Écrire des données, exécuter des migrations et administrer une base de données sont exclus par conception. Le travail de modélisation en plusieurs étapes, avec de lourdes transformations de logique métier, reste du ressort de votre couche de transformation, le text-to-SQL interrogeant ses sorties.

Notes sur les exemples

Les affirmations produit décrivent Datarelix tel que livré en août 2026 ; la page sécurité fait foi. Tous les exemples SQL utilisent le schéma de démonstration d’un détaillant fictif (customers, orders, order_items) et sont illustratifs plutôt que captés sur un système en production. Les deux variantes de dialecte sont écrites pour montrer où les générateurs divergent, pas pour classer les moteurs.

Essayez sur votre propre schéma

Connectez un utilisateur de base de données en lecture seule à l’aide des guides de connexion, posez une question dont vous connaissez déjà la réponse, et lisez la requête qui a été exécutée. Si elle correspond à la lecture que vous aviez en tête, vous avez testé la partie du pipeline qui compte le plus.