2008-09-16 11 views
158

Comment puis-je vider les données, et seulement les données, pas le schéma, de certaines tables SQLite3 d'une base de données (pas toutes les tables)? La sauvegarde devrait être au format SQL, car elle devrait être facilement réinsérée dans la base de données plus tard et devrait être faite à partir de la ligne de commande. Quelque chose commeComment vider les données de certaines tables SQLite3?

sqlite3 db .dump 

mais sans le dumping du schéma et la sélection des tables à vider.

+0

À quel format?Quelque chose en particulier, ou êtes-vous simplement à la recherche d'une sauvegarde lisible par l'homme? Veuillez préciser. – dmckee

+1

Je veux vider au format SQL, afin que je puisse le restaurer facilement. J'ai ajouté cette information à la question principale. – Pablo

Répondre

-3

Vous pouvez faire une sélection sur les tables en insérant des virgules après chaque champ pour produire un fichier csv, ou utiliser un outil graphique pour retourner toutes les données et les enregistrer dans un fichier csv.

+2

Mon intention était de produire un fichier SQL qui pourrait facilement être ajouté de nouveau à la base de données. – Pablo

2

La meilleure méthode consisterait à prendre le code que le vidage sqlite3 db ferait, à l'exclusion des parties de schéma.

Exemple code pseudo:

SELECT 'INSERT INTO ' || tableName || ' VALUES(' || 
    {for each value} ' quote(' || value || ')'  (+ commas until final) 
|| ')' FROM 'tableName' ORDER BY rowid DESC 

Voir: src/shell.c:838 (pour sqlite-3.5.9) pour le code réel

Vous pourriez même prendre juste que shell et commentez les parties de schéma et utiliser.

189

Vous ne dites pas ce que vous voulez faire avec le fichier sauvegardé.

Je voudrais utiliser ce qui suit pour obtenir un fichier CSV, que je peux importer dans presque tout

.mode csv 
-- use '.separator SOME_STRING' for something other than a comma. 
.headers on 
.out file.dmp 
select * from MyTable; 

Si vous souhaitez réinsérer dans une base de données SQLite différente alors:

.mode insert <target_table_name> 
.out file.sql 
select * from MyTable; 
+0

Existe-t-il un moyen de faire cela par programme en utilisant des instructions SQL? Je peux voir comment le faire en utilisant l'interprète, mais si je voulais écrire un script? – coleifer

+3

Vous pouvez placer vos instructions dans un fichier (par exemple sample.txt), puis l'appeler à l'aide de: sqlite3 db.sq3 CyberFonic

35

Pas la meilleur moyen, mais au bail n'a pas besoin d'outils externes (sauf grep, qui est de série sur les boîtes * nix de toute façon)

sqlite3 database.db3 .dump | grep '^INSERT INTO "tablename"' 

mais vous avez besoin de faire cette commande pour chaque table que vous recherchez.

Notez que cela n'inclut pas le schéma.

+1

J'ai utilisé 'sqlite3 Database.s3db .dump' –

+3

Cela se casse si ces insertions ont des retours à la ligne dans les valeurs. Mieux vaut utiliser 'grep -v '^ CREATE'' comme suggéré dans l'une des autres réponses – dequis

+1

en utilisant' grep -v'^CREATE; 'va se casser si les instructions' CREATE' ont des sauts de ligne en eux (ce qu'ils font parfois). Best, IMO, ne doit pas supprimer automatiquement les instructions CREATE, mais les éditer manuellement. Utilisez simplement l'éditeur de texte dont vous avez besoin et recherchez 'CREATE' et supprimez manuellement ces instructions. Tant que la base de données n'est pas énorme (et puisque vous utilisez sqlite, je suppose que c'est la note), alors c'est assez simple. –

31

Vous pouvez spécifier un ou plusieurs arguments de table pour la commande spéciale .dump, par ex. sqlite3 db ".dump 'table1' 'table2'".

+0

lorsque j'ajoute plusieurs noms de table comme vous l'avez mentionné, il me donne cette sortie: Utilisation: .dump? - preserve-rowids? ? MOTIF-MOTIF? – mwm

123

Vous pouvez faire cela en obtenant la différence des commandes .schema et .dump. par exemple avec grep:

sqlite3 some.db .schema > schema.sql 
sqlite3 some.db .dump > dump.sql 
grep -vx -f schema.sql dump.sql > data.sql 

fichier data.sql ne contiendra que des données sans schéma, quelque chose comme ceci:

BEGIN TRANSACTION; 
INSERT INTO "table1" VALUES ...; 
... 
INSERT INTO "table2" VALUES ...; 
... 
COMMIT; 

J'espère que cela vous aide.

+0

des commandes directes pour les réimporter? – dorado

+3

@anurageldorado c'est sql simple. il suffit de lancer 'sqlite3 some.db jellyfish

+0

Pour certains Rasson ne fonctionne pas pour moi. J'ai besoin d'utilisations autour. 'sqlite3 storage/db/jobs.s3db. jobs jobs> schema.sql' ne fonctionnent pas, mais' echo '.schema' jobs | sqlite3 storage/db/jobs.s3db> schema.sql' fonctionne bien – abkrim

8

Comme une amélioration à la réponse de Paul Egan, cela peut être accompli comme suit:

sqlite3 database.db3 '.dump "table1" "table2"' | grep '^INSERT' 

--ou--

sqlite3 database.db3 '.dump "table1" "table2"' | grep -v '^CREATE' 

La mise en garde, bien sûr, est que vous devez avoir grep installé.

+1

J'aime celui-ci. En prime, cela fonctionne toujours si vous avez un fichier SQL sauvegardé, juste 'cat database.sql | grep '^ INSERT'> database_inserts.sql' (même chose pour le schéma, remplacez par 'grep '^ CREATE'' – trisweb

+2

@trisweb, bien sûr, vous voulez dire' grep'^INSERT ' database_inserts.sql' que 'cat 'est superflu – Sebastian

+1

Rien de superflu à ce propos: le' cat' ne coûte pratiquement rien à exécuter et rend la chaîne d'entrée à la sortie plus claire.Bien sûr, vous pouvez aussi écrire ' rjh

2

Cette version fonctionne bien avec les nouvelles lignes à l'intérieur des inserts:

sqlite3 database.sqlite3 .dump | grep -v '^CREATE'

Dans la pratique exclut toutes les lignes commençant par CREATE qui est moins susceptible de contenir des sauts de ligne

9

Toute réponse qui suggère d'utiliser grep pour exclure les lignes CREATE ou simplement saisir les lignes INSERT de la sortie sqlite3 $DB .dump échoueront gravement. Les commandes CREATE TABLE listent une colonne par ligne (donc CREATE ne l'obtiendra pas), et les valeurs sur les lignes INSERT peuvent avoir des retours à la ligne incorporés (donc vous ne pouvez pas saisir seulement les lignes INSERT).

for t in $(sqlite3 $DB .tables); do 
    echo -e ".mode insert $t\nselect * from $t;" 
done | sqlite3 $DB > backup.sql 

Testé sur sqlite3 version 3.6.20.

Si vous souhaitez exclure certaines tables, vous pouvez les filtrer avec $(sqlite $DB .tables | grep -v -e one -e two -e three), ou si vous souhaitez obtenir un sous-ensemble spécifique, remplacez-le par one two three.

6

En Python ou Java ou n'importe quel langage de haut niveau, le fichier .dump ne fonctionne pas. Nous devons coder la conversion en CSV à la main. Je donne un exemple Python. D'autres exemples seraient appréciés:

from os import path 
import csv 

def convert_to_csv(directory, db_name): 
    conn = sqlite3.connect(path.join(directory, db_name + '.db')) 
    cursor = conn.cursor() 
    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") 
    tables = cursor.fetchall() 
    for table in tables: 
     table = table[0] 
     cursor.execute('SELECT * FROM ' + table) 
     column_names = [column_name[0] for column_name in cursor.description] 
     with open(path.join(directory, table + '.csv'), 'w') as csv_file: 
      csv_writer = csv.writer(csv_file) 
      csv_writer.writerow(column_names) 
      while True: 
       try: 
        csv_writer.writerow(cursor.fetchone()) 
       except csv.Error: 
        break 

Si vous avez « données de panel, autrement dit de nombreuses entrées individuelles avec ids ajouter à la avec le regard et les décharges des statistiques sommaires:

 if 'id' in column_names: 
      with open(path.join(directory, table + '_aggregate.csv'), 'w') as csv_file: 
       csv_writer = csv.writer(csv_file) 
       column_names.remove('id') 
       column_names.remove('round') 
       sum_string = ','.join('sum(%s)' % item for item in column_names) 
       cursor.execute('SELECT round, ' + sum_string +' FROM ' + table + ' GROUP BY round;') 
       csv_writer.writerow(['round'] + column_names) 
       while True: 
        try: 
         csv_writer.writerow(cursor.fetchone()) 
        except csv.Error: 
         break 
0

Le répondre par retracile devrait être le plus proche, mais cela ne fonctionne pas pour mon cas. Une requête d'insertion s'est juste interrompue au milieu et l'exportation s'est arrêtée. Je ne sais pas quelle est la raison. Cependant, cela fonctionne bien pendant .dump.

Enfin j'ai écrit un outil pour la diviser le SQL généré à partir .dump:

https://github.com/motherapp/sqlite_sql_parser/

1

Examen d'autres solutions possibles

Inclure seulement INSERTS

sqlite3 database.db3 .dump | grep '^INSERT INTO "tablename"' 

facile à mettre en œuvre, mais il échouera si l'une de vos colonnes incl lignes Ude nouvelles

mode d'insertion SQLite

for t in $(sqlite3 $DB .tables); do 
    echo -e ".mode insert $t\nselect * from $t;" 
done | sqlite3 $DB > backup.sql 

C'est une solution agréable et personnalisable, mais il ne fonctionne pas si vos colonnes ont des objets blob comme type 'géométrie' dans spatialite

Diff la décharge avec le schéma

sqlite3 some.db .schema > schema.sql 
sqlite3 some.db .dump > dump.sql 
grep -v -f schema.sql dump > data.sql 

Je ne sais pas wh y, mais ne fonctionne pas pour moi

Une autre (nouvelle) solution possible

Probablement il n'y a pas une meilleure réponse à cette question, mais qui travaille pour moi grep les inserts en tenant compte du fait que soit nouveau lignes dans les valeurs de la colonne avec un expression like this

grep -Pzo "(?s)^INSERT.*\);[ \t]*$" 

pour sélectionner les tables ne sont l'objet de dumping .dump admet un argument LIKE pour faire correspondre les noms de table, mais si cela ne suffit pas probablement un script simple est meilleure option

TABLES='table1 table2 table3' 

echo '' > /tmp/backup.sql 
for t in $TABLES ; do 
    echo -e ".dump ${t}" | sqlite3 database.db3 | grep -Pzo "(?s)^INSERT.*?\);$" >> /tmp/backup.sql 
done 

ou quelque chose de plus élaboré pour respecter les clés étrangères et encapsuler toutes les décharge dans une seule transaction

TABLES='table1 table2 table3' 

echo 'BEGIN TRANSACTION;' > /tmp/backup.sql 
echo '' >> /tmp/backup.sql 
for t in $TABLES ; do 
    echo -e ".dump ${t}" | sqlite3 $1 | grep -Pzo "(?s)^INSERT.*?\);$" | grep -v -e 'PRAGMA foreign_keys=OFF;' -e 'BEGIN TRANSACTION;' -e 'COMMIT;' >> /tmp/backup.sql 
done 

echo '' >> /tmp/backup.sql 
echo 'COMMIT;' >> /tmp/backup.sql 

Prenez en compte que l'expression grep échouera si ); est une chaîne présente dans l'une des colonnes

pour restaurer (dans une base de données avec les tables déjà créées)

sqlite3 -bail database.db3 < /tmp/backup.sql 
4

Selon la documentation SQLite pour le Command Line Shell For SQLite vous pouvez exporter une table SQLite (ou une partie d'une table) au format CSV, en réglant simplement le « mode » à « csv », puis exécutez une requête pour extraire les lignes souhaitées de la table:

sqlite> .header on 
sqlite> .mode csv 
sqlite> .once c:/work/dataout.csv 
sqlite> SELECT * FROM tab1; 
sqlite> .exit 

utilisez ensuite la « .import » commande pour importer des données CSV (valeurs séparées par des virgules) dans une table SQLite:

sqlite> .mode csv 
sqlite> .import C:/work/dataout.csv tab1 
sqlite> .exit 

S'il vous plaît lire la plus documentation sur les deux cas à considérer: (1) Table « tab1 » ne n'existe pas précédemment et (2) la table "tab1" existe déjà.

Questions connexes