Bazı SQLite3 tablolarının verilerini nasıl dökebilirim?


183

Bir veritabanının bazı SQLite3 tablolarının (tüm tabloların değil) yalnızca şemasını değil verilerini ve verilerini nasıl dökebilirim? Döküm daha sonra veritabanına kolayca yeniden girilmesi ve komut satırından yapılması gerektiği için SQL biçiminde olmalıdır. Gibi bir şey

sqlite3 db .dump

ancak şemayı boşaltmadan ve hangi tabloların döküleceğini seçmeden.


Hangi formatta? Özellikle herhangi bir şey mi yoksa sadece okunabilir bir yedek mi arıyorsunuz? Lütfen belirtiniz.
dmckee --- ex-moderatör kedi yavrusu

1
SQL formatına dökmek istiyorum, böylece kolayca geri yükleyebilirim. Bu bilgiyi ana soruya ekledim.
pupeno

Yanıtlar:


214

Boşaltılan dosyayla ne yapmak istediğinizi söylemiyorsunuz.

Hemen hemen her şeye aktarabileceğim bir CSV dosyası almak için aşağıdakileri kullanırdım

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

Farklı bir SQLite veritabanına yeniden eklemek istiyorsanız:

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

SQL deyimlerini kullanarak programlı olarak bunu yapmanın bir yolu var mı? Tercüman kullanarak nasıl yapılacağını görebiliyorum, ama senaryo yazmak istersem ne olur?
coleifer

4
İfadelerinizi bir dosyaya (örn. Sample.txt) koyabilir ve daha sonra şunu kullanarak başlatabilirsiniz: sqlite3 db.sq3 <sample.txt
CyberFonic

" Veya .output yerine .once komutunu kullanın ve çıktılar konsola dönmeden önce yalnızca bir sonraki komut için yeniden yönlendirilecektir. Standart çıktıya yeniden yazmaya başlamak için argüman olmadan .output komutunu kullanın. " SQLite docs
ruffin

156

Bunu .schema ve .dump komutlarının farkını alarak yapabilirsiniz. örneğin grep ile:

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

data.sql dosyası yalnızca şema içermeyen veriler içerir, şuna benzer:

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

Umarım bu sana yardımcı olur.


5
@anurageldorado bu düz sql. sadece koşmaksqlite3 some.db < data.sql
denizanası

Bazı rassonlar benim için çalışmıyor. Etrafta kullanımlara ihtiyacım var. sqlite3 storage/db/jobs.s3db .schema jobs > schema.sqlçalışmıyor, ama echo '.schema' jobs | sqlite3 storage/db/jobs.s3db > schema.sqliyi çalışıyor
abkrim

2
İyi bir çözüm gibi görünüyordu, ama benim durumumda çizgilerin çoğu aslında grep tarafından kaldırılıyor. .Schema komutu, her tablonun şemasını birden çok satırda oluşturur, bu nedenle yalnızca içeren bir satır vardır );ve grep, grep seçeneğine );ekleme -xseçeneği içeren tüm satırları bu sorunu çözer.
Sunder

38

En iyi yol değil, ancak kiralamada harici araçlara ihtiyaç duymaz (yine de * nix kutularında standart olan grep hariç)

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

ancak aradığınız her tablo için bu komutu yapmanız gerekir.

Bunun şema içermediğini unutmayın.


1
Kullandımsqlite3 Database.s3db .dump
Jader Dias

3
Bu ekler değerlerde satırsonu varsa bu kesilir. grep -v '^CREATE'Diğer cevaplardan birinde önerildiği gibi daha iyi kullanım
dequis

1
kullanarak grep -v '^CREATE;eğer kıracak CREATEifadeleri içlerinde satır sonları (bazen yaparlar) var. En iyisi, IMO, CREATEifadeleri otomatik olarak çıkarmak değil, manuel olarak düzenlemek. İhtiyacınız olan her metin düzenleyiciyi kullanın CREATEve bu ifadeleri arayın ve manuel olarak kaldırın. Veritabanı çok büyük olmadığı sürece (ve sqlite kullandığınızdan beri, not olduğunu tahmin ediyorum), bu oldukça basittir.
Dan Jones

ancak oluşturmanın grep'i oluşturmayı görünümlerden de alacaktır. bunu nasıl kaldırabilirim?
Silve2611

35

.Dump özel komutuna bir veya daha fazla tablo bağımsız değişkeni belirtebilirsiniz, örn sqlite3 db ".dump 'table1' 'table2'".


4
bahsettiğiniz gibi birden çok tablo adı eklediğimde, bu çıktıyı verir: Kullanım: .dump? - preserve-rowids? ? GİBİ-MODEL?
mwm

1
@mwm de aynı sorunu gözlemliyorum sqlite3 3.31.1 (2020/01/27). Değişiklik günlüğü bu konuda hiçbir şey söylemiyor. (Bu arada, --preserve-rowidsçalışıyor ama hiç belgelenmedi.)
ynn

11

CREATEÇizgileri hariç tutmak veya sadece çıktıdan INSERTalmak için grep kullanılmasını öneren herhangi bir cevap sqlite3 $DB .dumpkötü bir şekilde başarısız olacaktır. CREATE TABLEKomutları satır başına bir sütun listesi (hariç yüzden CREATEhepsini almazsınız) ve üzerinde değerler INSERT(sadece kapmak olamaz böylece hatları gömülü yeni satır olabilir INSERTçizgiler).

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

Sqlite3 sürüm 3.6.20 üzerinde test edilmiştir.

Belirli tabloları hariç tutmak istiyorsanız, bunları filtreleyebilirsiniz $(sqlite $DB .tables | grep -v -e one -e two -e three)veya belirli bir alt küme almak istiyorsanız, bunu bununla değiştirin one two three.


9

Paul Egan'ın cevabında bir gelişme olarak, bu aşağıdaki gibi yapılabilir:

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

--veya--

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

Tabii ki uyarı, grep'in kurulu olması gerektiğidir.


1
Bunu beğendim. Ek bir bonus olarak, etrafta asılı bir cat database.sql | grep '^INSERT' > database_inserts.sqlgrep '^CREATE'
dökümü

2
@trisweb elbette Şunu grep '^INSERT' < database.sql > database_inserts.sqlo catgereksiz olduğunu
Sebastian

1
Bu konuda gereksiz bir şey yok. catTemelde yürütülecek hiçbir maliyeti ve girişten çıkışa zinciri daha net hale getirir. Tabii ki de yazabilirsiniz, < database.sql grep '^INSERT' ...ancak açık bir borunun okunması çok daha kolaydır.
rjh

1
bahsettiğiniz gibi birden çok tablo adı eklediğimde, bu çıktıyı verir: Kullanım: .dump? - preserve-rowids? ? GİBİ-MODEL?
mwm

-1: CREATE ile satır aramak işe yaramaz bir fikirdir. Hemen hemen her görünüm veya tetikleyici, özellikle yorum içeriyorsa, birden fazla satır gerektirir.
ceving

6

Python veya Java veya herhangi bir üst düzey dilde .dump çalışmaz. CSV'ye dönüşümü elle kodlamamız gerekiyor. Bir Python örneği veriyorum. Diğerleri, örnekler takdir edilecektir:

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

Panel verileriniz varsa, başka bir deyişle, kimliğine sahip birçok bağımsız giriş bunu görünümüne ekler ve ayrıca özet istatistiklerini döker:

        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 

4

Komut Satırı Kabuğu için SQLite belgelerine göre SQLite için bir SQLite tablosunu (veya tablonun bir bölümünü) CSV olarak dışa aktarabilirsiniz, sadece "mod" u "csv" olarak ayarlayıp daha sonra istenen satırları ayıklamak için bir sorgu çalıştırabilirsiniz. tablo:

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

Daha sonra CSV (virgülle ayrılmış değer) verilerini SQLite tablosuna içe aktarmak için ".import" komutunu kullanın:

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

Lütfen dikkate alınması gereken iki durumla ilgili diğer belgeleri okuyun: (1) "tab1" tablosu daha önce mevcut değil ve (2) "tab1" tablosu zaten mevcut.


3

En iyi yöntem, şema parçaları hariç sqlite3 db dökümünün yapacağı kodu almak olacaktır.

Örnek sözde kod:

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

Görmek: src/shell.c:838 Gerçek kod için (sqlite-3.5.9 için)

Hatta o kabuğu alıp şema bölümlerini yorumlayabilir ve kullanabilirsiniz.


3

Diğer olası çözümlerin gözden geçirilmesi

Yalnızca INSERT'leri dahil et

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

Uygulaması kolaydır, ancak sütunlarınızdan herhangi birinde yeni satırlar varsa başarısız olur

SQLite ekleme modu

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

Bu hoş ve özelleştirilebilir bir çözümdür, ancak sütunlarınızda mekansalda 'Geometri' türü gibi blob nesneleri varsa işe yaramaz.

Dökümü şema ile dağıtın

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

Neden olduğundan emin değilim ama benim için çalışmıyor

Başka bir (yeni) olası çözüm

Muhtemelen bu soruya en iyi cevap yoktur, ancak benim için çalışan bir tanesi, böyle bir ifadeyle sütun değerlerinde yeni satırlar olduğunu dikkate alarak ekleri grep

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

Dumped tabloları seçmek için .dumptablo adlarını eşleştirmek için bir LIKE argümanı kabul, ancak bu yeterli değilse, muhtemelen basit bir komut dosyası daha iyi bir seçenek

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

veya yabancı anahtarlara saygı göstermek ve tüm çöplüğü tek bir işlemde kapsüllemek için daha ayrıntılı bir şey

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

);Sütunlardan herhangi birinde bir dize varsa grep ifadesinin başarısız olacağını dikkate alın

Geri yüklemek için (tablolar önceden oluşturulmuş bir veritabanında)

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

2

Bu sürüm, insert içindeki yeni satırlarla iyi çalışır:

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

Uygulamada CREATE, yeni satır içermesi daha düşük olan tüm satırları hariç tutar


0

Geri çekilme ile cevap en yakın cevap olmalı, ancak benim durumum için çalışmıyor. Bir ekleme sorgusu tam ortada kırıldı ve dışa aktarma durdu. Sebebin ne olduğundan emin değilim. Ancak sırasında iyi çalışır.dump .

Sonunda oluşturulan SQL bölünmek için bir araç yazdım .dump:

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


-3

Bir csv üretmek için her alandan sonra virgül ekleyerek tablolarda bir seçim yapabilir veya tüm verileri döndürmek ve bir csv'ye kaydetmek için bir GUI aracı kullanabilirsiniz.


2
Amacım kolayca DB yeniden eklenebilir bir SQL dosyası üretmekti.
pupeno
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.