Konwertuj plik zrzutu SQLITE SQL na POSTGRESQL

97

Zajmuję się programowaniem przy użyciu bazy danych SQLITE z produkcją w POSTGRESQL. Właśnie zaktualizowałem moją lokalną bazę danych o ogromną ilość danych i muszę przenieść konkretną tabelę do produkcyjnej bazy danych.

Bazując na uruchomieniu sqlite database .dump > /the/path/to/sqlite-dumpfile.sql, SQLITE generuje zrzut tabeli w następującym formacie:

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;

Jak przekonwertować powyższe na plik zrzutu zgodny z POSTGRESQL, który mogę zaimportować na mój serwer produkcyjny?

DevX
źródło
1
Cóż, to polecenie nie zadziałało, dopóki nie zmieniłem sqlite na sqlite3
Celal Ergün

Odpowiedzi:

103

Powinieneś być w stanie przesłać ten plik zrzutu bezpośrednio do psql:

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

Jeśli chcesz, aby idkolumna była „automatycznie zwiększana”, zmień jej typ z „int” na „serial” w linii tworzenia tabeli. PostgreSQL dołączy wtedy sekwencję do tej kolumny, tak aby wstawkom INSERT z identyfikatorami NULL automatycznie przypisywana była następna dostępna wartość. PostgreSQL również nie rozpoznaje AUTOINCREMENTpoleceń, więc należy je usunąć.

Będziesz także chciał sprawdzić datetimekolumny w schemacie SQLite i zmienić je timestampna PostgreSQL. (Dzięki Clayowi za wskazanie tego).

Jeśli masz wartości logiczne w swoim SQLite, możesz przekonwertować 1i 0na 1::booleani 0::boolean(odpowiednio) lub możesz zmienić kolumnę boolowską na liczbę całkowitą w sekcji schematu zrzutu, a następnie naprawić je ręcznie w PostgreSQL po imporcie.

Jeśli masz obiekty BLOB w swoim SQLite, będziesz chciał dostosować schemat do użycia bytea. Prawdopodobnie będziesz musiał również włączyć się do niektórych decoderozmów . Napisanie szybkiej i brudnej kserokopiarki w swoim ulubionym języku może być łatwiejsze niż manipulowanie kodem SQL, jeśli jednak masz do czynienia z wieloma BLOBami.

Jak zwykle, jeśli masz klucze obce, prawdopodobnie będziesz chciał zajrzeć, set constraints all deferredaby uniknąć problemów z kolejnością wstawiania, umieszczając polecenie wewnątrz pary BEGIN / COMMIT.

Podziękowania dla Nicolasa Rileya za notatki logiczne, blob i ograniczenia.

Jeśli masz `na swoim kodzie wygenerowanym przez niektórych klientów SQLite3, musisz je usunąć.

PostGRESQL również nie rozpoznaje unsignedkolumn, więc możesz to porzucić lub dodać niestandardowe ograniczenie, takie jak to:

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

Podczas gdy SQLite domyślnie przyjmuje wartości null na '', PostgreSQL wymaga, aby były ustawione jako NULL.

Składnia w pliku zrzutu SQLite wydaje się być w większości zgodna z PostgreSQL, więc możesz załatać kilka rzeczy i przekazać je psql. Importowanie dużej ilości danych przez SQL INSERT może zająć trochę czasu, ale zadziała.

mu jest za krótkie
źródło
4
Nie, chcesz zachować transakcję, aby uniknąć pewnych kosztów ogólnych.
Peter Eisentraut,
3
To działa świetnie. Chciałbym również zauważyć, że jeśli chcesz migrować datetimekolumny sqlite , musisz je zmienić timestampna postgres.
Clay
4
Kilka innych problemów, które napotkałem: zmiana BLOBna BYTEA( stackoverflow.com/questions/3103242 ), zmiana 0/1 dla BOOLEANkolumn na „0” / „1” i odroczenie ograniczeń ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED).
Nicholas Riley
1
@NicholasRiley: Dzięki za to. Zrezygnowałem z wiki społeczności, ponieważ stało się to wysiłkiem grupowym, sprawiedliwe jest sprawiedliwe.
mu jest za krótkie
2
Możesz użyć to_timestamp () w postgreSQL, aby przekonwertować znacznik czasu na znacznik czasu
progreSQL
63

pgloader

Natknąłem się na ten post, szukając sposobu na przekonwertowanie zrzutu SQLite na PostgreSQL. Mimo że ten post ma akceptowaną odpowiedź (i dobrą przy tym +1), myślę, że dodanie tego jest ważne.

Zacząłem szukać rozwiązań tutaj i zdałem sobie sprawę, że szukam bardziej zautomatyzowanej metody. Sprawdziłem dokumenty wiki:

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

i odkrył pgloader. Całkiem fajna aplikacja i jest stosunkowo łatwa w użyciu. Możesz przekonwertować płaski plik SQLite na użyteczną bazę danych PostgreSQL. Zainstalowałem z *.debi utworzyłem taki commandplik w katalogu testowym:

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

jak w przypadku dokumentów . Następnie utworzyłem testdbz createdb:

createdb testdb

Uruchomiłem pgloaderpolecenie w ten sposób:

pgloader command

a następnie połączony z nową bazą danych:

psql testdb

Po kilku zapytaniach w celu sprawdzenia danych wygląda na to, że działało całkiem dobrze. Wiem, że gdybym próbował uruchomić jeden z tych skryptów lub wykonać wspomnianą tutaj konwersję krokową, spędziłbym znacznie więcej czasu.

Aby udowodnić tę koncepcję, porzuciłem to testdbi zaimportowałem do środowiska programistycznego na serwerze produkcyjnym, a dane zostały ładnie przesłane.

nicorellius
źródło
2
Uważaj, (nadal obsługiwane) dystrybucje Ubuntu mogą mieć przestarzałą wersję - v2.xy są już przestarzałe i nie działają. Wersja 3.2.x może działać, ale zalecana jest wersja 3.2.3. Pobrałem wersję 3.2.3 z bleeding edge i zainstalowałem z sudo dpkg -i <nazwa pliku .deb> , nie miałem problemu z zależnościami.
silpol
Zgadzam się z @silpol - pamiętaj, aby pobrać najnowszą stabilną wersję i zainstalować za pomocą ulubionego menedżera pakietów; w przypadku pliku „polecenia” jest to tylko plik tekstowy o nazwie „polecenie” bez nazwy rozszerzenia (tj. nie ma potrzeby umieszczania .txt na końcu nazwy pliku), nie trzeba umieszczać nazwy pliku w nawiasach kątowych; musiałem zmienić search_parth w bazie danych psql, aby zobaczyć moje dane; pgloader działa dobrze i zaoszczędził mi wielu kłopotów
BKSpurgeon
to ocal mój dzień.
Yakob Ubaidi
1
Tak, walczyłem, kiedy napotkałem ten problem, a to narzędzie bardzo mi to ułatwiło… Czasami wszystko po prostu dobrze się układa, prawda?
nicorellius
Dzięki stary. Widzę, że ta odpowiedź jest warta zaakceptowania! bardzo dobre narzędzie.
mohamed_18
14

Gem sequel (biblioteka Ruby) oferuje Kopiowanie danych między różnymi bazami danych: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

Najpierw zainstaluj Rubiego, a następnie zainstaluj gem, uruchamiając gem install sequel.

W przypadku sqlite wyglądałoby to tak: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db

lulalala
źródło
1
Niesamowite rozwiązanie. O wiele łatwiejsze niż majsterkowanie pgloader.
michaeldever
Oczywiście pgloader jest niechlujny, GC wydaje się zawieszać w ogromnych bazach danych: github.com/dimitri/pgloader/issues/962
hasufell
Nie krępuj się opublikować swoją odpowiedź na stackoverflow.com/questions/6148421/, gdzie skopiowałem twoją odpowiedź. Następnie pinguj mnie, a cofnę moją odpowiedź, jeśli chcesz powtórzyć za nią.
Felix
@Felix thanks! Możesz wziąć kredyt. Czy mógłbyś zamienić kolejność odwołań do bazy danych (ponieważ chce PG do SQLite), och i dodać jeszcze jedno „la” do mojego identyfikatora. Odpowiedź może być również mniej pomocna, ponieważ wymaga zainstalowania PG na maszynie deweloperskiej, a wtedy po prostu używają PG do programowania.
lulalala
@lulalala Thanks. Zrobił to. Ale nie zgadzam się z uzasadnieniem. Mogą np. Przekonwertować bazę danych na komputerze z systemem Linux, a następnie skopiować ją na maszynę deweloperską (jako plik sqlite db). Ale w sumie to zły pomysł :) Ale sequel uratował mi tyłek w paskudnej sytuacji.
Felix
7

Możesz użyć one linera, oto przykład z pomocą polecenia 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 
develCuy
źródło
nie ma zamiennika dla typu LONG, np.
yetanothercoder.
1
można dodać jeszcze jedną pozycjęsed -e 's/DATETIME/TIMESTAMP/g'
silpol
sed -e 's/TINYINT(1)/SMALLINT/g' - a dla porównania wszystkich typów danych zobacz stackoverflow.com/questions/1942586/…
Purplejacket
Miałem również problem z SMALLINT, który domyślnie ustawiał „t” lub „f” w sqlite. Oczywiście logiczna, ale nie na tyle zaznajomiona z żadnym z systemów db, aby zalecić bezpieczną poprawkę.
labirynt
1
Wymień ' | sed -e 'się ; :)
AstraSerg
0

Próbowałem edytować / regexping zrzutu sqlite, więc PostgreSQL je akceptuje, jest to żmudne i podatne na błędy.

Co mam do pracy naprawdę szybko:

Najpierw odtwórz schemat na PostgreSQL bez żadnych danych, edytując zrzut lub jeśli używasz ORM, możesz mieć szczęście i komunikuje się z obydwoma back-endami (sqlalchemy, peewee, ...).

Następnie przeprowadź migrację danych za pomocą pand. Załóżmy, że masz tabelę z polem bool (które ma wartość 0/1 w sqlite, ale musi być t / f w 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)

To działa jak urok, jest łatwe do napisania, odczytania i debugowania każdej funkcji, w przeciwieństwie do (dla mnie) wyrażeń regularnych.

Teraz możesz spróbować załadować wynikowy plik csv za pomocą PostgreSQL (nawet graficznie za pomocą narzędzia administratora), z jedynym zastrzeżeniem, że musisz załadować tabele kluczami obcymi po załadowaniu tabel z odpowiednimi kluczami źródłowymi. Nie miałem przypadku zależności cyklicznej, myślę, że można chwilowo zawiesić klucz sprawdzając, czy tak jest.

agomcas
źródło
-2

pgloader działa cuda podczas konwersji bazy danych w sqlite do postgresql.

Oto przykład konwersji lokalnej sqlitedb na zdalną bazę danych PostgreSQL:

pgloader sqlite.db PostgreSQL: // nazwa_użytkownika : hasło @ nazwa hosta / nazwa_bd

kouichi
źródło
1
Pgloader jest strasznie wadliwy i zawodny. Natychmiast ulega awarii z błędemKABOOM! Control stack exhausted (no more space for function call frames).
Cerin