web-dev-qa-db-fra.com

Comment vider les données de certaines tables SQLite3?

Comment vider les données, et uniquement les données, pas le schéma, de certaines tables SQLite3 d'une base de données (pas toutes les tables)? Le vidage doit être au format SQL, car il doit être facilement ré-entré ultérieurement dans la base de données et doit être effectué à partir de la ligne de commande. Quelque chose comme

sqlite3 db .dump

mais sans vider le schéma et sélectionner les tables à vider.

170
pupeno

Vous ne dites pas ce que vous souhaitez faire avec le fichier vidé.

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.csv 
select * from MyTable;

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

.mode insert <target_table_name>
.out file.sql 
select * from MyTable;
207
CyberFonic

Vous pouvez faire cela en obtenant la différence entre les 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

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

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

J'espère que ceci vous aide.

144
jellyfish

Ce n’est pas la meilleure solution, mais au moins n’a pas besoin d’outils externes (sauf grep, qui est de toutes façons standard sur les boîtes * nix)

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

mais vous devez faire cette commande pour chaque table que vous recherchez cependant.

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

37
polyglot

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

34
Paul Egan

Toute réponse suggérant d'utiliser grep pour exclure les lignes CREATE ou simplement saisir les lignes INSERT de la sortie sqlite3 $DB .dump échouera mal. Les commandes CREATE TABLE répertorient une colonne par ligne (ainsi, l'exclusion de CREATE ne l'obtiendra pas en totalité), et les valeurs des lignes INSERT peuvent comporter des traits nouveaux juste 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 la version 3.6.20 de sqlite3.

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.

10
retracile

Pour améliorer 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 installé grep.

8
Drew

Dans Python ou Java ou tout autre langage de haut niveau, le fichier .dump ne fonctionne pas. Nous devons coder la conversion au format CSV à la main. Je donne un exemple Python. D'autres, des 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 des données de panel, en d'autres termes, de nombreuses entrées individuelles avec un identifiant ajoutent ceci au look avec et produira également des statistiques récapitulatives:

        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 
6

Selon la documentation de SQLite pour le ligne de commande shell pour SQLite , vous pouvez exporter une table SQLite (ou une partie d’une table) au format CSV, en définissant simplement le "mode" sur "csv", puis en exécutant un script. requête pour extraire les lignes désiré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 commande ".import" 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

Veuillez lire la documentation complémentaire sur les deux cas à prendre en compte: (1) Le tableau "tab1" n’existait pas auparavant et (2) le tableau "tab1" existait déjà.

4
PeterCo

La meilleure méthode serait de prendre le code que ferait le dump sqlite3 db, en excluant les parties de schéma.

Exemple de pseudo-code:

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 actuel

Vous pouvez même simplement prendre ce shell, commenter les parties du schéma et l'utiliser.

3
harningt

Examen d'autres solutions possibles

Inclut uniquement les INSERT

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

Facile à mettre en œuvre mais cela échouera si l'une de vos colonnes inclut de nouvelles lignes

Mode d'insertion SQLite

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

Ceci est une solution agréable et personnalisable, mais cela ne fonctionne pas si vos colonnes ont des objets blob tels que 'Geometry' de type spatialite

Diffère le dump 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 pourquoi, mais ça ne marche pas pour moi

Une autre (nouvelle) solution possible

Il n’ya probablement pas de meilleure réponse à cette question, mais celle qui marche pour moi est grep les insertions en tenant compte des nouvelles lignes dans les valeurs de colonne avec un expression comme celle-ci

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

Pour sélectionner les tables, effectuez un vidage. .dump admet un argument LIKE correspondant aux noms des tables. Toutefois, si cela ne suffit pas, il est probablement préférable d'utiliser un simple script.

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 tout le dump en 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

Tenez compte du fait que l'expression grep échouera si ); est une chaîne présente dans l'une des colonnes.

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

sqlite3 -bail database.db3 < /tmp/backup.sql
3
Francisco Puga

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

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

En pratique, exclut toutes les lignes commençant par CREATE qui est moins susceptible de contenir des nouvelles lignes

2
Elia Schito

La réponse par rétracile devrait être la plus proche, mais cela ne fonctionne pas pour mon cas. Une requête d'insertion vient de se briser au milieu et l'exportation vient de s'arrêter. Je ne sais pas quelle est la raison. Cependant, cela fonctionne bien pendant .dump.

Enfin, j'ai écrit un outil pour scinder le SQL généré à partir de .dump:

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

0
Walty Yeung