Преобразование файла дампа 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, который я могу импортировать на свой рабочий сервер?

DevX
источник
1
Что ж, эта команда не работала для меня, пока я не изменил sqlite на sqlite3
Джелал Эргюн

Ответы:

103

Вы должны иметь возможность загрузить этот файл дампа прямо в psql:

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

Если вы хотите, чтобы idстолбец «увеличивался автоматически», измените его тип с «int» на «serial» в строке создания таблицы. PostgreSQL затем присоединит последовательность к этому столбцу, чтобы вставкам с NULL идентификаторами автоматически присваивалось следующее доступное значение. PostgreSQL также не распознает AUTOINCREMENTкоманды, поэтому их необходимо удалить.

Вы также захотите проверить наличие datetimeстолбцов в схеме SQLite и изменить их timestampна PostgreSQL. (Спасибо Клею за указание на это.)

Если у вас есть логические значения в вашем SQLite, вы можете преобразовать 1и 0в 1::booleanи 0::boolean(соответственно) или вы можете изменить логический столбец на целое число в разделе схемы дампа, а затем исправить их вручную внутри PostgreSQL после импорта.

Если у вас есть большие двоичные объекты в вашем SQLite, вы захотите настроить схему для использования bytea. Вероятно, вам также понадобится смешать несколько decodeвызовов . Написание быстрого и грязного копировального аппарата на вашем любимом языке может быть проще, чем переделывать SQL, если вам нужно иметь дело с большим количеством больших двоичных объектов.

Как обычно, если у вас есть внешние ключи, вы, вероятно, захотите изучить, set constraints all deferredчтобы избежать проблем с порядком вставки, поместив команду в пару BEGIN / COMMIT.

Спасибо Nicolas Riley за заметки о логических значениях, blob и ограничениях.

Если у вас есть `код, созданный некоторыми клиентами SQLite3, вам необходимо удалить их.

PostGRESQL также не распознает unsignedстолбцы, поэтому вы можете отказаться от него или добавить настраиваемое ограничение, например следующее:

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

В то время как SQLite по умолчанию использует нулевые значения '', PostgreSQL требует, чтобы они были установлены как NULL.

Синтаксис файла дампа SQLite в основном совместим с PostgreSQL, поэтому вы можете исправить несколько вещей и скормить их psql. Импорт большого количества данных через SQL INSERT может занять некоторое время, но это сработает.

mu слишком мало
источник
4
Нет, вы хотите сохранить транзакцию, чтобы избежать накладных расходов.
Питер Эйзентраут
3
Это прекрасно работает. Я также хотел бы отметить, что если вам нужно перенести datetimeстолбцы sqlite , вы должны изменить их на timestampдля postgres.
Clay
4
Еще несколько проблем, с которыми я столкнулся: переход BLOBна BYTEA( stackoverflow.com/questions/3103242 ), изменение 0/1 для BOOLEANстолбцов на '0' / '1' и отсрочка ограничений ( DEFERRABLE/ SET CONSTRAINTS ALL DEFERRED).
Николас Райли
1
@NicholasRiley: Спасибо за это. Я передал это вики сообщества, так как это превратилось в коллективную работу, честно, честно.
mu слишком короткое
2
Вы можете использовать to_timestamp () в postgreSQL для преобразования отметки времени в отметку времени progreSQL
r03
62

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 от bleeding edge и установил с помощью sudo dpkg -i <.deb file name> , проблем с зависимостями не было.
silpol
Я согласен с @silpol - обязательно загрузите последний стабильный выпуск и установите его с помощью менеджера пакетов fav; для "командного" файла это просто текстовый файл с именем 'command' без имени расширения (т.е. нет необходимости в .txt в конце имени файла), вам не нужно помещать имя файла в угловые скобки; мне пришлось изменить search_parth базы данных psql, чтобы увидеть мои данные; pgloader работает хорошо и избавил меня от
лишних
это спасет мой день.
Якоб
1
Да, я боролся, когда столкнулся с этой проблемой, и этот инструмент сделал ее настолько простой ... Иногда все просто хорошо получается, не так ли?
Никореллиус
Спасибо, бро. Я считаю, что этот ответ достоин быть принятым! очень хороший инструмент.
mohamed_18 02
16

Я написал сценарий sqlite3для postgresмиграции. Он не обрабатывает все переводы схемы / данных, упомянутые в https://stackoverflow.com/a/4581921/1303625 , но он делает то, что мне нужно. Надеюсь, это станет хорошей отправной точкой для других.

https://gist.github.com/2253099

Эрл Клабб
источник
2
Это хорошо работает! Я раздвоил Gist и добавил некоторые идеи в качестве комментария: gist.github.com/bittner/7368128
Петерино
14

Сиквел камень (библиотека Ruby) предлагает копирования данных в различных базах данных: http://sequel.jeremyevans.net/rdoc/files/doc/bin_sequel_rdoc.html#label-Copy+Databases

Сначала установите Ruby, затем установите гем, запустив gem install sequel.

В случае sqlite это будет так: sequel -C sqlite://db/production.sqlite3 postgres://user@localhost/db

Lulalala
источник
1
Отличное решение. Гораздо проще, чем возиться pgloader.
michaeldever
Безусловно, pgloader беспорядочный, сборщик мусора, похоже, дает сбой в огромных базах данных: github.com/dimitri/pgloader/issues/962
hasufell
Не стесняйтесь размещать свой ответ на stackoverflow.com/questions/6148421/…, где я скопировал ваш ответ. Затем пингуйте меня, и я отзову свой ответ, если вам нужны представители.
Феликс
@Felix спасибо! Вы можете взять кредит. Не могли бы вы поменять местами порядок ссылок на БД (так как он хочет, чтобы PG на SQLite), о, и добавить еще одну «ля» к моему идентификатору. Ответ также может быть менее полезным, поскольку для этого требуется, чтобы они установили PG на машину разработчика, и в этот момент они просто использовали бы PG для разработки.
lulalala
@lulalala Спасибо. Сделал это. Но насчет рассуждений я не согласен. Они могут, например, преобразовать базу данных на машине Linux, а затем скопировать ее на машину разработки (как файл 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 
develCuy
источник
нет замены для типа LONG, например
stillanothercoder
1
можно добавить еще один пунктsed -e 's/DATETIME/TIMESTAMP/g'
силпол
sed -e 's/TINYINT(1)/SMALLINT/g' - и для сравнения всех типов данных см. stackoverflow.com/questions/1942586/…
Purplejacket
У меня также была проблема с SMALLINT, который по умолчанию был равен 't' или 'f' в sqlite. Очевидно, логическое значение, но недостаточно знакомо с любой системой db, чтобы рекомендовать безопасное исправление.
лабиринт
1
Заменить ' | sed -e 'на ; :)
AstraSerg 03
0

Я пробовал редактировать / выполнять регулярное выражение дампа sqlite, поэтому PostgreSQL принимает его, это утомительно и подвержено ошибкам.

Что мне нужно, чтобы работать очень быстро:

Сначала воссоздайте схему в PostgreSQL без каких-либо данных, либо отредактировав дамп, либо, если вы использовали ORM, вам может повезти, и он общается с обоими внутренними компонентами (sqlalchemy, peewee, ...).

Затем перенесите данные с помощью панд. Предположим, у вас есть таблица с полем bool (которое равно 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: // имя пользователя : пароль @ имя хоста / имя базы данных

куичи
источник
1
Pgloader ужасно глючит и ненадежен. Сразу вылетает с ошибкойKABOOM! Control stack exhausted (no more space for function call frames).
Cerin 01