¿Cómo vuelco los datos de algunas tablas SQLite3?

183

¿Cómo vuelco los datos, y solo los datos, no el esquema, de algunas tablas SQLite3 de una base de datos (no todas las tablas)? El volcado debe estar en formato SQL, ya que se debe volver a ingresar fácilmente en la base de datos más adelante y debe hacerse desde la línea de comandos. Algo como

sqlite3 db .dump

pero sin volcar el esquema y seleccionar qué tablas volcar.

Pablo
fuente
¿A que formato? ¿Algo en particular o simplemente está buscando una copia de seguridad legible por humanos? Por favor especifica.
dmckee --- ex-gatito moderador
1
Quiero volcar al formato SQL, para poder restaurarlo fácilmente. He agregado esa información a la pregunta principal.
pupeno

Respuestas:

214

No estás diciendo lo que deseas hacer con el archivo volcado.

Usaría lo siguiente para obtener un archivo CSV, que puedo importar en casi todo

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

Si desea reinsertarse en una base de datos SQLite diferente, entonces:

.mode insert <target_table_name>
.out file.sql 
select * from MyTable;
CyberFonic
fuente
¿Hay alguna manera de hacer esto mediante programación utilizando sentencias SQL? Puedo ver cómo hacerlo usando el intérprete, pero ¿y si quisiera escribir un guión?
coleifer
44
Puede poner sus declaraciones en un archivo (por ejemplo, sample.txt) y luego invocarlo usando: sqlite3 db.sq3 <sample.txt
CyberFonic
" O use el comando .once en lugar de .output y la salida solo se redirigirá para el siguiente comando antes de volver a la consola. Use .output sin argumentos para comenzar a escribir nuevamente en la salida estándar " .
Documentos
156

Puede hacer esto obteniendo la diferencia de los comandos .schema y .dump. por ejemplo con grep:

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

data.sql El archivo contendrá solo datos sin esquema, algo como esto:

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

Espero que esto te ayude.

medusa
fuente
55
@anurageldorado es simple sql. acaba de corrersqlite3 some.db < data.sql
medusas
Para algunos rasson no funciona para mí. Necesito usos alrededor. sqlite3 storage/db/jobs.s3db .schema jobs > schema.sqlno funciona, pero echo '.schema' jobs | sqlite3 storage/db/jobs.s3db > schema.sqlfunciona bien
abkrim
2
Parecía una buena solución, pero en mi caso la mayoría de las líneas se están eliminando con grep. El comando .schema genera el esquema de cada tabla en varias líneas, por lo que solo hay una línea que contiene );, y grep elimina todas las líneas que contienen );Agregar la -xopción a grep resuelve este problema.
Sunder
38

No es la mejor manera, pero al arrendamiento no necesita herramientas externas (excepto grep, que de todos modos es estándar en las cajas * nix)

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

pero necesita hacer este comando para cada tabla que está buscando.

Tenga en cuenta que esto no incluye el esquema.

polígloto
fuente
1
Yo solíasqlite3 Database.s3db .dump
Jader Dias
3
Esto se romperá si esas inserciones tienen nuevas líneas en los valores. Mejor uso grep -v '^CREATE'como se sugiere en una de las otras respuestas
dequis
1
el uso grep -v '^CREATE;se interrumpirá si las CREATEdeclaraciones tienen saltos de línea (lo que a veces hacen). Lo mejor, IMO, es no eliminar automáticamente las CREATEdeclaraciones, sino editarlas manualmente. Simplemente use el editor de texto que necesite y busque CREATEy elimine manualmente esas declaraciones. Mientras la base de datos no sea enorme (y dado que está usando sqlite, supongo que es una nota), entonces esto es bastante simple.
Dan Jones
pero el grep de la creación también tomará la creación de las vistas. ¿Cómo puedo eliminar eso?
Silve2611
35

Puede especificar uno o más argumentos de tabla para el comando especial .dump, por ejemplo sqlite3 db ".dump 'table1' 'table2'".

Paul Egan
fuente
44
cuando agrego varios nombres de tablas como mencionó, me da este resultado: Uso: .dump? - preserve-rowids? ? COMO PATRÓN?
mwm
1
@mwm Estoy observando el mismo problema en sqlite3 3.31.1 (2020/01/27). El registro de cambios no dice nada al respecto. (Por cierto, --preserve-rowidsfunciona pero no está documentado en absoluto.)
ynn
11

Cualquier respuesta que sugiera usar grep para excluir las CREATElíneas o simplemente tomar las INSERTlíneas de la sqlite3 $DB .dumpsalida fallará gravemente. Los CREATE TABLEcomandos enumeran una columna por línea (por lo que excluir CREATEno obtendrá todo), y los valores en las INSERTlíneas pueden tener nuevas líneas incrustadas (por lo que no puede tomar solo las INSERTlíneas).

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

Probado en sqlite3 versión 3.6.20.

Si desea excluir ciertas tablas con las que puede filtrarlas $(sqlite $DB .tables | grep -v -e one -e two -e three), o si desea obtener un subconjunto específico, reemplácelo con one two three.

retroceder
fuente
9

Como una mejora a la respuesta de Paul Egan, esto se puede lograr de la siguiente manera:

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

--o--

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

La advertencia, por supuesto, es que tienes que tener grep instalado.

Dibujó
fuente
1
Me gusta este. Como beneficio adicional, aún funciona si tiene un archivo SQL volcado dando vueltas, solo cat database.sql | grep '^INSERT' > database_inserts.sql(lo mismo para el esquema, reemplace congrep '^CREATE'
trisweb
2
@trisweb, por supuesto que quieres decir grep '^INSERT' < database.sql > database_inserts.sqlque cates superfluo
Sebastian
1
Nada superfluo al respecto. La catcuesta prácticamente nada para ejecutar y hace que la cadena de entrada como de salida mucho más clara. Por supuesto, también podría escribir, < database.sql grep '^INSERT' ...pero una tubería explícita es mucho más fácil de leer.
rjh
1
cuando agrego varios nombres de tablas como mencionó, me da este resultado: Uso: .dump? - preserve-rowids? ? COMO PATRÓN?
mwm
-1: Buscar líneas con CREATE es una idea inútil. Casi todas las vistas o disparadores, especialmente si contienen comentarios, requieren más de una línea.
ceving
6

En Python o Java o en cualquier lenguaje de alto nivel, el .dump no funciona. Necesitamos codificar la conversión a CSV a mano. Doy un ejemplo de Python. Otros, se agradecerían ejemplos:

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 tiene "datos del panel", en otras palabras, muchas entradas individuales con ID agregan esto al aspecto y también vuelca las estadísticas de resumen:

        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 
rev. Davoud Taghawi-Nejad
fuente
4

De acuerdo con la documentación de SQLite para Command Line Shell Para SQLite , puede exportar una tabla de SQLite (o parte de una tabla) como CSV, simplemente configurando el "modo" a "csv" y luego ejecute una consulta para extraer las filas deseadas de la mesa:

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

Luego use el comando ".import" para importar datos CSV (valores separados por comas) en una tabla SQLite:

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

Lea la documentación adicional sobre los dos casos a considerar: (1) la tabla "tab1" no existe anteriormente y (2) la tabla "tab1" ya existe.

revs PeterCo
fuente
3

El mejor método sería tomar el código que haría el volcado sqlite3 db, excluyendo las partes del esquema.

Ejemplo de pseudocódigo:

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

Ver: src/shell.c:838 (para sqlite-3.5.9) para el código real

Incluso podría tomar ese caparazón y comentar las partes del esquema y usarlo.

harningt
fuente
3

Revisión de otras posibles soluciones.

Incluir solo INSERTOS

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

Fácil de implementar pero fallará si alguna de sus columnas incluye nuevas líneas

Modo de inserción de SQLite

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

Esta es una solución agradable y personalizable, pero no funciona si sus columnas tienen objetos blob como el tipo 'Geometry' en spaceialite

Difunde el basurero con el esquema

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

No estoy seguro de por qué, pero no funciona para mí.

Otra (nueva) posible solución

Probablemente no haya una mejor respuesta a esta pregunta, pero una que funciona para mí es grep las inserciones teniendo en cuenta que hay nuevas líneas en los valores de columna con una expresión como esta

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

Para seleccionar las tablas que se descartan, se .dumpadmite un argumento LIKE para que coincida con los nombres de las tablas, pero si esto no es suficiente, probablemente un script simple sea una mejor opción

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

o algo más elaborado para respetar las claves externas y encapsular todo el volcado en una sola transacción

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

Tenga en cuenta que la expresión grep fallará si );hay una cadena presente en cualquiera de las columnas

Para restaurarlo (en una base de datos con las tablas ya creadas)

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

Esta versión funciona bien con líneas nuevas dentro de inserciones:

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

En la práctica, excluye todas las líneas que comienzan con CREATEmenos probabilidades de contener nuevas líneas.

Elia Schito
fuente
0

La respuesta por retracile debería ser la más cercana, pero no funciona para mi caso. Una consulta de inserción simplemente se rompió en el medio y la exportación simplemente se detuvo. No estoy seguro de cuál es la razón. Sin embargo, funciona bien durante .dump.

Finalmente escribí una herramienta para dividir el SQL generado a partir de .dump:

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

Walty Yeung
fuente
-3

Puede hacer una selección en las tablas insertando comas después de cada campo para producir un csv, o usar una herramienta GUI para devolver todos los datos y guardarlos en un csv.


fuente
2
Mi intención era producir un archivo SQL que pudiera volver a agregarse fácilmente a la base de datos.
pupeno