ฉันจะถ่ายโอนข้อมูลของตาราง SQLite3 บางตารางได้อย่างไร


183

ฉันจะถ่ายโอนข้อมูลและเฉพาะข้อมูลไม่ใช่ schema ของตาราง SQLite3 บางตัวของฐานข้อมูล (ไม่ใช่ตารางทั้งหมด) ได้อย่างไร ดัมพ์ควรอยู่ในรูปแบบ SQL เนื่องจากควรป้อนซ้ำในฐานข้อมูลได้อย่างง่ายดายในภายหลังและควรทำจากบรรทัดคำสั่ง สิ่งที่ต้องการ

sqlite3 db .dump

แต่ไม่มีการดัมพ์สกีมาและเลือกตารางที่จะดัมพ์


รูปแบบใด มีอะไรเป็นพิเศษหรือคุณแค่มองหาการสำรองข้อมูลที่มนุษย์สามารถอ่านได้? กรุณาระบุ
dmckee --- ผู้ดูแลอดีตลูกแมว

1
ฉันต้องการดัมพ์เป็นรูปแบบ SQL เพื่อที่ฉันจะสามารถกู้คืนได้อย่างง่ายดาย ฉันได้เพิ่มข้อมูลนั้นไปยังคำถามหลัก
pupeno

คำตอบ:


214

คุณไม่ได้พูดในสิ่งที่คุณต้องการจะทำกับไฟล์ที่ถูกทิ้ง

ฉันจะใช้สิ่งต่อไปนี้เพื่อรับไฟล์ CSV ซึ่งฉันสามารถนำเข้าได้เกือบทุกอย่าง

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

หากคุณต้องการแทรกเข้าไปในฐานข้อมูล SQLite อื่น:

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

มีวิธีการทำโปรแกรมนี้โดยใช้คำสั่ง SQL หรือไม่ ฉันเห็นวิธีการใช้ล่าม แต่ถ้าฉันต้องการเขียนสคริปต์
coleifer

4
คุณสามารถใส่งบของคุณในไฟล์ (เช่น sample.txt) แล้วเรียกใช้โดยใช้: sqlite3 db.sq3 <sample.txt
CyberFonic

" หรือใช้คำสั่ง .once แทน. เอาท์พุทและเอาท์พุทจะถูกเปลี่ยนเส้นทางสำหรับคำสั่งถัดไปเดียวก่อนที่จะย้อนกลับไปที่คอนโซลใช้. เอาท์พุทโดยไม่มีข้อโต้แย้งเพื่อเริ่มเขียนไปยังเอาต์พุตมาตรฐานอีกครั้ง " เอกสาร SQLite
ruffin

156

คุณสามารถทำสิ่งนี้เพื่อรับความแตกต่างของคำสั่ง. schema และ. dump เช่น grep:

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

data.sql ไฟล์จะมีเฉพาะข้อมูลที่ไม่มีสคีมาสิ่งนี้:

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

ฉันหวังว่านี่จะช่วยคุณได้


5
@ anurageldorado เป็น sql ธรรมดา เพิ่งวิ่งsqlite3 some.db < data.sql
แมงกะพรุน

สำหรับบางคนไม่ได้ทำงานให้ฉัน ฉันต้องการใช้รอบ sqlite3 storage/db/jobs.s3db .schema jobs > schema.sqlไม่ทำงาน แต่echo '.schema' jobs | sqlite3 storage/db/jobs.s3db > schema.sqlทำงานได้ดี
abkrim

2
ดูเหมือนว่าจะเป็นทางออกที่ดี แต่ในกรณีของฉันบรรทัดส่วนใหญ่จะถูกลบโดย grep คำสั่ง. schema สร้างสคีมาของแต่ละตารางบนหลายบรรทัดดังนั้นจึงมีบรรทัดที่มีเฉพาะ);และ grep จะลบบรรทัดทั้งหมดที่มีการ);เพิ่ม-xตัวเลือกเพื่อ grep แก้ไขปัญหานี้
Sunder

38

ไม่ใช่วิธีที่ดีที่สุด แต่ในการเช่าไม่จำเป็นต้องใช้เครื่องมือภายนอก (ยกเว้น grep ซึ่งเป็นมาตรฐานในกล่อง * ห้ามต่อไป)

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

แต่คุณจำเป็นต้องทำคำสั่งนี้สำหรับแต่ละตารางที่คุณกำลังมองหา

โปรดทราบว่านี่ไม่รวมสคีมา


1
ฉันใช้sqlite3 Database.s3db .dump
Jader Dias

3
สิ่งนี้จะแตกถ้าส่วนแทรกเหล่านั้นมีบรรทัดใหม่ในค่า ใช้งานได้ดีขึ้นgrep -v '^CREATE'ตามที่แนะนำในหนึ่งในคำตอบอื่น
dequis

1
ใช้grep -v '^CREATE;จะทำลายถ้าCREATEงบมีการแบ่งบรรทัดในพวกเขา (ซึ่งบางครั้งพวกเขาทำ) ที่ดีที่สุด IMO ไม่ได้เป็นการตัดCREATEงบออกโดยอัตโนมัติแต่แก้ไขด้วยตนเอง เพียงใช้เครื่องมือแก้ไขข้อความที่คุณต้องการและค้นหาCREATEและลบข้อความเหล่านั้นด้วยตนเอง ตราบใดที่ฐานข้อมูลยังไม่ใหญ่มาก (และเนื่องจากคุณใช้ sqlite ฉันเดาว่ามันเป็นโน้ต) ดังนั้นนี่จึงค่อนข้างง่าย
Dan Jones

แต่ grep ของการสร้างจะใช้การสร้างจากมุมมอง ฉันจะลบมันได้อย่างไร
Silve2611

35

คุณสามารถระบุอาร์กิวเมนต์ในตารางอย่างน้อยหนึ่งข้อให้กับคำสั่งsqlite3 db ".dump 'table1' 'table2'". dump พิเศษเช่น


4
เมื่อฉันเพิ่มชื่อตารางหลายชื่อตามที่คุณกล่าวถึงมันจะให้ผลลัพธ์นี้: การใช้งาน: .dump? - อนุรักษ์-rowids? หรือไม่เช่นรูปแบบ?
mwm

1
@mwm ฉันกำลังสังเกตปัญหาเดียวกันsqlite3 3.31.1 (2020/01/27)ค่ะ ผู้เปลี่ยนแปลงไม่ได้พูดอะไรเกี่ยวกับเรื่องนั้น (โดยวิธีการ--preserve-rowidsทำงาน แต่ไม่ได้บันทึกเลย)
ynn

11

คำตอบใด ๆ ที่แนะนำให้ใช้ grep เพื่อแยกCREATEบรรทัดหรือเพียงแค่จับINSERTเส้นจากsqlite3 $DB .dumpผลลัพธ์จะไม่ดี CREATE TABLEคำสั่งรายการคอลัมน์หนึ่งต่อบรรทัด (เพื่อไม่รวมCREATEจะไม่ได้รับทั้งหมดของมัน) และค่านิยมในINSERTสายจะมีการขึ้นบรรทัดใหม่ฝังตัว (ดังนั้นคุณจึงไม่สามารถคว้าเพียงINSERTบรรทัด)

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

ทดสอบกับ sqlite3 เวอร์ชั่น 3.6.20

หากคุณต้องการที่จะไม่รวมตารางบางอย่างที่คุณสามารถกรองพวกเขาด้วยหรือถ้าคุณต้องการที่จะได้รับเฉพาะกลุ่มย่อยแทนที่ด้วย$(sqlite $DB .tables | grep -v -e one -e two -e three)one two three


9

เพื่อเป็นการปรับปรุงคำตอบของ Paul Egan สิ่งนี้สามารถทำได้ดังนี้:

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

--หรือ--

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

แน่นอนว่าข้อแม้คือคุณต้องติดตั้ง grep


1
ฉันชอบอันนี้ ในฐานะที่เป็นโบนัสที่เพิ่มเข้ามามันยังคงใช้ได้หากคุณมีไฟล์ SQL ที่ถูกทิ้งไว้ห้อยอยู่รอบ ๆcat database.sql | grep '^INSERT' > database_inserts.sql(เหมือนเดิมสำหรับ schema แทนที่ด้วยgrep '^CREATE'
trisweb

2
@trisweb แน่นอนคุณหมายความgrep '^INSERT' < database.sql > database_inserts.sqlว่าcatไม่จำเป็น
Sebastian

1
ไม่มีอะไรฟุ่มเฟือยเกี่ยวกับเรื่องนี้ catค่าใช้จ่ายโดยทั่วไปไม่มีอะไรที่จะดำเนินการและทำให้ห่วงโซ่ของการป้อนข้อมูลเพื่อการส่งออกที่ชัดเจนมากขึ้น แน่นอนคุณสามารถเขียนได้< database.sql grep '^INSERT' ...แต่ท่อที่ชัดเจนง่ายต่อการอ่าน
rjh

1
เมื่อฉันเพิ่มชื่อตารางหลายชื่อตามที่คุณกล่าวถึงมันจะให้ผลลัพธ์นี้: การใช้งาน: .dump? - อนุรักษ์-rowids? หรือไม่เช่นรูปแบบ?
mwm

-1: การค้นหาบรรทัดด้วย CREATE เป็นความคิดที่ไร้ประโยชน์ เกือบทุกมุมมองหรือทริกเกอร์โดยเฉพาะถ้ามันมีความคิดเห็นต้องมีมากกว่าหนึ่งบรรทัด
ceving

6

ใน Python หรือ Java หรือภาษาระดับสูงใด ๆ . การถ่ายโอนข้อมูลไม่ทำงาน เราจำเป็นต้องเขียนโค้ดการแปลงเป็น CSV ด้วยตัวเอง ฉันยกตัวอย่าง Python คนอื่น ๆ ตัวอย่างจะได้รับการชื่นชม:

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

หากคุณมี 'ข้อมูลพาเนล' ในคำอื่น ๆ หลายรายการที่มี ID เพิ่มให้กับรูปลักษณ์และมันยังทิ้งสถิติสรุป:

        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

ตามเอกสาร SQLite สำหรับCommand Line Shell สำหรับ SQLiteคุณสามารถส่งออกตาราง SQLite (หรือบางส่วนของตาราง) เป็น CSV เพียงแค่ตั้งค่า "mode" เป็น "csv" แล้วเรียกใช้แบบสอบถามเพื่อแยกแถวที่ต้องการของ โต๊ะ:

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

จากนั้นใช้คำสั่ง ".import" เพื่อนำเข้าข้อมูล CSV (คั่นด้วยเครื่องหมายจุลภาค) ลงในตาราง SQLite:

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

โปรดอ่านเอกสารเพิ่มเติมเกี่ยวกับสองกรณีที่ต้องพิจารณา: (1) ตาราง "tab1" ไม่มีอยู่ก่อนหน้านี้และ (2) ตาราง "tab1" ไม่มีอยู่แล้ว


3

วิธีที่ดีที่สุดคือการใช้รหัส sqlite3 db dump จะทำยกเว้นส่วนสคีมา

ตัวอย่างรหัสเทียม:

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

ดู: src/shell.c:838 (สำหรับ sqlite-3.5.9) สำหรับรหัสจริง

คุณอาจจะแค่เอาเปลือกนั้นออกและคอมเม้นต์สคีมาแล้วใช้มัน


3

ทบทวนแนวทางแก้ไขที่เป็นไปได้อื่น ๆ

รวมเฉพาะ INSERT

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

ใช้งานง่าย แต่จะล้มเหลวหากคอลัมน์ใดคอลัมน์หนึ่งของคุณมีบรรทัดใหม่

โหมดแทรก SQLite

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

นี่เป็นโซลูชันที่ดีและสามารถปรับแต่งได้ แต่จะไม่ทำงานหากคอลัมน์ของคุณมีวัตถุหยดเช่นประเภท 'เรขาคณิต' ในพื้นที่

กระจายดัมพ์ด้วยสคีมา

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

ไม่แน่ใจว่าทำไม แต่ไม่ทำงานสำหรับฉัน

อีกวิธีแก้ปัญหาที่เป็นไปได้ (ใหม่)

อาจไม่มีคำตอบที่ดีที่สุดสำหรับคำถามนี้ แต่คำตอบที่ดีสำหรับฉันคือ grep ส่วนแทรกที่พิจารณาว่าเป็นบรรทัดใหม่ในค่าคอลัมน์ที่มีนิพจน์เช่นนี้

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

ในการเลือกตารางจะถูกทิ้ง.dumpยอมรับอาร์กิวเมนต์ LIKE เพื่อให้ตรงกับชื่อตาราง แต่ถ้านี่ไม่เพียงพออาจเป็นสคริปต์ง่าย ๆ เป็นตัวเลือกที่ดีกว่า

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

หรือมีสิ่งที่อธิบายเพิ่มเติมเกี่ยวกับการเคารพคีย์ต่างประเทศและแค็ปซูลการถ่ายโอนข้อมูลทั้งหมดในธุรกรรมเดียวเท่านั้น

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

พิจารณาว่านิพจน์ grep จะล้มเหลวหาก);มีสตริงอยู่ในคอลัมน์ใด ๆ

หากต้องการกู้คืน (ในฐานข้อมูลที่สร้างตารางไว้แล้ว)

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

2

รุ่นนี้ทำงานได้ดีกับการขึ้นบรรทัดใหม่ภายในส่วนแทรก:

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

ในทางปฏิบัติจะยกเว้นบรรทัดทั้งหมดที่เริ่มต้นด้วยCREATEซึ่งมีโอกาสน้อยที่จะมีการขึ้นบรรทัดใหม่


0

คำตอบโดย retracile ควรเป็นคำที่ใกล้เคียงที่สุด แต่ก็ไม่ได้ผลกับกรณีของฉัน หนึ่งแทรกการสืบค้นอยู่ตรงกลางและการส่งออกก็หยุดลง ไม่แน่ใจว่าอะไรคือเหตุผล .dumpแต่มันทำงานได้ดีในช่วง

ในที่สุดฉันก็เขียนเครื่องมือสำหรับแยก SQL ที่สร้างขึ้นจาก.dump:

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


-3

คุณสามารถเลือกในตารางที่ใส่เครื่องหมายจุลภาคหลังจากแต่ละฟิลด์เพื่อสร้าง csv หรือใช้เครื่องมือ GUI เพื่อส่งคืนข้อมูลทั้งหมดและบันทึกลงใน csv


2
ความตั้งใจของฉันคือการสร้างไฟล์ SQL ที่สามารถเพิ่มเข้าไปในฐานข้อมูลอีกครั้งได้อย่างง่ายดาย
pupeno
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.