# Écrire du SQL et des migrations avec l’IA

URL: https://agentvera.dev/fr/blog/write-sql-with-ai/ · Publié: 2026-10-27

Écrire du SQL et des migrations avec des agents IA en sécurité : schéma réel, utilisateur en lecture seule, plans EXPLAIN, index et migrations testées sur une copie.

**En bref:**

- Les agents IA écrivent du bon SQL quand ils voient le vrai schéma, le plan d’exécution et la taille des tables. Donnez-leur un utilisateur en lecture seule, pas vos identifiants admin.
- Demandez des migrations en petites étapes réversibles (expand, migration des données, contract), construisez les index sans bloquer, et lancez chaque migration d’abord sur une copie.
- Les serveurs MCP de base de données comme celui de Supabase ont un mode lecture seule. Ne donnez jamais à un agent l’écriture en production : il génère le SQL, vous le relisez et l’appliquez.

**Pour écrire du SQL avec l’IA en toute sécurité, donnez à l’agent votre vrai schéma et un utilisateur de base de données en lecture seule, faites-lui montrer le plan d’exécution, et gardez chaque migration petite, réversible et testée sur une copie des données avant qu’elle approche de la production.** Un agent de code IA écrit vite des requêtes et des migrations. Le risque n’est pas qu’il écrive parfois du mauvais SQL, c’est qu’une mauvaise instruction s’exécute là où elle peut faire des dégâts.

Ce guide explique comment formuler vos demandes de requêtes, comment les vérifier avec `EXPLAIN`, comment demander des index, comment écrire des migrations qui ne verrouillent pas et ne perdent pas de données, quelle place donner aux ORM, et comment connecter un agent à une base via MCP sans lui confier les clés de la production. Les exemples utilisent PostgreSQL ; les idées s’appliquent aussi à MySQL et SQLite.

## Commencez par le schéma, pas par la question

La raison la plus fréquente d’une requête fausse, c’est que l’agent a deviné : une colonne appelée `user_id` qui est en réalité `account_id`, un statut stocké sous forme d’entier, un indicateur de suppression logique dont il ignorait l’existence. Donnez-lui d’abord le schéma.

Où le trouver :

- **Les fichiers de schéma de l’ORM.** `prisma/schema.prisma`, vos fichiers de schéma Drizzle, `models.py` de Django, `db/schema.rb` de Rails. L’agent peut les lire directement ; indiquez-les dans le prompt.
- **Un export de la structure seule.** `pg_dump --schema-only` écrit les tables, colonnes, index et contraintes sans aucune donnée :

```bash
pg_dump --schema-only --no-owner "$DEV_DATABASE_URL" > schema.sql
```

- **Une connexion en lecture seule à la base** via un serveur MCP, pour que l’agent liste les tables et inspecte les colonnes lui-même (voir plus bas).

Ajoutez ensuite ce que le schéma ne dit pas : la taille approximative des tables, les colonnes souvent NULL et le sens des termes métier. « Un client actif est un client qui a passé une commande dans les 90 derniers jours » évite une mauvaise supposition.

Un prompt pour une requête :

```text
Using schema.sql: write a PostgreSQL query that returns, for each country,
the number of active customers (an order in the last 90 days) and their
total order value this year. Exclude soft-deleted customers
(deleted_at IS NOT NULL). orders has about 20M rows, customers 400k.
Run it on the dev database, show me the first 10 rows and the EXPLAIN plan.
```

## Donnez à l’agent un utilisateur en lecture seule

Avant qu’un agent exécute quoi que ce soit sur une base, donnez-lui son propre utilisateur, incapable de modifier les données. Depuis PostgreSQL 14, le rôle intégré `pg_read_all_data` rend cela rapide :

```sql
CREATE ROLE agent_ro LOGIN PASSWORD 'change-me';
GRANT pg_read_all_data TO agent_ro;
ALTER ROLE agent_ro SET default_transaction_read_only = on;
ALTER ROLE agent_ro SET statement_timeout = '30s';
```

`pg_read_all_data` donne un accès en lecture à toutes les tables, sans droit d’écriture. Les deux lignes `ALTER ROLE` ajoutent une double sécurité : les transactions démarrent en lecture seule, et une requête qui s’emballe est annulée au bout de 30 secondes. Sur les versions plus anciennes, ou pour un accès plus restreint, accordez plutôt `CONNECT`, `USAGE` sur le schéma et `SELECT` sur les tables voulues.

Branchez cet utilisateur sur une base de développement ou de staging avec des données réalistes, pas sur la production. Si vous avez besoin de chiffres de production, utilisez un réplica en lecture ou une copie anonymisée récente.

## Lisez le plan d’exécution

Une requête qui renvoie les bonnes lignes peut quand même prendre des minutes. Demandez à l’agent de lancer `EXPLAIN` sur tout ce qui touche une grosse table et de vous expliquer le plan :

```sql
EXPLAIN (ANALYZE, BUFFERS)
SELECT c.country, count(DISTINCT c.id)
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.created_at > now() - interval '90 days'
  AND c.deleted_at IS NULL
GROUP BY c.country;
```

`EXPLAIN` seul montre le plan que la base utiliserait. `ANALYZE` exécute réellement la requête et ajoute les vrais temps et nombres de lignes. C’est important : `EXPLAIN ANALYZE` sur un `UPDATE` ou un `DELETE` modifie vraiment les données. Enveloppez-les dans une transaction que vous annulez, ou lancez-les uniquement sur une copie.

Ce que l’agent doit chercher :

- **Des scans séquentiels sur de grosses tables** alors que vous filtrez sur quelques lignes.
- **Un grand écart entre lignes estimées et lignes réelles**, signe de statistiques obsolètes (`ANALYZE tablename` les rafraîchit).
- **Des tris ou des hachages qui débordent sur le disque.**
- **Des boucles imbriquées sur beaucoup de lignes** là où une jointure par hachage coûterait moins cher.

Un bon prompt de suivi : « Explique ce plan avec des mots simples. Quelle étape prend le plus de temps et pourquoi ? Propose un changement et montre le nouveau plan. »

## Demandez des index, avec leur coût

Les agents aiment proposer des index. Chacun accélère certaines lectures, ralentit chaque écriture sur la table et occupe de l’espace disque. Demandez le raisonnement :

```text
The query above does a sequential scan on orders. Suggest at most one
index, explain which queries it helps and what it costs on writes,
and show the EXPLAIN plan with it on the dev database.
```

Sur une table très sollicitée, construisez l’index sans bloquer les écritures :

```sql
CREATE INDEX CONCURRENTLY idx_orders_customer_created
  ON orders (customer_id, created_at);
```

`CONCURRENTLY` prend plus de temps mais ne bloque pas les insertions et mises à jour pendant la construction. Il ne peut pas s’exécuter dans un bloc de transaction, ce qui compte car beaucoup d’outils de migration enveloppent chaque migration dans une transaction ; vérifiez comment votre outil le gère (la plupart proposent une option pour désactiver la transaction sur une migration). Si une construction concurrente échoue, elle laisse un index invalide qu’il faut supprimer puis reconstruire.

## Écrivez des migrations sûres à exécuter

Une migration s’exécute sur des données vivantes, souvent pendant que l’application sert du trafic. Voici les patterns à demander à votre agent, et à vérifier dans ce qu’il produit.

### Expand, migrate, contract

Ne renommez pas et ne supprimez pas en une seule étape. Pour renommer `users.name` en `users.full_name` :

1. **Expand :** ajoutez `full_name` comme colonne nullable. Déployez du code qui écrit dans les deux colonnes.
2. **Migrate :** remplissez `full_name` à partir de `name` par lots. Basculez les lectures sur `full_name`.
3. **Contract :** dans une version ultérieure, quand plus rien ne lit `name`, supprimez-la.

Chaque étape peut être déployée et annulée séparément. Un simple `ALTER TABLE ... RENAME COLUMN` casse toutes les instances de l’ancien code en cours d’exécution dès qu’il s’exécute.

### Évitez les verrous longs

Certaines instructions DDL prennent un verrou qui bloque les lectures ou les écritures pendant toute leur durée. Demandez à l’agent de les signaler et d’utiliser la forme plus sûre :

| Risqué | Plus sûr |
| --- | --- |
| `CREATE INDEX` sur une grosse table | `CREATE INDEX CONCURRENTLY` |
| Ajouter une clé étrangère en une étape | `ADD CONSTRAINT ... NOT VALID`, puis `VALIDATE CONSTRAINT` dans une étape séparée |
| `SET NOT NULL` sur une grosse table | Ajouter un `CHECK (col IS NOT NULL) NOT VALID`, le valider, puis passer en NOT NULL |
| Changer le type d’une colonne | Ajouter une nouvelle colonne, la remplir, basculer, supprimer l’ancienne |
| Un énorme `UPDATE` pour un backfill | Des lots de quelques milliers de lignes |

Depuis PostgreSQL 11, ajouter une colonne avec une valeur par défaut constante ne réécrit pas la table : cette opération est donc en général peu coûteuse. Définissez aussi un délai de verrou en tête de migration, pour qu’elle échoue vite au lieu d’attendre derrière une longue requête et de bloquer tout ce qui suit :

```sql
SET lock_timeout = '5s';
```

### Rendez-la réversible

Chaque migration doit avoir un chemin de retour : une migration down ou une étape de rollback écrite. Demandez-le explicitement : « Écris la migration up et la migration down, et dis-moi quelles étapes ne peuvent pas être annulées sans perte de données. » Supprimer une colonne ne s’annule pas avec une migration down ; les données ont disparu. C’est une raison de plus pour supprimer dans une étape ultérieure et séparée, après une sauvegarde.

### Testez-la sur une copie

Lancez la migration sur une copie des données avant la production : une base de staging restaurée depuis une sauvegarde récente, ou une base locale avec de fausses données de la taille de la production. Vérifiez trois choses : qu’elle se termine, combien de temps elle prend, et que l’application fonctionne toujours avec le nouveau schéma. Lancez ensuite la migration down et vérifiez-la aussi.

## Avec un ORM : laissez-le générer, faites relire par l’agent

Si vous utilisez un ORM, le flux le plus sûr est le suivant : modifiez le modèle, laissez l’ORM générer la migration, et faites relire le SQL généré par l’agent.

| ORM | Générer une migration | Appliquer | Voir le SQL |
| --- | --- | --- | --- |
| Prisma | `npx prisma migrate dev --name add_invoice --create-only` | `npx prisma migrate deploy` | le fichier `migration.sql` qu’il crée |
| Drizzle | `npx drizzle-kit generate` | `npx drizzle-kit migrate` | les fichiers SQL de votre dossier de migrations |
| Django | `python manage.py makemigrations` | `python manage.py migrate` | `python manage.py sqlmigrate app 0004` |
| Rails | `bin/rails generate migration AddFullNameToUsers` | `bin/rails db:migrate` | `db/schema.rb` et le fichier de migration |

L’option `--create-only` de Prisma écrit la migration sans l’appliquer, pour que vous puissiez d’abord modifier le SQL, par exemple pour ajouter `CONCURRENTLY` ou découper une étape. Drizzle propose aussi `drizzle-kit push`, qui applique directement les changements de schéma sans fichiers de migration ; c’est pratique pour prototyper en local, mais utilisez des migrations générées pour tout ce qui est partagé.

Un prompt de relecture qui fonctionne avec chacun d’eux :

```text
Read the new migration in prisma/migrations/. For each statement, tell me:
does it lock the table, can it lose data, how long will it take on a
table with 20M rows, and is there a safer form? Don't change any files.
```

## Connecter un agent à une base de données avec MCP

Un serveur [MCP](/fr/glossary/mcp/ "Qu’est-ce que MCP") permet à l’agent d’interroger la base lui-même : lister les tables, lancer un `SELECT`, lire un plan. C’est utile, et c’est aussi là que se trouve le risque : commencez donc en lecture seule.

**Supabase** propose un serveur MCP hébergé. En octobre 2026, ajouter `read_only=true` à son URL exécute chaque requête avec un utilisateur Postgres en lecture seule, et `project_ref` le limite à un seul projet :

```bash
claude mcp add --transport http supabase \
  "https://mcp.supabase.com/mcp?project_ref=<your-project-ref>&read_only=true"
```

Les recommandations de Supabase elles-mêmes : ne connecter un projet de production que si la tâche a vraiment besoin des données de production, et alors avec la limitation au projet et le mode lecture seule activés ; garder l’approbation manuelle des appels d’outils ; et relire les résultats avant d’agir, car les protections contre l’injection de prompt ne sont pas infaillibles.

**PostgreSQL seul :** utilisez un serveur MCP Postgres maintenu, avec votre utilisateur `agent_ro` dans la chaîne de connexion. [Les meilleurs serveurs MCP pour coder](/fr/blog/best-mcp-servers-for-coding/ "Les meilleurs serveurs MCP pour coder") liste les options et leurs réglages de lecture seule. L’ancien serveur Postgres de référence du projet MCP est archivé.

Les règles à inscrire dans votre `CLAUDE.md` ou votre `AGENTS.md` :

```markdown
## Database
- The database MCP server is read-only. Never ask for write access.
- Schema changes go through migrations in prisma/migrations, never direct DDL.
- Never run UPDATE or DELETE without a WHERE clause.
- Run new queries with EXPLAIN on the dev database before proposing them.
```

### Ne donnez jamais à un agent l’accès en écriture à la production

C’est la seule règle à ne jamais assouplir. Des lignes de données peuvent contenir du texte qui ressemble à des instructions (un ticket de support, une bio d’utilisateur), et un agent qui les lit peut les suivre ; c’est l’[injection de prompt](/fr/glossary/prompt-injection/ "Qu’est-ce que l’injection de prompt"). Une demande mal comprise peut devenir un `DELETE` avec le mauvais filtre. Avec un utilisateur en lecture seule, le pire scénario est une requête lente. Avec l’accès en écriture, c’est une panne ou des données perdues.

La bonne répartition : l’agent écrit et teste le SQL sur des données de développement ; vous le relisez ; un outil de migration ou une personne l’applique en production. [La sécurité des agents de code IA](/fr/blog/ai-coding-agent-security/ "Sécurité des agents de code IA") couvre plus largement le sandboxing et les permissions.

## Le faire dans AgentVera

AgentVera est une application de bureau pour macOS, Windows et Linux qui exécute Claude Code, Codex et d’autres agents CLI côte à côte. Quelques fonctionnalités sont conçues précisément pour ce travail :

- **[Gestionnaire de bases de données](/fr/features/database-manager/ "Gestionnaire de bases de données") :** des connexions PostgreSQL, MySQL/MariaDB et SQLite dans la même fenêtre que vos agents, avec une vue de table modifiable, un éditeur SQL avec `EXPLAIN`, un concepteur de tables qui montre le DDL avant de l’appliquer, et un diagramme ER. Les connexions marquées en lecture seule sont aussi ouvertes en lecture seule côté serveur, et une connexion marquée comme production s’affiche en rouge, chaque modification demandant d’abord une confirmation. Vous pouvez laisser les agents utiliser une connexion via l’outil intégré agentvera-db : l’accès est désactivé par défaut, démarre en lecture seule quand vous l’activez, les agents ne voient jamais le mot de passe, et chaque requête qu’ils exécutent est journalisée. Le gestionnaire de bases de données est inclus dans les offres Pro et Team.
- **[DB Guard](/fr/features/db-guard/ "DB Guard") :** quand un agent termine un tour, les fichiers de migration modifiés sont analysés à la recherche de risques comme `DROP`, `TRUNCATE`, `UPDATE` ou `DELETE` sans `WHERE`, `CREATE INDEX` sans `CONCURRENTLY`, de nouvelles contraintes ou des étapes down manquantes. Avec une connexion de type production sélectionnée, le risque est pondéré par la taille réelle des tables. Vous pouvez essayer la migration sur une base fantôme dans une transaction toujours annulée, ou renvoyer les remarques à l’agent pour qu’il corrige.
- **[MCP manager](/fr/features/mcp-manager/ "MCP manager") :** configurez une fois un serveur MCP de base de données ; il se branche sur vos agents à chaque lancement.
- **[Code review](/fr/features/code-review/ "Code review") :** à la fin du tour, un second modèle relit les migrations et les requêtes écrites par l’agent.

[Téléchargez AgentVera](/fr/download/ "Télécharger AgentVera") et essayez-le sur une base de développement.

## En résumé

Donnez à l’agent le vrai schéma et un utilisateur en lecture seule sur des données de développement. Demandez-lui de lancer `EXPLAIN` et d’expliquer le plan, de justifier chaque index et d’écrire les migrations en petites étapes réversibles de type expand and contract, avec du DDL non bloquant. Laissez votre ORM générer les migrations et l’agent les relire, testez chacune sur une copie, et gardez les écritures en production entre vos mains. Des consignes claires facilitent tout cela ; [écrire des prompts pour agents de code IA](/fr/blog/prompts-for-ai-coding-agents/ "Prompts pour agents de code IA") approfondit le contexte, les plans et les critères de fin.

## Questions fréquentes

**L’IA peut-elle écrire du SQL correct ?** Souvent, si elle voit votre vrai schéma et la forme de vos données. La plupart des requêtes fausses viennent de noms de colonnes devinés, de jointures manquantes ou de NULL inattendus. Donnez à l’agent le schéma, quelques lignes d’exemple et le résultat attendu, et faites-lui lancer la requête sur une base de développement avant de vous y fier.

**Est-il sûr de connecter un agent de code à ma base de données ?** À une base de développement ou de staging avec un utilisateur en lecture seule, oui, avec prudence. À la production avec des droits d’écriture, non. Un agent peut mal comprendre une demande, suivre une instruction injectée dans les données ou lancer un DELETE sans WHERE. Gardez les écritures derrière une migration que vous relisez et appliquez vous-même.

**Comment donner le schéma de ma base à un agent IA ?** Indiquez-lui le fichier de schéma tenu par votre ORM (schema.prisma, fichiers de schéma Drizzle, modèles Django) ou exportez uniquement la structure, par exemple avec pg_dump --schema-only. Un serveur MCP de base de données en lecture seule permet aussi à l’agent de lister lui-même les tables et les colonnes.

**Qui doit écrire la migration : l’IA ou l’ORM ?** Laissez l’ORM générer la migration à partir de la modification du modèle, puis faites relire le SQL généré par l’agent pour repérer les verrous, les pertes de données et les étapes manquantes. N’écrivez du SQL brut à la main (ou via l’agent) que pour ce que l’ORM ne sait pas exprimer, comme les index concurrents ou les backfills de données.

**Qu’est-ce que le pattern expand and contract ?** Une façon de modifier un schéma sans interruption. D’abord expand : ajoutez la nouvelle colonne ou table à côté de l’ancienne. Puis migrate : déployez du code qui écrit dans les deux et remplissez les anciennes lignes. Enfin contract : quand plus rien ne lit l’ancienne structure, supprimez-la dans une migration ultérieure.

---

**À propos d’AgentVera.** AgentVera est une app de bureau pour macOS, Windows et Linux, développée par Solviera Teknoloji. Elle exécute 18 agents de code IA (Claude Code, Codex, Gemini CLI, Copilot, Cursor, Antigravity, opencode, Hermes, Qwen Code, Kimi Code, Kiro, Amp, Droid, Goose, Vibe, Crush, Aider, Cline) côte à côte, par projet, dans de vrais terminaux avec les installations et connexions CLI de l’utilisateur. L’offre gratuite inclut des agents illimités. Télécharger: https://agentvera.dev/fr/download/ · Tarifs: https://agentvera.dev/fr/pricing/
