Bagaimana cara membuang data dari beberapa tabel SQLite3?

183

Bagaimana cara membuang data, dan hanya data, bukan skema, dari beberapa tabel SQLite3 dari database (tidak semua tabel)? Dump harus dalam format SQL, karena harus dengan mudah dimasukkan kembali ke dalam database nanti dan harus dilakukan dari baris perintah. Sesuatu seperti

sqlite3 db .dump

tetapi tanpa membuang skema dan memilih tabel mana yang akan dibuang.

Pablo
sumber
Untuk format apa? Ada yang khusus, atau Anda hanya mencari cadangan yang dapat dibaca manusia? Silakan tentukan.
dmckee --- ex-moderator kitten
1
Saya ingin membuang ke format SQL, sehingga saya dapat mengembalikannya dengan mudah. Saya telah menambahkan informasi itu ke pertanyaan utama.
pupeno

Jawaban:

214

Anda tidak mengatakan apa yang ingin Anda lakukan dengan file yang dibuang.

Saya akan menggunakan yang berikut ini untuk mendapatkan file CSV, yang dapat saya impor ke hampir semuanya

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

Jika Anda ingin memasukkan kembali ke dalam database SQLite yang berbeda maka:

.mode insert <target_table_name>
.out file.sql 
select * from MyTable;
CyberFonic
sumber
Apakah ada cara untuk melakukan ini secara terprogram menggunakan pernyataan SQL? Saya bisa melihat bagaimana melakukannya menggunakan penerjemah, tetapi bagaimana jika saya ingin menulis naskah?
coleifer
4
Anda dapat meletakkan pernyataan Anda dalam file (mis. Sample.txt) dan memohonnya menggunakan: sqlite3 db.sq3 <sample.txt
CyberFonic
" Atau gunakan perintah .once alih-alih .output dan output hanya akan diarahkan untuk satu perintah berikutnya sebelum kembali ke konsol. Gunakan .output tanpa argumen untuk mulai menulis ke output standar lagi. " SQLite docs
ruffin
156

Anda dapat melakukan ini dengan mendapatkan perbedaan perintah .schema dan .dump. misalnya dengan grep:

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

data.sql file hanya akan berisi data tanpa skema, seperti ini:

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

Saya harap ini membantu Anda.

ubur-ubur
sumber
5
@anurageldorado sangat sederhana. jalankan sajasqlite3 some.db < data.sql
ubur
Untuk beberapa rasson tidak bekerja untukku. Saya perlu menggunakan sekitar. sqlite3 storage/db/jobs.s3db .schema jobs > schema.sqltidak bekerja, tetapi echo '.schema' jobs | sqlite3 storage/db/jobs.s3db > schema.sqlbekerja dengan baik
abkrim
2
Tampaknya ini adalah solusi yang bagus, tetapi dalam kasus saya sebagian besar baris benar-benar dihapus oleh grep. Perintah .schema menghasilkan skema setiap tabel pada beberapa baris, jadi ada satu baris yang berisi saja );, dan grep menghapus semua baris yang berisi );Menambahkan -xopsi untuk grep menyelesaikan masalah ini.
Sunder
38

Bukan cara terbaik, tetapi setidaknya tidak memerlukan alat eksternal (kecuali grep, yang merupakan standar pada * nix box)

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

tetapi Anda perlu melakukan perintah ini untuk setiap tabel yang Anda cari.

Perhatikan bahwa ini tidak termasuk skema.

poliglot
sumber
1
Saya menggunakansqlite3 Database.s3db .dump
Jader Dias
3
Ini akan rusak jika sisipan tersebut memiliki baris baru dalam nilai. Lebih baik digunakan grep -v '^CREATE'seperti yang disarankan dalam salah satu jawaban lain
dequis
1
menggunakan grep -v '^CREATE;akan rusak jika CREATEpernyataan memiliki garis istirahat di dalamnya (yang kadang-kadang mereka lakukan). Terbaik, IMO, tidak secara otomatis menghapus CREATEpernyataan sama sekali, tetapi secara manual mengeditnya. Cukup gunakan editor teks apa pun yang Anda butuhkan, dan cari CREATEdan hapus secara manual pernyataan-pernyataan itu. Selama databasenya tidak besar (dan karena Anda menggunakan sqlite, saya kira itu catatan), maka ini cukup sederhana.
Dan Jones
tetapi grep dari buat juga akan mengambil buat dari pandangan. bagaimana saya bisa menghapusnya?
Silve2611
35

Anda bisa menentukan satu atau lebih argumen tabel ke perintah khusus .dump, mis sqlite3 db ".dump 'table1' 'table2'".

Paul Egan
sumber
4
ketika saya menambahkan beberapa nama tabel seperti yang Anda sebutkan, itu memberi saya hasil ini: Penggunaan: .dump? - preserve-rowid? POLA SEPERTI?
mwm
1
@ mwm Saya mengamati masalah yang sama di sqlite3 3.31.1 (2020/01/27). The changelog mengatakan apa-apa tentang itu. (Ngomong-ngomong, --preserve-rowidsitu bekerja tetapi tidak didokumentasikan sama sekali.)
ynn
11

Setiap jawaban yang menyarankan penggunaan grep untuk mengecualikan CREATEgaris atau hanya mengambil INSERTgaris dari sqlite3 $DB .dumpoutput akan gagal parah. The CREATE TABLEdaftar perintah satu kolom per baris (sehingga tidak termasuk CREATEtidak akan mendapatkan semua itu), dan nilai-nilai pada INSERTbaris dapat memiliki baris baru tertanam (sehingga Anda tidak bisa ambil hanya INSERTgaris).

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

Diuji pada sqlite3 versi 3.6.20.

Jika Anda ingin mengecualikan tabel tertentu Anda dapat memfilternya $(sqlite $DB .tables | grep -v -e one -e two -e three), atau jika Anda ingin mendapatkan subset tertentu ganti dengan one two three.

retracile
sumber
9

Sebagai peningkatan pada jawaban Paul Egan, ini dapat dicapai sebagai berikut:

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

--atau--

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

Peringatannya, tentu saja, adalah bahwa Anda harus menginstal grep.

Drew
sumber
1
Saya suka yang ini. Sebagai bonus tambahan, itu masih berfungsi jika Anda memiliki file SQL cat database.sql | grep '^INSERT' > database_inserts.sqlgrep '^CREATE'
dumped
2
@trisweb, tentu saja Anda berarti grep '^INSERT' < database.sql > database_inserts.sqlbahwa catadalah berlebihan
Sebastian
1
Tidak ada yang berlebihan tentang hal itu. The catdasarnya tidak ada biaya untuk mengeksekusi dan membuat rantai dari input ke output lebih jelas. Tentu saja, Anda juga bisa menulis < database.sql grep '^INSERT' ...tetapi pipa eksplisit lebih mudah dibaca.
rjh
1
ketika saya menambahkan beberapa nama tabel seperti yang Anda sebutkan, itu memberi saya hasil ini: Penggunaan: .dump? - preserve-rowid? POLA SEPERTI?
mwm
-1: Mencari garis dengan CREATE adalah ide yang tidak berguna. Hampir setiap tampilan atau pemicu khususnya, jika berisi komentar, membutuhkan lebih dari satu baris.
ceving
6

Dalam Python atau Java atau bahasa tingkat tinggi apa pun. Dump tidak berfungsi. Kita perlu mengkodekan konversi ke CSV dengan tangan. Saya memberikan contoh Python. Lainnya, contoh akan dihargai:

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

Jika Anda memiliki 'data panel, dengan kata lain banyak entri individual dengan id menambahkan ini ke tampilan with dan juga membuang statistik ringkasan:

        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 
Davoud Taghawi-Nejad
sumber
4

Menurut dokumentasi SQLite untuk Command Line Shell For SQLite Anda dapat mengekspor tabel SQLite (atau bagian dari tabel) sebagai CSV, cukup dengan mengatur "mode" ke "csv" dan kemudian menjalankan kueri untuk mengekstrak baris yang diinginkan dari meja:

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

Kemudian gunakan perintah ".import" untuk mengimpor data CSV (comma separated value) ke dalam tabel SQLite:

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

Silakan baca dokumentasi lebih lanjut tentang dua kasus untuk mempertimbangkan: (1) Tabel "tab1" sebelumnya tidak ada dan (2) tabel "tab1" sudah ada.

PeterCo
sumber
3

Metode terbaik adalah dengan mengambil kode dump sqlite3 db akan lakukan, tidak termasuk bagian skema.

Contoh kode semu:

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

Lihat: src/shell.c:838 (untuk sqlite-3.5.9) untuk kode aktual

Anda bahkan mungkin hanya mengambil shell itu dan mengomentari bagian skema dan menggunakannya.

Harningt
sumber
3

Tinjau solusi lain yang mungkin

Sertakan hanya INSERT

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

Mudah diimplementasikan tetapi akan gagal jika salah satu kolom Anda menyertakan baris baru

Mode penyisipan SQLite

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

Ini adalah solusi yang bagus dan dapat disesuaikan, tetapi tidak berfungsi jika kolom Anda memiliki objek gumpalan seperti tipe 'Geometri' dalam spasial

Bedakan dengan skema

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

Tidak yakin mengapa, tetapi tidak berhasil untuk saya

Solusi (baru) lainnya yang mungkin

Mungkin tidak ada jawaban terbaik untuk pertanyaan ini, tetapi salah satu yang berfungsi untuk saya adalah ambil sisipan dengan mempertimbangkan baris baru di kolom yang bernilai dengan ekspresi seperti ini

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

Untuk memilih tabel jangan dibuang .dumpmengakui argumen LIKE untuk mencocokkan nama tabel, tetapi jika ini tidak cukup mungkin skrip sederhana adalah pilihan yang lebih baik

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

atau, sesuatu yang lebih rumit untuk menghormati kunci asing dan merangkum semua dump hanya dalam satu transaksi

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

Mempertimbangkan bahwa ekspresi grep akan gagal jika );ada string di salah satu kolom

Untuk mengembalikannya (dalam database dengan tabel sudah dibuat)

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

Versi ini berfungsi baik dengan baris baru di dalam sisipan:

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

Dalam praktiknya mengecualikan semua baris yang dimulai dengan CREATEyang cenderung mengandung baris baru

Elia Schito
sumber
0

Jawaban dengan retracile haruslah jawaban yang paling dekat, tetapi tidak berhasil untuk kasus saya. Satu permintaan memasukkan baru saja putus di tengah dan ekspor hanya berhenti. Tidak yakin apa alasannya. Namun itu berfungsi dengan baik selama .dump.

Akhirnya saya menulis alat untuk membagi SQL yang dihasilkan dari .dump:

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

Walty Yeung
sumber
-3

Anda bisa melakukan pilih pada tabel memasukkan koma setelah setiap bidang untuk menghasilkan csv, atau menggunakan alat GUI untuk mengembalikan semua data dan menyimpannya ke csv.


sumber
2
Tujuan saya adalah untuk menghasilkan file SQL yang dapat dengan mudah ditambahkan kembali ke DB.
pupeno