# [script] Convertir SQL > csv

## Tony Clifton

Bonsoir,

j'ai un gros fichier SQL (quelques Go) que je souhaiterais convertir en CSV.

Pour ce faire, j'avais pensé faire un grep de tout ce qui commence par INSERT dans le fichier import.sql, afin d'obtenir quelque chose comme ça :

 *import.sql wrote:*   

> INSERT INTO `table1` VALUES ('chpA1', 'chpA2', 'chpA3', 'chpA4');
> 
> INSERT INTO `table2` VALUES ('chpB1', 'chpB2');

 

Ensuite je voulais extraire le nom de la table et la liste des champs pour chaque insertion afin de stocker les valeurs des champs dans un fichier qui porterait le nom de la table, soit :

 *table1 wrote:*   

> 'chpA1', 'chpA2', 'chpA3', 'chpA4'

 

 *table2 wrote:*   

> 'chpB1', 'chpB2''

 

Seulement voila, je bloque là, j'ai essayé avec AWK mais j'ai aucune idée de comment m'y prendre. Et en bash j'ai réussi à extraire le nom de la table et les valeurs avec expr pour une ligne, avec les commandes suivantes : 

```
expr "$STR" :  'INSERT INTO `\(.*\)`'

expr "$STR" :  'INSERT INTO `.*` VALUES (\(.*\))'
```

, mais je doute que ce soit la bonne solution.

Pouvez-vous m'aidez ?

Merci

----------

## truc

Le problème avec cette approche, c'est qu'il y a probablement des ' échappées ( ' ' ) dans les valeurs, et ça risque de ne pas fonctionner si notre approche est trop simple.

De même, est-ce que tes INSERTs sont toujours de cette forme? Style, est-ce qu'il y en a avec seulement quelques colonnes?

----------

## Tony Clifton

Merci pour ta réponse !

Ma problématique était plus ludique qu'autre chose (rien que faire un grep sur le fichier SQL prend plusieurs heures, alors du bash…), car je m'intéresse aux regex appliquées à sed, awk et autres. Je trouve ça vraiment très intéressant, ça doit vraiment être un plus de bien les maîtriser. Mais lorsque j'essaye une mise en application avec des cas réels, je m'aperçois que c'est beaucoup trop compliqué — ou alors j'ai vraiment l'esprit tordu   :Rolling Eyes: 

----------

## truc

Bah, si tu veux on peut supposer que tu n'as que des INSERT normaux avec zéro échappement, toujours tout sur la même ligne et bref que des trucs supers cools et on peut déjà commencer à s'amuser avec ça.

Si je comprends bien, tu voudrais donc ne faire un traitement que sur les INSERT (lignes commençant par INSERT), tu peux donc, avec sed et awk, n'effectuer des opérations que sur ces lignes grace à ce sélécteur /^INSERT[[:space::]/.

Après, tu veux remplir tes fichiers dont le nom dépend du deuxième champ, alors, là on a un comportement un peu dynamique si j'puis dire (c'est quel temps ça d'ailleurs, si j'puis dire?! C'est français seulement?), du coup, nous allons plutôt travailler avec awk.

remarque: tu pourrais également d'abord faire un traitement avec sed, pour pouvoir ensuite faire le travail d'écriture dans les fichiers avec awk plus facilement. Mais on va voir déjà où tu nous emmènes avec awk puis on changera peut-être de cap par la suite.

Bon, histoire que tout soit bien clair, donne nous déjà un exemple de ligne que tu as en entrée et de ce que tu veux obtenir en sortie.

----------

## Tony Clifton

Whaou ! La classe j'vais faire du sed et du awk en même temps   :Cool:  .

 *truc wrote:*   

> Après, tu veux remplir tes fichiers dont le nom dépend du deuxième champ, alors, là on a un comportement un peu dynamique si j'puis dire (c'est quel temps ça d'ailleurs, si j'puis dire?! C'est français seulement?), du coup, nous allons plutôt travailler avec awk.

 

Ce langage là, je le maîtrise un peu mieux ; donc oui, il s'agit bien du verbe pouvoir conjugué au présent de l'indicatif. C'est moins usité que « je peux », donc un peu plus littéraire peut-être.

----------

## truc

arf, j'viens de voir que t'avais déjà donner des exemples de tout ça(fichiers en entrée et en sortie)

```
INSERT INTO `table1` VALUES ('chpA1', 'chpA2', 'chpA3', 'chpA4');

INSERT INTO `table2` VALUES ('chpB1', 'chpB2');
```

On est bien d'accord, c'est pour jouer, les noms des tables ainsi que les champs sont sans caractères spéciaux, ni rien de génant...

```
<inputFile awk -f joujou.awk
```

avec 

```

# awk travaille avec les Extended REGEXP, contrairement à sed par défaut,

# ça va surement t'embrouiller au début...

# on se place sur les bonnes lignes (attention la ligne suivante risque d'être

# coupée sur le forum)

/^INSERT[[:space:]]+INTO[[:space:]]+`[^`]+`[[:space:]]+VALUES[[:space:]]*\(.*\)[[:space:]]*;[[:space:]]*$/ {

   # puis on extrait le nom de la table dans le champ numéro 3

   table=substr($3, 2, length($3)-2);

   # $0 contient toute la ligne, il nous suffit de ne garder que la partie entre les ()

   sub(/^[^(]+\([[:space:]]*/, "", $0)

   # sub opère par défaut sur $0, donc normalement, ceci est équivalent

   ## sub(/^[(]+([[:space:]]*/, "")

   # puis la parenthèse fermante et le ';'

   sub(/[[:space:]]*\)[[:space:]]*;[[:space:]]*$/, "")

   # si tu veux vérifier:

   #print table, ":", $0

   # il nous suffit maintenant d'écrire le tout dans le bon fichier, ce que

   # awk nous permet de faire très simplement

   # comme on est cool, on maintient quand même une liste des fichiers qu'on 

   # va ouvrir en écriture pour ensuite les refermer

   # cette liste va d'ailleurs nous servir pour savoir si on écrase le fichier

   # si il existe déjà ou si on écrit à la fin

   if (table in opened_files)

      print >> table

   else

      print > table

   # on est fou, on va aussi faire des (modestes) stats à la fin!

   opened_files[table]++

}

END {

   # on ferme maintenant tous les fichiers dans lesquels on a écrit

   for (name in opened_files) {

      close(name, "to")

      printf "%10d ligne(s) écrite(s) dans le fichier %s\n", opened_files[name], name

   }

}

```

Bon, c'est bien commenté! Tu devrais t'y retrouver...

bon, hormis avec tes exemples, j'ai pas vraiment tester ce truc, donc, attentions aux chats...

----------

## Tony Clifton

Merci pour le script ! Ca me permet de comprendre certaines commandes sur lesquelles j'ai pu m'arracher les cheveux (Mais NON, j'vous dis qu'c'est pas possible !!!! … Et bien si en fait  :Very Happy: ).

Tout ça me fait réaliser que je dois me documenter sur ces outils (langages même ?), je ne connais pas l'équivalence du site php.net du PHP pour AWK ou sed mais si il n'y en a pas il faudra alors que j'achète mon premier bouquin d'informatique.

----------

## StinGer_Uesugi

Et sinon, un script en Perl ou Python ? Bon ça va revenir au même que awk et sed au final, et ça fonctionnera pas forcément plus vite. Mais ça peut permettre de faire pas mal de chose en traitement ligne par ligne.

Sinon, awk est vraiment très très puissant. J'ai déjà fait du traitement (en production) dans l'autre sens avec : transformer des fichiers CSV en fichiers SQL pour insertion dans une BDD. Et quand tu connais un peu awk, tu fais des programmes de fou en une dizaine de ligne, à peine.

Et si tu cherches un livre sur awk, pas besoin de chercher loin, tu prends la base : The awk programming language. J'ai commencé par là, et franchement, y a tout dedans...

----------

## Tony Clifton

Merci pour le conseil, j'vais trouver ça dès que j'ai un instant  :Smile: 

 *StinGer_Uesugi wrote:*   

> transformer des fichiers CSV en fichiers SQL pour insertion dans une BDD

 

C'est justement ce que je voulais éviter, j'ai récemment appris par mon expérience que c'était à bannir sur des BDD qui commence à titiller le Go voire plus : import en 18h avec fichier SQL contre 90 min pour la même base de données en CSV.

----------

