แปลงไฟล์ดัมพ์ SQLITE SQL เป็น POSTGRESQL


97

ฉันได้ทำการพัฒนาโดยใช้ฐานข้อมูล SQLITE พร้อมการผลิตใน POSTGRESQL ฉันเพิ่งอัปเดตฐานข้อมูลในเครื่องของฉันด้วยข้อมูลจำนวนมากและจำเป็นต้องโอนตารางเฉพาะไปยังฐานข้อมูลการผลิต

จากการรันsqlite database .dump > /the/path/to/sqlite-dumpfile.sqlSQLITE จะแสดงผลลัพธ์ตารางดัมพ์ในรูปแบบต่อไปนี้:

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;

ฉันจะแปลงข้างต้นเป็นไฟล์ดัมพ์ที่เข้ากันได้กับ POSTGRESQL ที่ฉันสามารถนำเข้าสู่เซิร์ฟเวอร์การผลิตของฉันได้อย่างไร


1
คำสั่งนั้นใช้ไม่ได้สำหรับฉันจนกว่าฉันจะเปลี่ยนsqliteเป็นsqlite3
Celal Ergün

คำตอบ:


103

คุณควรจะฟีดไฟล์ดัมพ์นั้นตรงไปที่psql:

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

หากคุณต้องการให้idคอลัมน์เป็น "การเพิ่มอัตโนมัติ" ให้เปลี่ยนประเภทจาก "int" เป็น "อนุกรม" ในบรรทัดการสร้างตาราง จากนั้น PostgreSQL จะแนบลำดับไปยังคอลัมน์นั้นเพื่อให้ INSERTs ที่มี NULL ids ได้รับการกำหนดค่าที่พร้อมใช้งานถัดไปโดยอัตโนมัติ PostgreSQL จะไม่รู้จักAUTOINCREMENTคำสั่งดังนั้นจึงจำเป็นต้องลบออก

คุณจะต้องตรวจสอบdatetimeคอลัมน์ในสคีมา SQLite และเปลี่ยนเป็นtimestampสำหรับ PostgreSQL (ขอบคุณClay ที่ชี้ให้เห็นสิ่งนี้)

หากคุณมีบูลีนใน SQLite ของคุณคุณสามารถแปลง1และ0เป็น1::booleanและ0::boolean(ตามลำดับ) หรือคุณสามารถเปลี่ยนคอลัมน์บูลีนเป็นจำนวนเต็มในส่วนสคีมาของดัมพ์จากนั้นแก้ไขด้วยมือภายใน PostgreSQL หลังจากการนำเข้า

ถ้าคุณมี BLOBs ใน SQLite byteaของคุณแล้วคุณจะต้องการที่จะปรับสคีมากับการใช้งาน คุณอาจจะต้องผสมในบางสายเช่นกันdecode การเขียนเครื่องถ่ายเอกสาร Quick'n'dirty ในภาษาที่คุณชื่นชอบอาจจะง่ายกว่าการทำให้ SQL ยุ่งเหยิงหากคุณมี BLOB จำนวนมากที่ต้องจัดการ

ตามปกติหากคุณมีคีย์ต่างประเทศคุณอาจต้องการตรวจสอบset constraints all deferredเพื่อหลีกเลี่ยงปัญหาการแทรกการสั่งซื้อโดยวางคำสั่งไว้ในคู่ BEGIN / COMMIT

ขอบคุณNicolas Rileyสำหรับบันทึกบูลีนหยดและข้อ จำกัด

หากคุณมี`โค้ดของคุณซึ่งสร้างโดยไคลเอนต์ SQLite3 บางตัวคุณจำเป็นต้องลบออก

PostGRESQL ยังไม่รู้จักunsignedคอลัมน์ดังนั้นคุณอาจต้องการวางหรือเพิ่มข้อ จำกัด ที่กำหนดเองเช่นนี้:

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

ในขณะที่ SQLite เริ่มต้นค่า null เป็น''PostgreSQL กำหนดให้ตั้งค่าเป็นNULL.

ไวยากรณ์ในแฟ้มการถ่ายโอนข้อมูล SQLite ดูเหมือนจะเข้ากันได้ส่วนใหญ่กับ PostgreSQL เพื่อให้คุณสามารถแก้ไขเล็ก ๆ น้อย ๆ psqlและอาหารมัน การนำเข้าข้อมูลจำนวนมากผ่าน SQL INSERTs อาจใช้เวลาสักครู่ แต่จะได้ผล


4
ไม่คุณต้องการเก็บธุรกรรมไว้เพื่อหลีกเลี่ยงค่าใช้จ่ายบางส่วน
Peter Eisentraut

3
ใช้งานได้ดี ฉันจะทราบด้วยว่าหากคุณต้องการย้ายdatetimeคอลัมน์sqlite คุณต้องเปลี่ยนเป็นtimestampสำหรับ postgres
ดิน

4
ปัญหาอื่น ๆ อีกเล็กน้อยที่ฉันพบ: การเปลี่ยนBLOBเป็นBYTEA( stackoverflow.com/questions/3103242 ) การเปลี่ยน 0/1 สำหรับBOOLEANคอลัมน์เป็น '0' / '1' และการเลื่อนข้อ จำกัด ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED)
Nicholas Riley

1
@NicholasRiley: ขอบคุณสำหรับสิ่งนั้น ฉันยกสิ่งนี้ให้กับวิกิชุมชนเนื่องจากมันกลายเป็นความพยายามของกลุ่มแล้วยุติธรรมก็ยุติธรรม
สั้นเกินไป

2
คุณสามารถใช้ to_timestamp () ใน postgreSQL เพื่อแปลงการประทับเวลาเป็นการประทับเวลา progreSQL
r03

63

pgloader

ฉันเจอโพสต์นี้เมื่อค้นหาวิธีแปลงการถ่ายโอนข้อมูล SQLite เป็น PostgreSQL แม้ว่าโพสต์นี้จะมีคำตอบที่เป็นที่ยอมรับ (และเป็นสิ่งที่ดีที่ +1) แต่ฉันคิดว่าการเพิ่มสิ่งนี้เป็นสิ่งสำคัญ

ฉันเริ่มมองหาวิธีแก้ปัญหาที่นี่และตระหนักว่าฉันกำลังมองหาวิธีการอัตโนมัติมากขึ้น ฉันค้นหาเอกสารวิกิ:

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

pgloaderและค้นพบ แอปพลิเคชั่นที่ยอดเยี่ยมและค่อนข้างใช้งานง่าย คุณสามารถแปลงไฟล์ SQLite แบบแบนเป็นฐานข้อมูล PostgreSQL ที่ใช้งานได้ ฉันติดตั้งจาก*.debและสร้างcommandไฟล์เช่นนี้ในไดเร็กทอรีทดสอบ:

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';

เช่นสถานะเอกสาร จากนั้นฉันสร้างtestdbด้วยcreatedb:

createdb testdb

ฉันรันpgloaderคำสั่งดังนี้:

pgloader command

จากนั้นเชื่อมต่อกับฐานข้อมูลใหม่:

psql testdb

หลังจากมีการสอบถามเพื่อตรวจสอบข้อมูลปรากฏว่าได้ผลดีทีเดียว ฉันรู้ว่าถ้าฉันพยายามเรียกใช้สคริปต์เหล่านี้หรือทำการแปลงแบบขั้นตอนที่กล่าวถึงในที่นี้ฉันจะต้องใช้เวลามากขึ้น

เพื่อพิสูจน์แนวคิดฉันทิ้งสิ่งนี้testdbและนำเข้าสู่สภาพแวดล้อมการพัฒนาบนเซิร์ฟเวอร์ที่ใช้งานจริงและข้อมูลที่ถ่ายโอนไปอย่างสวยงาม


2
ระวังว่าการแจกจ่าย Ubuntu (ยังคงรองรับ) อาจมีเวอร์ชันที่ล้าสมัย - v2.xy เลิกใช้งานแล้วและใช้งานไม่ได้จริง v3.2.x อาจใช้งานได้ แต่แนะนำให้ใช้ v3.2.3 ฉันดึง v3.2.3 จากขอบเลือดออกและติดตั้งด้วยsudo dpkg -i <ชื่อไฟล์. deb>มันไม่มีปัญหากับการอ้างอิง
silpol

ฉันเห็นด้วยกับ @silpol - อย่าลืมดาวน์โหลดเวอร์ชันเสถียรล่าสุดและติดตั้งโดยใช้ตัวจัดการแพ็คเกจที่คุณชอบ สำหรับไฟล์ "command" นี่เป็นเพียงไฟล์ข้อความที่เรียกว่า "command" โดยไม่มีชื่อนามสกุล (เช่นไม่จำเป็นต้องมี. txt ต่อท้ายชื่อไฟล์) คุณไม่จำเป็นต้องใส่ชื่อไฟล์ในวงเล็บเหลี่ยม ฉันต้องเปลี่ยน search_parth ของฐานข้อมูล psql เพื่อดูข้อมูลของฉัน pgloader ทำงานได้ดีและช่วยฉันไม่ให้ยุ่งยาก
BKSpurgeon

นี่ช่วยวันของฉัน
Yakob Ubaidi

1
ใช่ฉันรู้สึกลำบากเมื่อพบปัญหานี้และเครื่องมือนั้นทำให้มันง่ายมาก ... บางครั้งสิ่งต่าง ๆ ก็ออกมาดีใช่ไหม
nicorellius

ขอบคุณครับ ฉันเห็นว่าคำตอบนี้คุ้มค่าที่จะเป็นคำตอบที่ยอมรับ! เครื่องมือที่ดีมาก
mohamed_18

16

ผมเขียนสคริปต์จะทำอย่างไรที่sqlite3จะpostgresย้ายถิ่น ไม่ได้จัดการการแปลสคีมา / ข้อมูลทั้งหมดที่กล่าวถึงในhttps://stackoverflow.com/a/4581921/1303625แต่ทำในสิ่งที่ฉันต้องการให้ทำ หวังว่าจะเป็นจุดเริ่มต้นที่ดีสำหรับคนอื่น ๆ

https://gist.github.com/2253099


2
ใช้งานได้ดี! ฉันได้แยก Gist และเพิ่มข้อมูลเชิงลึกบางส่วนเป็นความคิดเห็น: gist.github.com/bittner/7368128
Peterino

14

อัญมณีสืบเนื่อง (ห้องสมุดทับทิม) มีการคัดลอกข้อมูลไปยังฐานข้อมูลที่แตกต่างกัน: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

gem install sequelก่อนติดตั้งทับทิมอัญมณีแล้วติดตั้งโดยใช้

ในกรณีของ sqlite จะเป็นดังนี้: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db


1
ทางออกที่ยอดเยี่ยม pgloaderง่ายกว่าการเล่นซอรอบกับ
michaeldever

แน่นอนว่า pgloader ยุ่งเหยิง GC ดูเหมือนจะขัดข้องในฐานข้อมูลขนาดใหญ่: github.com/dimitri/pgloader/issues/962
hasufell

อย่าลังเลที่จะโพสต์คำตอบของคุณที่stackoverflow.com/questions/6148421/…ที่ฉันคัดลอกคำตอบของคุณ จากนั้น ping ฉันและฉันจะเพิกถอนคำตอบของฉันหากคุณต้องการตัวแทนสำหรับมัน
Felix

@Felix ขอบคุณ! คุณสามารถรับเครดิต คุณสามารถสลับลำดับการอ้างอิง DB รอบ ๆ ได้ไหม (เนื่องจากต้องการ PG เป็น SQLite) โอ้และเพิ่ม "la" อีกหนึ่งรายการให้กับ id ของฉัน คำตอบอาจมีประโยชน์น้อยกว่าแม้ว่าจะต้องติดตั้ง PG บนเครื่อง dev และเมื่อถึงจุดนั้นพวกเขาก็ใช้ PG ในการพัฒนา
lulalala

@lulalala ขอบคุณ ทำอย่างนั้น แต่เกี่ยวกับเหตุผลฉันไม่เห็นด้วย พวกเขาสามารถเช่นแปลง db บนเครื่อง linux แล้วคัดลอกไปยังเครื่อง dev (เป็นไฟล์ sqlite db) แต่อย่างไรก็ตามโดยรวมแล้วมันเป็นความคิดที่ไม่ดี :) แต่ภาคต่อช่วยชีวิตฉันไว้ที่นี่ในสถานการณ์ที่น่ารังเกียจ
เฟลิกซ์

7

คุณสามารถใช้ซับเดียวนี่คือตัวอย่างด้วยความช่วยเหลือของคำสั่ง 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 

ไม่มีการแทนที่สำหรับประเภท LONG เช่น
yetanothercoder

1
สามารถเพิ่มได้อีกหนึ่งรายการsed -e 's/DATETIME/TIMESTAMP/g'
silpol

sed -e 's/TINYINT(1)/SMALLINT/g' - และสำหรับการเปรียบเทียบข้อมูลทุกประเภทโปรดดูstackoverflow.com/questions/1942586/…
Purplejacket

ฉันยังมีปัญหากับ SMALLINT ที่เริ่มต้นเป็น 't' หรือ 'f' ใน sqlite เห็นได้ชัดว่าเป็นบูลีน แต่ไม่คุ้นเคยกับระบบ db อย่างใดอย่างหนึ่งมากพอที่จะแนะนำการแก้ไขที่ปลอดภัย
เขาวงกต

1
แทนที่' | sed -e 'ด้วย; :)
AstraSerg

0

ฉันได้ลองแก้ไข / regexping การถ่ายโอนข้อมูล sqlite เพื่อให้ PostgreSQL ยอมรับมันน่าเบื่อและมีแนวโน้มที่จะเกิดข้อผิดพลาด

สิ่งที่ฉันต้องทำงานเร็วมาก:

ก่อนอื่นให้สร้างสคีมาใหม่บน PostgreSQL โดยไม่มีข้อมูลใด ๆ ไม่ว่าจะแก้ไขดัมพ์หรือถ้าคุณใช้ ORM คุณอาจโชคดีและมันพูดถึงแบ็คเอนด์ทั้งสอง (sqlalchemy, peewee, ... )

จากนั้นย้ายข้อมูลโดยใช้แพนด้า สมมติว่าคุณมีตารางที่มีฟิลด์บูล (ซึ่งเป็น 0/1 ใน sqlite แต่ต้องเป็น t / f ใน 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)

สิ่งนี้ใช้งานได้อย่างมีเสน่ห์คือง่ายต่อการเขียนอ่านและแก้ไขข้อบกพร่องแต่ละฟังก์ชันซึ่งแตกต่างจากนิพจน์ทั่วไป (สำหรับฉัน)

ตอนนี้คุณสามารถลองโหลด csv ที่เป็นผลลัพธ์ด้วย PostgreSQL (แม้กระทั่งในรูปแบบกราฟิกด้วยเครื่องมือผู้ดูแลระบบ) โดยมีข้อแม้เดียวที่คุณต้องโหลดตารางด้วยคีย์ต่างประเทศหลังจากที่คุณโหลดตารางด้วยคีย์ต้นทางที่เกี่ยวข้อง ฉันไม่ได้มีกรณีของการพึ่งพาแบบวงกลมฉันเดาว่าคุณสามารถระงับการตรวจสอบคีย์ชั่วคราวได้หากเป็นเช่นนั้น


-2

pgloader ทำงานมหัศจรรย์ในการแปลงฐานข้อมูลใน sqlite เป็น postgresql

นี่คือตัวอย่างในการแปลง sqlitedb โลคัลเป็น PostgreSQL db ระยะไกล:

pgloader sqlite.db postgresql: // ชื่อผู้ใช้ : รหัสผ่าน @ ชื่อโฮสต์ / dbname


1
Pgloader เป็นรถที่แย่มากและไม่น่าเชื่อถือ มันขัดข้องทันทีด้วยข้อผิดพลาดKABOOM! Control stack exhausted (no more space for function call frames).
Cerin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.