Vous avez un tableau sur une page web. Vous en avez besoin dans votre base de données.
L'approche manuelle : copier dans Excel, nettoyer, exporter en CSV, écrire le CREATE TABLE à la main, utiliser LOAD DATA ou COPY, déboguer les erreurs.
La meilleure approche : générer du SQL complet directement — CREATE TABLE avec types inférés, requêtes INSERT avec échappement correct.
Voici comment construire un convertisseur de tableaux web vers SQL.
Le Format de Sortie
Un export SQL complet devrait inclure :
-- Exporté depuis HTML Table Exporter PRO
CREATE TABLE products (
product_id INTEGER,
name TEXT,
price REAL,
in_stock TEXT
);
INSERT INTO products (product_id, name, price, in_stock) VALUES
(1, 'Widget', 29.99, 'true'),
(2, 'Gadget', 49.99, 'false'),
(3, 'L''article d''O''Brien', 19.99, 'true');
Exigences clés :
- Nom de table valide (identifiant SQL sûr)
- Noms de colonnes valides (pas d'espaces, pas de caractères spéciaux)
- Types de colonnes appropriés (INTEGER, REAL, TEXT)
- Valeurs correctement échappées (apostrophes doublées)
- Gestion des NULL
Étape 1 : Assainir les Identifiants
Les identifiants SQL (noms de tables et de colonnes) ont des règles strictes :
- Pas d'espaces ni de caractères spéciaux
- Ne peuvent pas commencer par un chiffre
- Devraient être en minuscules pour la portabilité
function sanitizeSqlIdentifier(name, fallback) {
let id = (name || "").toString().trim();
if (!id) id = fallback || "col";
id = id
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "") // Supprimer les accents (café → cafe)
.toLowerCase()
.replace(/[^a-z0-9_]+/g, "_") // Remplacer les car. invalides par underscore
.replace(/^_+|_+$/g, ""); // Supprimer les underscores en début/fin
// Les identifiants SQL ne peuvent pas commencer par un chiffre
if (/^[0-9]/.test(id)) {
id = "_" + id;
}
if (!id) id = fallback || "col";
return id;
}
Exemples :
- « Nom du Produit » → « nom_du_produit »
- « Prix (€) » → « prix »
- « 2024 Revenus » → « _2024_revenus »
- « Préço » → « preco »
Étape 2 : Générer des Noms de Colonnes Uniques
Les tableaux peuvent avoir des en-têtes dupliqués. SQL ne peut pas avoir de noms de colonnes dupliqués.
function generateColumnNames(headerRow) {
const usedNames = new Set();
return headerRow.map((header, index) => {
const base = sanitizeSqlIdentifier(header, `col_${index + 1}`);
let candidate = base;
let counter = 1;
while (usedNames.has(candidate)) {
candidate = `${base}_${counter}`;
counter++;
}
usedNames.add(candidate);
return candidate;
});
}
Exemples :
- ["Nom", "Nom", "Valeur"] → ["nom", "nom_1", "valeur"]
- ["", "", "Données"] → ["col_1", "col_2", "donnees"]
Étape 3 : Inférer les Types de Colonnes
SQL a trois types principaux qui nous intéressent :
- INTEGER : Nombres entiers
- REAL : Nombres décimaux
- TEXT : Tout le reste
L'inférence échantillonne les valeurs de la colonne et choisit le type le plus spécifique qui correspond à toutes les valeurs :
function inferSqlColumnTypes(rows, headerRowIndex = 0) {
const headerRow = rows[headerRowIndex] || [];
const dataRows = rows.slice(headerRowIndex + 1);
const colCount = headerRow.length;
const types = new Array(colCount).fill("TEXT");
for (let col = 0; col < colCount; col++) {
// Échantillonner jusqu'à 50 valeurs non vides
const values = [];
for (let r = 0; r < dataRows.length && values.length < 50; r++) {
const cell = dataRows[r][col];
const v = cell != null ? String(cell).trim() : "";
if (v !== "") values.push(v);
}
if (values.length === 0) {
types[col] = "TEXT";
continue;
}
// Vérifier si toutes les valeurs sont des entiers
let allInt = true;
let allNumeric = true;
for (const v of values) {
if (!/^[-+]?\d+$/.test(v)) {
allInt = false;
}
if (!/^[-+]?\d+([.,]\d+)?$/.test(v)) {
allNumeric = false;
}
}
if (allInt) {
types[col] = "INTEGER";
} else if (allNumeric) {
types[col] = "REAL";
} else {
types[col] = "TEXT";
}
}
return types;
}
Décisions clés :
- Échantillonner seulement 50 valeurs pour la performance sur les grands tableaux
- INTEGER est plus strict que REAL (pas de décimales autorisées)
- Si UNE SEULE valeur ne correspond pas, retomber sur TEXT
- Les colonnes vides sont TEXT par défaut
Étape 4 : Échapper les Valeurs
Les chaînes SQL nécessitent d'échapper les apostrophes en les doublant :
function sqlEscapeValue(raw, type) {
// Gestion des NULL
if (raw == null) return "NULL";
const v = String(raw).trim();
if (v === "") return "NULL";
// Pour les types numériques, essayer de retourner un nombre sans guillemets
if (type === "INTEGER" || type === "REAL") {
const normalized = v.replace(",", "."); // Gérer le format décimal EU
const num = Number(normalized);
if (!Number.isNaN(num) && Number.isFinite(num)) {
return normalized;
}
// Retomber sur le traitement TEXT si ce n'est pas un nombre valide
}
// TEXT ou fallback : échapper les apostrophes
const escaped = v.replace(/'/g, "''");
return `'${escaped}'`;
}
Exemples :
-
"Bonjour"→'Bonjour' -
"L'article"→'L''article' -
"C'est \"cité\""→'C''est "cité"' -
123(INTEGER) →123 -
45.67(REAL) →45.67 -
""→NULL -
null→NULL
Étape 5 : Générer le SQL Complet
function tableToSqlString(tableInfo) {
const rows = tableInfo.rows || [];
if (!rows.length) return "";
const headerRowIndex = tableInfo.headerRowIndex || 0;
const headerRow = rows[headerRowIndex];
const dataRows = rows.slice(headerRowIndex + 1);
if (!headerRow) return "";
// Générer des noms de colonnes sûrs
const columnNames = generateColumnNames(headerRow);
// Inférer les types de colonnes
const types = inferSqlColumnTypes(rows, headerRowIndex);
// Générer un nom de table sûr
const rawTableName = tableInfo.slug || tableInfo.name || "table";
let tableName = sanitizeSqlIdentifier(rawTableName, "table");
if (!tableName) tableName = "table_export";
// CONSTRUIRE LE CREATE TABLE
const createLines = columnNames.map((col, i) =>
` ${col} ${types[i] || "TEXT"}`
);
const createStmt = `CREATE TABLE ${tableName} (\n${createLines.join(",\n")}\n);`;
// CONSTRUIRE LES INSERT
const insertHeader = `INSERT INTO ${tableName} (${columnNames.join(", ")}) VALUES`;
const valueLines = dataRows.map(row => {
const values = columnNames.map((_, i) => {
const cell = row[i];
const type = types[i] || "TEXT";
return sqlEscapeValue(cell, type);
});
return ` (${values.join(", ")})`;
});
// COMBINER
let sql = `-- Exporté depuis HTML Table Exporter PRO\n\n${createStmt}\n\n`;
if (valueLines.length) {
sql += `${insertHeader}\n${valueLines.join(",\n")};\n`;
}
return sql;
}
Exemple de Sortie
Tableau d'entrée :
| Produit | Prix | Qté |
|---|---|---|
| Widget | 29.99 | 100 |
| L'article d'O'Brien | 19.99 | 50 |
Sortie :
-- Exporté depuis HTML Table Exporter PRO
CREATE TABLE products (
produit TEXT,
prix REAL,
qte INTEGER
);
INSERT INTO products (produit, prix, qte) VALUES
('Widget', 29.99, 100),
('L''article d''O''Brien', 19.99, 50);
Gérer les Cas Limites
Tableaux Vides
if (!rows.length) return "";
if (!headerRow) return "";
Retourner une chaîne vide plutôt que du SQL invalide.
Colonnes Entièrement NULL
Les colonnes avec uniquement des valeurs vides/nulles obtiennent le type TEXT. La fonction d'inférence gère cela :
if (values.length === 0) {
types[col] = "TEXT";
continue;
}
Formats de Nombres Mixtes
L'échappeur normalise les décimales avec virgule :
const normalized = v.replace(",", ".");
« 1,234.56 » reste tel quel. « 1.234,56 » (format EU) devrait être normalisé avant d'atteindre le générateur SQL — c'est le rôle des préréglages de nettoyage.
Valeurs Très Longues
Les colonnes TEXT dans SQLite/PostgreSQL gèrent des longueurs arbitraires. Pas de troncature nécessaire. Pour les limites VARCHAR de MySQL, il faudrait spécifier la longueur ou utiliser TEXT explicitement.
Compatibilité entre Bases de Données
Le SQL généré est intentionnellement simple :
| Fonctionnalité | SQLite | PostgreSQL | MySQL |
|---|---|---|---|
| CREATE TABLE | ✅ | ✅ | ✅ |
| INTEGER/REAL/TEXT | ✅ | ✅ | ✅ |
| INSERT multi-lignes | ✅ | ✅ | ✅ |
| Échappement apostrophe | ✅ | ✅ | ✅ |
Pour des fonctionnalités spécifiques aux bases de données (contraintes, index, schémas), il faudrait étendre le générateur. Pour un import basique de données, cela fonctionne partout.
Utiliser l'Export
# SQLite
sqlite3 mydb.db < export.sql
# PostgreSQL
psql -d mydb -f export.sql
# MySQL
mysql mydb < export.sql
Ou collez directement dans votre client de base de données.
Pour en savoir plus sur le chemin d'export CSV (quand vous n'avez pas besoin de SQL), consultez notre guide sur l'export de toutes les lignes d'un tableau web paginé.
Besoin d'exports SQL sans écrire de code ? En savoir plus sur gauchogrid.com/fr/html-table-exporter ou essayez-le gratuitement sur le Chrome Web Store.
Top comments (0)