Làm cách nào để kết xuất dữ liệu của một số bảng SQLite3?


183

Làm cách nào để tôi kết xuất dữ liệu và chỉ dữ liệu chứ không phải lược đồ của một số bảng SQLite3 của cơ sở dữ liệu (không phải tất cả các bảng)? Kết xuất phải ở định dạng SQL, vì nó sẽ dễ dàng được nhập lại vào cơ sở dữ liệu sau đó và nên được thực hiện từ dòng lệnh. Cái gì đó như

sqlite3 db .dump

nhưng không bỏ lược đồ và chọn bảng nào để kết xuất.


Đến định dạng nào? Bất cứ điều gì đặc biệt, hoặc bạn chỉ đang tìm kiếm một bản sao lưu có thể đọc được của con người? Xin hãy chỉ ra cụ thể.
dmckee --- ex-moderator mèo con

1
Tôi muốn chuyển sang định dạng SQL, để tôi có thể khôi phục nó dễ dàng. Tôi đã thêm thông tin đó vào câu hỏi chính.
Pupeno

Câu trả lời:


214

Bạn không nói những gì bạn muốn làm với tệp bị đổ.

Tôi sẽ sử dụng cách sau để nhận tệp CSV mà tôi có thể nhập vào hầu hết mọi thứ

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

Nếu bạn muốn đăng nhập lại vào cơ sở dữ liệu SQLite khác thì:

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

Có cách nào để thực hiện việc này bằng cách sử dụng các câu lệnh SQL không? Tôi có thể thấy cách thực hiện bằng trình thông dịch, nhưng nếu tôi muốn viết một kịch bản thì sao?
coleifer

4
Bạn có thể đặt các câu lệnh của mình trong một tệp (ví dụ sample.txt) và sau đó gọi nó bằng cách sử dụng: sqlite3 db.sq3 <sample.txt
CyberFonic

" Hoặc sử dụng lệnh .once thay vì .output và đầu ra sẽ chỉ được chuyển hướng cho một lệnh tiếp theo trước khi quay trở lại bàn điều khiển. Sử dụng .output không có đối số để bắt đầu ghi lại đầu ra tiêu chuẩn. " Tài liệu SQLite
ruffin

156

Bạn có thể làm điều này nhận được sự khác biệt của các lệnh .schema và .dump. ví dụ với grep:

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

data.sql tệp sẽ chỉ chứa dữ liệu mà không có lược đồ, đại loại như thế này:

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

Tôi hy vọng cái này sẽ giúp bạn.


5
@anurageldorado nó đơn giản là sql. chỉ cần chạysqlite3 some.db < data.sql
sứa

Đối với một số rasson không làm việc cho tôi. Tôi cần sử dụng xung quanh. sqlite3 storage/db/jobs.s3db .schema jobs > schema.sqlkhông hoạt động, nhưng echo '.schema' jobs | sqlite3 storage/db/jobs.s3db > schema.sqlhoạt động tốt
abkrim

2
Nó có vẻ là một giải pháp tốt, nhưng trong trường hợp của tôi, hầu hết các dòng thực sự bị xóa bởi grep. Lệnh .schema tạo lược đồ của mỗi bảng trên nhiều dòng, do đó, có một dòng chỉ chứa );và grep sẽ xóa tất cả các dòng chứa );Thêm -xtùy chọn để grep giải quyết vấn đề này.
Sunder

38

Không phải là cách tốt nhất, nhưng khi cho thuê không cần các công cụ bên ngoài (ngoại trừ grep, dù sao cũng là tiêu chuẩn trên các hộp * nix)

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

nhưng bạn cần phải thực hiện lệnh này cho mỗi bảng mà bạn đang tìm kiếm.

Lưu ý rằng điều này không bao gồm lược đồ.


1
Tôi đã sử dụngsqlite3 Database.s3db .dump
Jader Dias

3
Điều này sẽ phá vỡ nếu những chèn đó có dòng mới trong các giá trị. Sử dụng tốt hơn grep -v '^CREATE'như được đề xuất trong một trong những câu trả lời khác
dequis

1
việc sử dụng grep -v '^CREATE;sẽ phá vỡ nếu các CREATEcâu lệnh có ngắt dòng trong đó (đôi khi chúng làm). Tốt nhất, IMO, không phải là tự động loại bỏ các CREATEtuyên bố, mà là chỉnh sửa chúng theo cách thủ công. Chỉ cần sử dụng bất kỳ trình soạn thảo văn bản nào bạn cần, tìm kiếm CREATEvà xóa thủ công các câu lệnh đó. Miễn là cơ sở dữ liệu không lớn (và vì bạn đang sử dụng sqlite, tôi đoán đó là ghi chú), nên việc này khá đơn giản.
Dan Jones

nhưng grep của tạo cũng sẽ lấy tạo từ các khung nhìn. Làm thế nào tôi có thể loại bỏ điều đó?
Silve2611

35

Bạn có thể chỉ định một hoặc nhiều đối số bảng cho lệnh .dump đặc biệt, vd sqlite3 db ".dump 'table1' 'table2'".


4
Khi tôi thêm nhiều tên bảng như bạn đã đề cập, nó mang lại cho tôi đầu ra này: Cách sử dụng: .dump? - reserved-rowids? ? THÍCH-THỰC SỰ?
mwm

1
@mwm Tôi đang quan sát vấn đề tương tự trong sqlite3 3.31.1 (2020/01/27). Các thay đổi không nói gì về điều đó. (Nhân tiện, --preserve-rowidsnó hoạt động nhưng hoàn toàn không được ghi lại.)
ynn

11

Bất kỳ câu trả lời nào đề xuất sử dụng grep để loại trừ các CREATEdòng hoặc chỉ lấy các INSERTdòng từ sqlite3 $DB .dumpđầu ra sẽ thất bại nặng nề. Các CREATE TABLElệnh liệt kê một cột trên mỗi dòng (vì vậy loại trừ CREATEsẽ không nhận được tất cả của nó) và các giá trị trên các INSERTdòng có thể có dòng mới được nhúng (vì vậy bạn không thể lấy chỉ các INSERTdòng).

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

Đã thử nghiệm trên phiên bản sqlite3 3.6.20.

Nếu bạn muốn loại trừ các bảng nhất định, bạn có thể lọc chúng $(sqlite $DB .tables | grep -v -e one -e two -e three)hoặc nếu bạn muốn có một tập hợp con cụ thể thay thế bằng one two three.


9

Để cải thiện câu trả lời của Paul Egan, điều này có thể được thực hiện như sau:

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

--hoặc là--

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

Tất nhiên, hãy cẩn thận là bạn phải cài đặt grep.


1
Tôi thích cái này. Là một phần thưởng bổ sung, nó vẫn hoạt động nếu bạn có một tệp SQL bị bỏ đi, chỉ cat database.sql | grep '^INSERT' > database_inserts.sql(tương tự cho lược đồ, thay thế bằnggrep '^CREATE'
trisweb

2
@trisweb, tất nhiên ý bạn là grep '^INSERT' < database.sql > database_inserts.sqlđiều đó catkhông cần thiết
Sebastian

1
Không có gì thừa thãi về nó. Các catchi phí về cơ bản không có gì để thực hiện và làm cho chuỗi đầu vào để đầu ra rõ ràng hơn nhiều. Tất nhiên, bạn cũng có thể viết < database.sql grep '^INSERT' ...nhưng một ống rõ ràng dễ đọc hơn nhiều.
rjh

1
Khi tôi thêm nhiều tên bảng như bạn đã đề cập, nó mang lại cho tôi đầu ra này: Cách sử dụng: .dump? - reserved-rowids? ? THÍCH-THỰC SỰ?
mwm

-1: Tìm kiếm các dòng với CREATE là một ý tưởng vô ích. Hầu như mọi chế độ xem hoặc kích hoạt đặc biệt, nếu nó chứa các bình luận, yêu cầu nhiều hơn một dòng.
ceving

6

Trong Python hoặc Java hoặc bất kỳ ngôn ngữ cấp cao nào, .dump không hoạt động. Chúng tôi cần mã hóa chuyển đổi sang CSV bằng tay. Tôi đưa ra một ví dụ về Python. Những người khác, ví dụ sẽ được đánh giá cao:

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

Nếu bạn có 'dữ liệu bảng điều khiển, nói cách khác, nhiều mục riêng lẻ có id sẽ thêm dữ liệu này vào giao diện và nó cũng bỏ các thống kê tóm tắt:

        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

Theo tài liệu SQLite cho Command Line Shell cho SQLite, bạn có thể xuất bảng SQLite (hoặc một phần của bảng) dưới dạng CSV, chỉ cần đặt "chế độ" thành "csv" và sau đó chạy truy vấn để trích xuất các hàng mong muốn của cái bàn:

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

Sau đó, sử dụng lệnh ".import" để nhập dữ liệu CSV (giá trị được phân tách bằng dấu phẩy) vào bảng SQLite:

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

Vui lòng đọc tài liệu hướng dẫn thêm về hai trường hợp cần xem xét: (1) Bảng "tab1" không tồn tại trước đó và (2) bảng "tab1" đã tồn tại.


3

Phương pháp tốt nhất sẽ là lấy mã mà kết xuất db sqlite3 sẽ làm, ngoại trừ các phần lược đồ.

Mã giả ví dụ:

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

Xem: src/shell.c:838 (cho sqlite-3.5.9) cho mã thực tế

Bạn thậm chí có thể lấy vỏ đó và nhận xét các phần lược đồ và sử dụng nó.


3

Xem xét các giải pháp có thể khác

Chỉ bao gồm CHỨNG MINH

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

Dễ thực hiện nhưng sẽ thất bại nếu bất kỳ cột nào của bạn bao gồm các dòng mới

Chế độ chèn SQLite

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

Đây là một giải pháp tốt và có thể tùy chỉnh, nhưng nó không hoạt động nếu các cột của bạn có các đối tượng blob như kiểu 'Hình học' trong không gian

Diff kết xuất với lược đồ

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

Không chắc tại sao, nhưng không làm việc cho tôi

Một giải pháp khả thi (mới) khác

Có lẽ không có câu trả lời hay nhất cho câu hỏi này, nhưng câu trả lời phù hợp với tôi là grep các phần chèn có tính đến các dòng mới trong các giá trị cột với biểu thức như thế này

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

Để chọn các bảng, kết xuất sẽ .dumpthừa nhận một đối số THÍCH để khớp với các tên bảng, nhưng nếu điều này là không đủ có lẽ một kịch bản đơn giản là tùy chọn tốt hơ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

hoặc, một cái gì đó được xây dựng để tôn trọng các khóa ngoại và đóng gói tất cả các kết xuất chỉ trong một giao dịch

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

Hãy xem xét rằng biểu thức grep sẽ thất bại nếu );là một chuỗi có trong bất kỳ cột nào

Để khôi phục nó (trong cơ sở dữ liệu với các bảng đã được tạo)

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

2

Phiên bản này hoạt động tốt với các dòng mới bên trong chèn:

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

Trong thực tế loại trừ tất cả các dòng bắt đầu CREATEmà ít có khả năng chứa các dòng mới


0

Câu trả lời của retracile phải là câu trả lời gần nhất, nhưng nó không hoạt động đối với trường hợp của tôi. Một truy vấn chèn vừa bị hỏng ở giữa và quá trình xuất chỉ dừng lại. Không chắc lý do là gì. Tuy nhiên nó hoạt động tốt trong thời gian .dump.

Cuối cùng tôi đã viết một công cụ để phân tách SQL được tạo từ .dump:

https://github.com/othersapp/sqlite_sql_parser/


-3

Bạn có thể thực hiện chọn trên các bảng chèn dấu phẩy sau mỗi trường để tạo csv hoặc sử dụng công cụ GUI để trả về tất cả dữ liệu và lưu nó vào csv.


2
Ý định của tôi là tạo ra một tệp SQL có thể dễ dàng thêm lại vào DB.
Pupeno
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.