Chuyển đổi tệp kết xuất SQLITE SQL sang POSTGRESQL


96

Tôi đã phát triển bằng cách sử dụng cơ sở dữ liệu SQLITE với quá trình sản xuất trong POSTGRESQL. Tôi vừa cập nhật cơ sở dữ liệu cục bộ của mình với một lượng lớn dữ liệu và cần chuyển một bảng cụ thể sang cơ sở dữ liệu sản xuất.

Dựa trên việc chạy sqlite database .dump > /the/path/to/sqlite-dumpfile.sql, SQLITE xuất ra kết xuất bảng ở định dạng sau:

BEGIN TRANSACTION;
CREATE TABLE "courses_school" ("id" integer PRIMARY KEY, "department_count" integer NOT NULL DEFAULT 0, "the_id" integer UNIQUE, "school_name" varchar(150), "slug" varchar(50));
INSERT INTO "courses_school" VALUES(1,168,213,'TEST Name A',NULL);
INSERT INTO "courses_school" VALUES(2,0,656,'TEST Name B',NULL);
....
COMMIT;

Làm cách nào để chuyển đổi tệp ở trên thành tệp kết xuất tương thích POSTGRESQL mà tôi có thể nhập vào máy chủ sản xuất của mình?


1
Chà, lệnh đó không hoạt động với tôi cho đến khi tôi thay đổi sqlite thành sqlite3
Celal Ergün

Câu trả lời:


101

Bạn sẽ có thể nạp thẳng tệp kết xuất đó vào psql:

/path/to/psql -d database -U username -W < /the/path/to/sqlite-dumpfile.sql

Nếu bạn muốn idcột "tự động tăng" thì hãy thay đổi kiểu của nó từ "int" thành "serial" trong dòng tạo bảng. PostgreSQL sau đó sẽ đính kèm một chuỗi vào cột đó để các INSERT có id NULL sẽ được tự động gán giá trị có sẵn tiếp theo. PostgreSQL cũng sẽ không nhận dạng được AUTOINCREMENTcác lệnh, vì vậy chúng cần được loại bỏ.

Bạn cũng sẽ muốn kiểm tra datetimecác cột trong lược đồ SQLite và thay đổi chúng thành timestampcho PostgreSQL (cảm ơn Clay đã chỉ ra điều này).

Nếu bạn có boolean trong SQLite của mình thì bạn có thể chuyển đổi 101::boolean0::boolean(tương ứng) hoặc bạn có thể thay đổi cột boolean thành một số nguyên trong phần lược đồ của kết xuất và sau đó sửa chúng bằng tay bên trong PostgreSQL sau khi nhập.

Nếu bạn có BLOB trong SQLite của mình thì bạn sẽ muốn điều chỉnh lược đồ để sử dụng bytea. Bạn cũng có thể cần phải kết hợp một số decodecuộc gọi . Viết nhanh một máy photocopy không bẩn bằng ngôn ngữ yêu thích của bạn có thể dễ dàng hơn so với viết SQL nếu bạn phải xử lý nhiều BLOB.

Như thường lệ, nếu bạn có khóa ngoại thì có thể bạn sẽ muốn xem xét set constraints all deferredđể tránh các vấn đề chèn thứ tự, đặt lệnh bên trong cặp BEGIN / COMMIT.

Cảm ơn Nicolas Riley về các ghi chú boolean, blob và các ràng buộc.

Nếu bạn có `trên mã của mình, như được tạo bởi một số ứng dụng khách SQLite3, bạn cần xóa chúng.

PostGRESQL cũng không nhận dạng được unsignedcác cột, bạn có thể muốn loại bỏ cột đó hoặc thêm một ràng buộc tùy chỉnh như sau:

CREATE TABLE tablename (
    ...
    unsigned_column_name integer CHECK (unsigned_column_name > 0)
);

Trong khi SQLite mặc định các giá trị null thành '', PostgreSQL yêu cầu chúng phải được đặt thành NULL.

Cú pháp trong tệp kết xuất SQLite dường như hầu hết tương thích với PostgreSQL, do đó bạn có thể vá một số thứ và cung cấp cho nó psql. Việc nhập một đống dữ liệu lớn thông qua SQL INSERT có thể mất một lúc nhưng nó sẽ hoạt động.


4
Không, bạn muốn giữ giao dịch để tránh một số chi phí.
Peter Eisentraut

3
Điều này hoạt động tuyệt vời. Tôi cũng lưu ý rằng nếu bạn cần di chuyển datetimecác cột sqlite , bạn phải thay đổi chúng thành timestampcho các cột postgres.
Clay

4
Một số vấn đề khác mà tôi gặp phải: thay đổi BLOBthành BYTEA( stackoverflow.com/questions/3103242 ), thay đổi 0/1 cho BOOLEANcác cột thành '0' / '1' và trì hoãn các ràng buộc ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED).
Nicholas Riley

1
@NicholasRiley: Cảm ơn vì điều đó. Tôi đã đưa nó cho một wiki cộng đồng vì nó đã trở thành một nỗ lực của nhóm, công bằng là công bằng.
mu quá ngắn

2
Bạn có thể sử dụng to_timestamp () trong postgreSQL để chuyển đổi dấu thời gian thành dấu thời gian progreSQL
r03 23/03

61

pgloader

Tôi đã xem qua bài đăng này khi tìm kiếm cách chuyển đổi kết xuất SQLite thành PostgreSQL. Mặc dù bài đăng này có một câu trả lời được chấp nhận (và một câu trả lời tốt ở lượt +1 đó), tôi nghĩ rằng việc thêm điều này là quan trọng.

Tôi bắt đầu xem xét các giải pháp ở đây và nhận ra rằng tôi đang tìm kiếm một phương pháp tự động hơn. Tôi đã tra cứu tài liệu wiki:

https://wiki.postgresql.org/wiki/Converting_from_other_Databases_to_PostgreSQL

và được phát hiện pgloader. Ứng dụng khá hay và tương đối dễ sử dụng. Bạn có thể chuyển đổi tệp SQLite phẳng thành cơ sở dữ liệu PostgreSQL có thể sử dụng được. Tôi đã cài đặt *.debvà tạo một commandtệp như thế này trong thư mục thử nghiệm:

load database  
    from 'db.sqlite3'  
    into postgresql:///testdb 
       
with include drop, create tables, create indexes, reset sequences  
         
set work_mem to '16MB', maintenance_work_mem to '512 MB';

như trạng thái tài liệu . Sau đó, tôi đã tạo một testdbvới createdb:

createdb testdb

Tôi đã chạy pgloaderlệnh như sau:

pgloader command

và sau đó kết nối với cơ sở dữ liệu mới:

psql testdb

Sau một số truy vấn để kiểm tra dữ liệu, có vẻ như nó hoạt động khá tốt. Tôi biết nếu tôi đã cố gắng chạy một trong những tập lệnh này hoặc thực hiện chuyển đổi từng bước được đề cập ở đây, tôi sẽ mất nhiều thời gian hơn.

Để chứng minh khái niệm này, tôi đã loại bỏ điều này testdbvà nhập vào môi trường phát triển trên máy chủ sản xuất và dữ liệu được chuyển qua một cách độc đáo.


2
Lưu ý rằng các bản phân phối Ubuntu (vẫn được hỗ trợ) có thể có phiên bản lỗi thời - v2.xy đã không còn được dùng nữa và không thực sự hoạt động. v3.2.x có thể hoạt động nhưng v3.2.3 được khuyến nghị. Tôi đã tìm nạp v3.2.3 từ mép chảy máu và cài đặt bằng sudo dpkg -i <tên tệp .deb> , nó không có vấn đề gì với các phụ thuộc.
silpol

Tôi đồng tình với @silpol - hãy nhớ tải xuống bản phát hành ổn định mới nhất và cài đặt bằng trình quản lý gói yêu thích của bạn; đối với tệp "lệnh" đây chỉ là tệp văn bản được gọi là "lệnh" không có tên mở rộng (nghĩa là không cần .txt ở cuối tên tệp) bạn không cần đặt tên tệp trong dấu ngoặc nhọn; tôi đã phải thay đổi search_parth của cơ sở dữ liệu psql để xem dữ liệu của mình; pgloader hoạt động tốt và lưu lại cho tôi rất nhiều rắc rối
BKSpurgeon

điều này tiết kiệm ngày của tôi.
Yakob Ubaidi

1
Vâng, tôi đã rất vất vả khi gặp phải vấn đề này, và công cụ đó đã làm cho nó trở nên thật dễ dàng ... Đôi khi mọi thứ diễn ra tốt đẹp, phải không?
nicorellius

Cảm ơn nhé người anh em. Tôi thấy câu trả lời này đáng để trở thành câu trả lời được chấp nhận! công cụ rất tốt.
mohamed_18,

16

Tôi đã viết một kịch bản để thực hiện sqlite3để postgresdi cư. Nó không xử lý tất cả các bản dịch lược đồ / dữ liệu được đề cập trong https://stackoverflow.com/a/4581921/1303625 , nhưng nó thực hiện những gì tôi cần. Hy vọng rằng nó sẽ là một điểm khởi đầu tốt cho những người khác.

https://gist.github.com/2253099


2
Điều này hoạt động tốt! Tôi đã phân nhánh Gist và thêm một số thông tin chi tiết dưới dạng nhận xét: gist.github.com/bittner/7368128
Peterino,

12

Phần tiếp theo gem (một thư viện Ruby) cung cấp sao chép dữ liệu trên các cơ sở dữ liệu khác nhau: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

Đầu tiên cài đặt Ruby, sau đó cài đặt đá quý bằng cách chạy gem install sequel.

Trong trường hợp sqlite, nó sẽ như thế này: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db


1
Giải pháp tuyệt vời. Dễ dàng hơn nhiều so với việc tìm kiếm xung quanh pgloader.
michaeldever

Hoàn toàn có thể, pgloader rất lộn xộn, GC dường như gặp sự cố trên cơ sở dữ liệu khổng lồ: github.com/dimitri/pgloader/issues/962
hasufell

7

Bạn có thể sử dụng một lớp lót, đây là một ví dụ với sự trợ giúp của lệnh sed:

sqlite3 mjsqlite.db .dump | sed -e 's/INTEGER PRIMARY KEY AUTOINCREMENT/SERIAL PRIMARY KEY/' | sed -e 's/PRAGMA foreign_keys=OFF;//' | sed -e 's/unsigned big int/BIGINT/g' | sed -e 's/UNSIGNED BIG INT/BIGINT/g' | sed -e 's/BIG INT/BIGINT/g' | sed -e 's/UNSIGNED INT(10)/BIGINT/' | sed -e 's/BOOLEAN/SMALLINT/g' | sed -e 's/boolean/SMALLINT/g' | sed -e 's/UNSIGNED BIG INT/INTEGER/g' | sed -e 's/INT(3)/INT2/g' | sed -e 's/DATETIME/TIMESTAMP/g' | psql mypqdb mypguser 

không có thay thế cho loại DÀI, ví dụ
yeta anothercoder

1
có thể thêm một mục nữased -e 's/DATETIME/TIMESTAMP/g'
silpol

sed -e 's/TINYINT(1)/SMALLINT/g' - và để so sánh tất cả các loại dữ liệu, hãy xem stackoverflow.com/questions/1942586/…
Purplejacket

Tôi cũng gặp sự cố với SMALLINT được mặc định là 't' hoặc 'f' trong sqlite. Rõ ràng là một boolean, nhưng không đủ quen thuộc với cả hai hệ thống db để đề xuất một bản sửa lỗi an toàn.
mê cung

1
Thay thế ' | sed -e 'bằng ; :)
AstraSerg

0

Tôi đã thử chỉnh sửa / regexping bãi chứa sqlite để PostgreSQL chấp nhận nó, nó thật tẻ nhạt và dễ bị lỗi.

Những gì tôi phải làm việc thực sự nhanh chóng:

Đầu tiên, hãy tạo lại lược đồ trên PostgreSQL mà không có bất kỳ dữ liệu nào, có thể chỉnh sửa kết xuất hoặc nếu bạn đang sử dụng ORM, bạn có thể may mắn và nó nói chuyện với cả hai back-end (sqlalchemy, peewee, ...).

Sau đó, di chuyển dữ liệu bằng cách sử dụng gấu trúc. Giả sử bạn có một bảng với trường bool (là 0/1 trong sqlite, nhưng phải là t / f trong PostgreSQL)

def int_to_strbool(df, column):
    df = df.replace({column: 0}, 'f')
    df = df.replace({column: 1}, 't')
    return df

#def other_transform(df, column):
#...

conn = sqlite3.connect(db)
df = pd.read_sql(f'select * from {table_name}', conn)

df = int_to_strbool(df, bool_column_name)
#df = other_transform(df, other_column_name)

df.to_csv(table_name + '.csv'), sep=',', header=False, index=False)

Điều này hoạt động giống như một sự quyến rũ, dễ viết, đọc và gỡ lỗi từng hàm, không giống như (đối với tôi) các biểu thức chính quy.

Bây giờ bạn có thể thử tải csv kết quả bằng PostgreSQL (ngay cả bằng đồ họa với công cụ quản trị), với lưu ý duy nhất là bạn phải tải các bảng bằng khóa ngoại sau khi bạn đã tải các bảng bằng khóa nguồn tương ứng. Tôi không gặp trường hợp phụ thuộc vòng tròn, tôi đoán bạn có thể tạm dừng việc kiểm tra khóa nếu đúng như vậy.


-1

pgloader làm việc kỳ diệu trong việc chuyển đổi cơ sở dữ liệu trong sqlite sang postgresql.

Đây là một ví dụ về việc chuyển đổi một sqlitedb cục bộ thành một db PostgreSQL từ xa:

pgloader sqlite.db postgresql: // tên người dùng : password @ hostname / dbname


1
Pgloader rất nhiều lỗi và không đáng tin cậy. Nó ngay lập tức gặp lỗi với lỗiKABOOM! Control stack exhausted (no more space for function call frames).
Cerin
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.