💻 Développement

dev-sqlite-guide

Guide pour écrire des requêtes SQL et concevoir des schémas SQLite avec les bonnes pratiques.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- dev-sqlite-guide --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } dev-sqlite-guide -Launch"

🚀 Déjà installé ?

claude "/dev-sqlite-guide"

Ou tapez /dev-sqlite-guide dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

requête SQLschéma SQLitebase de données SQLitemigration SQLtable SQLitequery SQL

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/dev-sqlite-guide ~/.claude/skills/

Payload du plugin : skills/dev-sqlite-guide · source éditable : dev-skills/sqlite-guide

📖 Manuel

Guide SQLite

Workflow

  1. Identifier le besoin — conception de schéma, écriture de requête, optimisation, migration ou debug.
  2. Examiner le contexte — schéma existant, version SQLite (sqlite3 --version), volumes de données attendus.
  3. Choisir le pattern adapté — voir sections ci-dessous selon le cas.
  4. Livrer du code copiable — requêtes testables, schemas complets, commandes CLI directes.
  5. Signaler les pièges — typage dynamique, verrouillage de fichier, absence de types natifs date/bool.

Conception de schéma

Table de référence (template)

create table users (
  id      text not null primary key default ('u_' || lower(hex(randomblob(16)))),
  created text not null default (strftime('%Y-%m-%dT%H:%M:%fZ')),
  updated text not null default (strftime('%Y-%m-%dT%H:%M:%fZ')),
  email   text not null unique,
  name    text not null,
  active  integer not null default 1   -- bool : 0/1
) strict;

create trigger users_updated
after update on users
begin
  update users set updated = strftime('%Y-%m-%dT%H:%M:%fZ')
  where id = old.id;
end;

Conventions de nommage

ÉlémentConvention
Clé primaireid text + préfixe table (u_, p_, o_) + randomblob(16)
Timestampsstrftime('%Y-%m-%dT%H:%M:%fZ') — ISO 8601 avec ms, toujours UTC
Booléensinteger not null default 0 (0/1) — pas de type bool natif
JSONtext + contrainte check(json_valid(meta)) si nécessaire
Clés étrangèresuser_id text not null references users(id)

Activer les foreign keys (obligatoire à chaque connexion)

pragma foreign_keys = on;
SQLite n'active pas les FK par défaut. À mettre dans l'initialisation de chaque connexion.

Migrations

Toujours versionner avec une table dédiée :

create table if not exists migrations (
  version  integer primary key,
  name     text not null,
  applied  text not null default (strftime('%Y-%m-%dT%H:%M:%fZ'))
);

Pattern de migration safe :

begin;
-- modification du schéma
alter table posts add column slug text;
insert into migrations(version, name) values (3, 'add_posts_slug');
commit;

Requêtes

Règles de base

CTE — lecture claire

with active_users as (
  select id, name, email
  from users
  where active = 1
),
recent_posts as (
  select author_id, count(*) as cnt
  from posts
  where created > date('now', '-30 days')
  group by author_id
)
select u.name, u.email, coalesce(rp.cnt, 0) as posts_last_30d
from active_users u
left join recent_posts rp on rp.author_id = u.id
order by posts_last_30d desc;

Upsert

insert into settings (key, value)
values ('theme', 'dark')
on conflict(key) do update set
  value   = excluded.value,
  updated = strftime('%Y-%m-%dT%H:%M:%fZ');

Pagination (keyset > offset pour les grands volumes)

-- Offset (simple, mais lent sur grands volumes)
select id, title, created from posts
order by created desc
limit 20 offset 40;

-- Keyset (performant, reprend après le dernier élément vu)
select id, title, created from posts
where created < '2026-06-01T12:00:00.000Z'
order by created desc
limit 20;

Recherche — FTS5

-- Création de l'index virtuel
create virtual table posts_fts using fts5(
  title, body, content=posts, content_rowid=id
);

-- Indexation initiale
insert into posts_fts(posts_fts) values('rebuild');

-- Requête
select p.id, p.title, rank
from posts_fts
join posts p on p.id = posts_fts.rowid
where posts_fts match 'sqlite AND performance'
order by rank;

JSON (SQLite ≥ 3.38)

-- Extraction de champ
select json_extract(meta, '$.country') as country from users;

-- Filtre sur champ JSON
select * from orders
where json_extract(payload, '$.status') = 'paid';

-- Construction
select json_object('id', id, 'name', name) from users;

Optimisation & index

Analyser une requête

explain query plan
select * from posts where author_id = 'u_abc' order by created desc;

Créer les bons index

-- Index simple
create index idx_posts_author on posts(author_id);

-- Index composite (ordre = sélectivité décroissante)
create index idx_posts_author_created on posts(author_id, created desc);

-- Index partiel (réduit la taille de l'index)
create index idx_active_users on users(email) where active = 1;

WAL mode (performances en écriture concurrente)

pragma journal_mode = wal;
pragma synchronous = normal;  -- sécurité acceptable, perf ++

Statistiques

pragma table_info(posts);      -- colonnes et types
pragma index_list(posts);      -- index existants
analyze;                       -- mise à jour des stats pour l'optimiseur

CLI SQLite — commandes utiles

# Ouvrir / créer
sqlite3 mydb.db

# Import CSV
sqlite3 mydb.db -cmd ".mode csv" ".import data.csv my_table"

# Export CSV
sqlite3 -header -csv mydb.db "select * from users;" > users.csv

# Dump SQL complet
sqlite3 mydb.db .dump > backup.sql

# Exécuter un fichier SQL
sqlite3 mydb.db < schema.sql

Garde-fous & anti-patterns

Anti-patternProblèmeSolution
select * en productionCasse si colonnes ajoutées, lisibilité zéroNommer explicitement les colonnes
Table sans strictSQLite accepte n'importe quel type — bugs silencieuxToujours strict
offset sur grande tableO(n) — ralentit proportionnellementKeyset pagination
like '%terme%' sur gros volumesFull scanFTS5
FK sans pragma foreign_keys = onContraintes ignorées silencieusementActiver à chaque connexion
Timestamps avec datetime()Moins précis que strftime (pas de ms)strftime('%Y-%m-%dT%H:%M:%fZ')
Connexions multiples en écriture sans WALContention — SQLITE_BUSY fréquentspragma journal_mode = wal
Migrations manuelles non versionnéesImpossible de rejouer ou auditerTable migrations + transactions
Booléens en text ('true'/'false')Comparaisons casséesinteger 0/1

Critères de décision rapides