Перейти к содержимому

Конвертация MySQL в PostgreSQL

Перетащите дамп из mysqldump, mariadb-dump, mysqlpump, phpMyAdmin или Adminer в формате .sql или .sql.gz и скачайте скрипт PostgreSQL с теми же таблицами, ключами, индексами и данными. Каждое значение, которое PostgreSQL не может хранить как есть, и каждый объект, который он не переносит, указаны в отчете.

Ваш файл
sqlshop_2024.sqlПример файла, 5,1 кБ
Ваша база данных

18 строк конвертировано, 8 исправлений, ни одна не отклонена

Показать

Таблицы в shop_2024.sqlДамп MySQL 8.0.46 · создан программой mysqldump · utf8mb4

  • customers8 строк3
    7 столбцов
    idbigint not null
    namevarchar(100) not null
    emailvarchar(150) not null
    countryvarchar(2) not null
    is_activeboolean not null
    signed_update
    created_attimestamptz(0) not null
  • orders10 строк5
    9 столбцов
    idbigint not null
    customer_idbigint not null
    statustext not null
    totalnumeric(10,2) not null
    itemsinteger not null
    ordered_attimestamp(0) not null
    shipped_attimestamp(0)
    notevarchar(255)
    updated_attimestamptz(0) not null
-- Written by IntoSQL from a MySQL dump. Load it with: psql -v ON_ERROR_STOP=1 -f <file>
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET synchronous_commit = off;
SET maintenance_work_mem = '512MB';

CREATE TABLE customers (
    id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
    name varchar(100) NOT NULL,
    email varchar(150) NOT NULL,
    country varchar(2) DEFAULT 'US' NOT NULL,
    is_active boolean DEFAULT true NOT NULL,
    signed_up date,
    created_at timestamptz(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT customers_id_check CHECK (id >= 0)
);

CREATE TABLE orders (
    id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
    customer_id bigint NOT NULL,
    status text DEFAULT 'pending' NOT NULL,
    total numeric(10,2) NOT NULL,
    items integer DEFAULT 1 NOT NULL,
    ordered_at timestamp(0) NOT NULL,
    shipped_at timestamp(0),
    note varchar(255),
    updated_at timestamptz(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT orders_id_check CHECK (id >= 0),
    CONSTRAINT orders_customer_id_check CHECK (customer_id >= 0),
    CONSTRAINT orders_status_check CHECK (status IN ('pending', 'paid', 'shipped', 'cancelled', '')),
    CONSTRAINT orders_items_check CHECK (items >= 0)
);

COPY customers (id, name, email, country, is_active, signed_up, created_at) FROM stdin;
1	Ana Martínez	ana@example.com	MX	t	2023-01-15	2023-01-15 10:24:00+00:00
2	Zoë Müller	zoe@example.de	DE	t	2023-02-03	2023-02-03 08:11:42+00:00
3	José Peña	jose@example.es	ES	f	2023-03-21	2023-03-21 19:05:17+00:00
4	李雷	lilei@example.cn	CN	t	2023-05-09	2023-05-09 02:40:00+00:00
5	Noah O'Brien	noah@example.ie	IE	t	\N	2023-06-30 14:00:00+00:00
6	Amélie Laurent	amelie@example.fr	FR	t	2024-01-02	2024-01-02 09:30:00+00:00
7	Ravi Patel	ravi@example.in	IN	f	2024-02-29	2024-02-29 23:59:59+00:00
8	Sofia Rossi 🌻	sofia@example.it	IT	t	2024-04-12	2024-04-12 12:12:12+00:00
\.

COPY orders (id, customer_id, status, total, items, ordered_at, shipped_at, note, updated_at) FROM stdin;
1	1	shipped	129.90	3	2024-03-01 10:00:00	2024-03-02 16:30:00	\N	2024-03-02 16:30:00+00:00
2	2	paid	54.00	1	2024-03-02 11:15:00	\N	Gift wrap 🎁	2024-03-02 11:20:00+00:00
3	1	cancelled	12.50	1	2024-03-03 09:45:00	\N	Customer changed their mind	2024-03-03 10:00:00+00:00
4	4	shipped	980.00	12	2024-03-05 02:10:00	2024-03-07 08:00:00	请小心轻放	2024-03-07 08:00:00+00:00
5	5	pending	45.75	2	2024-03-08 17:20:00	\N	Leave at the door; ring twice	2024-03-08 17:20:00+00:00
6	6	shipped	310.40	5	2024-03-10 13:00:00	2024-03-11 09:00:00	Fragile: "glass"	2024-03-11 09:00:00+00:00
7	8	paid	76.20	2	2024-03-11 18:45:00	\N	\N	2024-03-11 18:46:00+00:00
8	2		19.99	1	2024-03-12 08:00:00	\N	Status lost in an old import	2024-03-12 08:00:00+00:00
9	3	shipped	64.00	2	2024-03-14 15:30:00	\N	Shipping date never recorded	2024-03-15 10:00:00+00:00
10	7	paid	1499.00	1	2024-03-15 21:05:00	\N	C:\\Users\\ravi\\invoice.pdf	2024-03-15 21:05:00+00:00
\.


-- Keys, indexes and constraints, after the rows so each builds once.
CREATE UNIQUE INDEX customers_pkey ON customers (id);
CREATE UNIQUE INDEX customers_uq_email ON customers (email);
CREATE UNIQUE INDEX orders_pkey ON orders (id);
CREATE INDEX orders_idx_customer ON orders (customer_id);
CREATE INDEX orders_idx_status_date ON orders (status, ordered_at);
ALTER TABLE customers ADD CONSTRAINT customers_pkey PRIMARY KEY USING INDEX customers_pkey;
ALTER TABLE customers ADD CONSTRAINT customers_uq_email UNIQUE USING INDEX customers_uq_email;
ALTER TABLE orders ADD CONSTRAINT orders_pkey PRIMARY KEY USING INDEX orders_pkey;
ALTER TABLE orders ADD CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers (id) NOT VALID;
DO $f$ BEGIN
    ALTER TABLE orders VALIDATE CONSTRAINT fk_orders_customer;
EXCEPTION WHEN foreign_key_violation THEN
    RAISE WARNING 'foreign key % has rows without a parent: it stays NOT VALID, and new rows are checked', 'fk_orders_customer';
END $f$;
SELECT setval(pg_get_serial_sequence('customers', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM customers)::numeric, 0) + 1, 1001), 9223372036854775807)::bigint, false);
COMMENT ON TABLE customers IS 'People who bought at least once';
SELECT setval(pg_get_serial_sequence('orders', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM orders)::numeric, 0) + 1, 5001), 9223372036854775807)::bigint, false);
CREATE FUNCTION orders_updated_at_on_update() RETURNS trigger LANGUAGE plpgsql AS $f$
BEGIN
    IF NEW IS DISTINCT FROM OLD AND NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at THEN
        NEW.updated_at := CURRENT_TIMESTAMP;
    END IF;
    RETURN NEW;
END
$f$;
CREATE TRIGGER orders_updated_at_on_update BEFORE UPDATE ON orders FOR EACH ROW EXECUTE FUNCTION orders_updated_at_on_update();

Исправления

  1. Столбец "id" таблицы customers беззнаковый, поэтому он стал bigint с проверкой, что значение не отрицательное.
  2. Столбец "signed_up" таблицы customers теперь допускает NULL: часть его значений нельзя было сохранить, и они записаны как NULL.
  3. Значение по умолчанию столбца "signed_up" таблицы customers, 0000‑00‑00, не является датой, которую принимает PostgreSQL, поэтому у столбца его нет.
  4. Столбец "customer_id" таблицы orders беззнаковый, поэтому он стал bigint с проверкой, что значение не отрицательное.
  5. Столбец "id" таблицы orders беззнаковый, поэтому он стал bigint с проверкой, что значение не отрицательное.
  6. Столбец "items" таблицы orders беззнаковый, поэтому он стал integer с проверкой, что значение не отрицательное.
  7. В 1 строке столбца "status" таблицы orders пустое значение, которое MySQL записывает вместо недопустимых; проверка значений его допускает.
  8. Столбец "updated_at" таблицы orders получает текущее время при каждом обновлении; в PostgreSQL это делает триггер.

Требует проверки

  • В "signed_up" таблицы customers 1 значение - нулевая или невозможная дата, например 0000‑00‑00; PostgreSQL не может их хранить, поэтому записан NULL. Если эти даты что-то значат, замените их в источнике настоящими до создания дампа.
  • В "shipped_at" таблицы orders 1 значение - нулевая или невозможная дата, например 0000‑00‑00 00:00:00; PostgreSQL не может их хранить, поэтому записан NULL. Если эти даты что-то значат, замените их в источнике настоящими до создания дампа.

Файл конвертируется на этом компьютере и никуда не загружается.

Другие примеры:

Что меняется при переходе с MySQL на PostgreSQL

Каждая строка - это правило, которое применяет конвертер, и строка отчета, которую он пишет, когда правило что-то меняет в ваших данных.

  • TINYINT(1), BOOL

    boolean, если каждое значение 0 или 1, иначе smallint

    BOOL в MySQL - это TINYINT(1), который может хранить любое число от -128 до 127. Столбец только с 0 и 1 становится boolean; столбец с 2 или -1 остается числом, чтобы ни одно значение не изменило смысл.

    Строка отчета: bool_kept_numeric

  • UNSIGNED integers

    следующий более широкий целый тип с CHECK на неотрицательность; BIGINT UNSIGNED становится bigint, если все значения помещаются, иначе numeric(20,0)

    В PostgreSQL нет беззнаковых целых. Более широкий тип вмещает весь беззнаковый диапазон, а проверка не пропускает отрицательные значения, как в MySQL.

    Строка отчета: unsigned_widened

  • ZEROFILL and display widths

    удаляется

    Дополнение нулями - это способ показа числа, а не его часть. Числа сохраняются; если дополнение важно, форматируйте их при чтении.

    Строка отчета: zerofill_dropped

  • FLOAT(M,D)

    real или double precision, без масштаба

    У чисел с плавающей точкой в PostgreSQL нет фиксированного масштаба. Записанные значения копируются как есть.

    Строка отчета: float_scale_dropped

  • BIT(1), BIT(n)

    boolean, bit(n)

    Один бит - это да или нет; более широкие битовые поля сохраняют каждый бит.

  • zero, partial or impossible dates (0000-00-00, 2024-02-30)

    NULL

    PostgreSQL хранит только настоящие календарные даты. MySQL сохраняет нулевые и невозможные даты, если это позволяет режим SQL; они становятся NULL, а отчет их подсчитывает.

    Строка отчета: invalid_date_null

  • NOT NULL columns with values that become NULL

    NOT NULL снимается

    Столбец, значения которого пришлось заменить на NULL, не может сохранить NOT NULL, иначе загрузка остановится.

    Строка отчета: not_null_relaxed

  • DEFAULT '0000-00-00'

    без значения по умолчанию

    Значение по умолчанию, которое PostgreSQL не может хранить, опускается, а не заменяется выдуманной датой.

    Строка отчета: zero_date_default

  • TIME

    time, если каждое значение укладывается в сутки, иначе interval

    TIME в MySQL - это длительность от -838:59:59 до 838:59:59. Столбец, значения которого укладываются в сутки, остается временем суток; столбец с более длинными или отрицательными значениями становится interval.

    Строка отчета: time_as_interval

  • YEAR

    smallint с CHECK диапазона

    В PostgreSQL нет типа для года; проверка допускает те же значения, что и MySQL.

  • CHAR(n)

    varchar(n)

    MySQL убирает пробелы в конце значений CHAR при чтении, а char(n) в PostgreSQL добавил бы их обратно, поэтому varchar(n) хранит значения такими, какими их возвращает MySQL.

  • DATETIME

    timestamp

    DATETIME - это показание часов без часового пояса, как timestamp в PostgreSQL.

  • TIMESTAMP

    timestamptz в часовом поясе, указанном в дампе, или UTC, если он не указан

    TIMESTAMP - это момент времени. Дампы указывают пояс, в котором он записан (mysqldump пишет UTC); без этого значения читаются как UTC, и отчет это отмечает.

    Строка отчета: timestamp_zone_assumed

  • ENUM

    text с CHECK значений

    Текст с проверкой хранит те же значения, и его проще изменить, чем тип enum в PostgreSQL.

  • ENUM holding '' (MySQL's error value)

    пустое значение, которое допускает проверка

    MySQL записывает пустую строку, когда недопустимое значение попадает в ENUM в нестрогом режиме SQL. Такие строки сохраняются, и проверка их допускает.

    Строка отчета: enum_invalid_value

  • ENUM or SET holding values outside its list

    без CHECK

    Значения, которых нет в списке, не прошли бы проверку, поэтому она не создается.

    Строка отчета: enum_check_skipped

  • SET

    text[] с CHECK, что каждый элемент есть в списке

    Массив хранит каждый элемент отдельно, поэтому запросы могут проверять вхождение.

  • JSON

    jsonb; json, если значение содержит \u0000

    jsonb - это тип, который PostgreSQL хорошо индексирует и запрашивает, но он не принимает экранирование \u0000, поэтому столбец с ним остается json.

    Строка отчета: json_not_jsonb

  • NUL bytes in text

    удаляется

    Текст в PostgreSQL не может содержать байт NUL. Байт удаляется, а отчет подсчитывает такие значения.

    Строка отчета: nul_removed

  • text that isn't valid in its character set

    неверные байты заменяются символом замены

    Текст в PostgreSQL должен быть корректным UTF-8.

    Строка отчета: invalid_utf8_replaced

  • text decoded twice (ñ)

    копируется как есть

    Дамп содержит именно эти символы, поэтому они копируются; отчет на них указывает.

    Строка отчета: mojibake_suspected

  • AUTO_INCREMENT

    GENERATED BY DEFAULT AS IDENTITY, счетчик выставлен после скопированных id

    Столбцы identity принимают скопированные id, а счетчик продолжается после наибольшего из них или после AUTO_INCREMENT дампа, смотря что больше.

  • MyISAM AUTO_INCREMENT on the second column of a key

    один счетчик на таблицу

    MyISAM считает отдельно для каждой группы первого столбца ключа; в PostgreSQL один счетчик на столбец.

    Строка отчета: myisam_group_autoincrement

  • ON UPDATE CURRENT_TIMESTAMP

    триггер BEFORE UPDATE

    Триггер записывает в столбец текущее время, когда строка меняется, а обновление не задало его, как это делает MySQL.

    Строка отчета: on_update_trigger

  • generated columns

    STORED

    PostgreSQL с 13 по 17 поддерживает только хранимые генерируемые столбцы; формула та же.

    Строка отчета: virtual_as_stored

  • generated columns with functions PostgreSQL lacks

    обычный столбец

    Формула, которую нельзя записать для PostgreSQL, оставляет обычный столбец и строку в отчете.

    Строка отчета: generated_not_translated

  • INVISIBLE columns

    обычные столбцы

    В PostgreSQL нет невидимых столбцов.

    Строка отчета: invisible_column

  • CHECK constraints

    переводится, внутри CREATE TABLE

    Встроенные проверки выполняются при загрузке каждой строки, а не отдельным проходом для каждой проверки после загрузки.

  • CHECK constraints with functions PostgreSQL lacks

    не создается

    Проверка, которую нельзя записать для PostgreSQL, опускается и попадает в отчет.

    Строка отчета: check_skipped

  • CHECK ... NOT ENFORCED

    не создается

    MySQL хранит эти проверки, но не применяет их, поэтому строки могут их нарушать.

    Строка отчета: check_not_enforced

  • defaults with functions PostgreSQL lacks

    без значения по умолчанию

    Значение по умолчанию, которое нельзя записать для PostgreSQL, опускается и попадает в отчет.

    Строка отчета: default_not_translated

  • keys and indexes on a prefix, c(20)

    индекс по left(c, 20)

    PostgreSQL индексирует выражения, поэтому индексируется тот же префикс.

    Строка отчета: prefix_unique

  • FULLTEXT indexes

    GIN по to_tsvector('simple', ...)

    Полнотекстовый поиск работает через @@ вместо MATCH ... AGAINST.

    Строка отчета: fulltext_as_gin

  • indexes on values over 2,000 bytes

    hash

    Запись btree не вмещает такие длинные значения; индекс hash все равно находит равные значения.

    Строка отчета: index_on_wide_values

  • SPATIAL indexes

    не создается без PostGIS

    Пространственным индексам нужен PostGIS.

    Строка отчета: spatial_index_skipped

  • functional indexes PostgreSQL can't write

    не создается

    Индекс по выражению, которое нельзя записать для PostgreSQL, опускается и попадает в отчет.

    Строка отчета: index_skipped

  • foreign keys

    после данных, NOT VALID, затем проверка с предупреждением о строках без родителя

    Дампы загружаются с FOREIGN_KEY_CHECKS=0, а MyISAM ничего не проверяет, поэтому строки без родительской записи встречаются часто. Ключ создается первым и проверяется последним; при строках без родителя он остается NOT VALID с предупреждением, и загрузка не останавливается.

  • foreign keys to columns without a unique key

    не создается

    PostgreSQL требует уникальный ключ на столбцах, на которые ссылается внешний ключ; InnoDB - нет.

    Строка отчета: foreign_key_skipped

  • table and column names

    нижний регистр, если имена остаются уникальными

    Имена в нижнем регистре можно писать в PostgreSQL без кавычек.

    Строка отчета: identifier_renamed

  • names over 63 bytes

    сокращается с хешем

    Имена в PostgreSQL вмещают 63 байта; хеш не дает сокращенным именам совпасть.

    Строка отчета: name_shortened

  • GEOMETRY, POINT, POLYGON...

    WKB в bytea

    Без PostGIS стандартный формат well-known binary точно сохраняет каждую геометрию.

    Строка отчета: geometry_as_wkb

  • INET4, INET6, UUID (MariaDB)

    inet, uuid

    В PostgreSQL есть такие же типы.

  • BINARY, VARBINARY, BLOB

    bytea

    Байты остаются байтами.

  • PARTITION BY

    одна таблица

    Строки те же; при необходимости секционируйте таблицу заново в PostgreSQL.

    Строка отчета: partitions_dropped

  • WITH SYSTEM VERSIONING (MariaDB)

    таблица с текущими строками

    Дамп содержит только текущие строки.

    Строка отчета: system_versioning_dropped

  • MyISAM, MEMORY and other engines

    обычная таблица

    В PostgreSQL один движок таблиц.

    Строка отчета: engine_dropped

  • views, triggers, procedures, functions and events

    перечисляются в отчете

    Их код написан на языке MySQL, поэтому они перечислены, чтобы вы создали их заново.

    Строка отчета: not_converted_objects

  • dumps without CREATE TABLE

    типы определяются по значениям

    Дамп, созданный с --no-create-info, содержит только строки, поэтому типы берутся из значений.

    Строка отчета: no_schema

  • geometries in a dump without CREATE TABLE

    WKB в bytea

    Формат геометрии MySQL распознается по значениям и сохраняется как стандартный WKB.

    Строка отчета: geometry_inferred

  • _ci collations

    точное сравнение

    PostgreSQL сравнивает текст точно, если не указано иное.

    Строка отчета: case_insensitive_collation

  • SET NAMES utf8 from utf8mb4 tables

    конвертируется с предупреждением

    mysqldump из MySQL 5.x по умолчанию пишет 3-байтовую utf8 и заменяет каждый эмодзи вопросительным знаком еще до того, как файл увидит какой-либо конвертер.

    Строка отчета: dump_lost_four_byte_chars

  • dumps without SET NAMES whose text isn't UTF-8

    читается как Latin-1 (Windows-1252)

    latin1 в MySQL - это Windows-1252, обычная кодировка таких дампов.

    Строка отчета: charset_guessed

  • sjis, cp932, gbk, big5 dumps

    читается как UTF-8, с предупреждением

    Эти кодировки пока не декодируются.

    Строка отчета: unsupported_charset

  • UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows

    вычисляются

    Некоторые программы дампа записывают значения как такие вызовы; они читаются как значения, которые возвращают, а в географическом WKT долгота ставится первой.

  • other expressions in rows

    NULL

    Конвертер, который не запускает базу данных, не может их вычислить.

    Строка отчета: expression_value

  • DEFAULT in VALUES

    значение столбца по умолчанию

    Литеральное значение по умолчанию копируется в строку.

    Строка отчета: default_keyword_filled

  • DEFAULT in VALUES without a literal default

    NULL

    Копировать нечего.

    Строка отчета: default_keyword_null

  • REPLACE and INSERT IGNORE

    обычные строки

    В дампе одна строка на ключ, поэтому строки те же.

    Строка отчета: replace_as_insert

  • types IntoSQL doesn't know

    text

    Тип text вмещает любое значение; измените тип после загрузки.

    Строка отчета: unknown_type

  • values that don't fit their column

    NULL

    Поврежденный или написанный вручную дамп может содержать значения, которые столбец не вмещает; они становятся NULL, чтобы остальное загрузилось.

    Строка отчета: invalid_value_null

  • unreadable geometries

    NULL

    Байты, которые не являются геометрией, нельзя сохранить как геометрию.

    Строка отчета: bad_geometry

  • CREATE SEQUENCE (MariaDB)

    CREATE SEQUENCE с текущим значением

    Последовательности PostgreSQL принимают те же параметры.

В MySQLВ PostgreSQLСтрока отчета
TINYINT(1), BOOLboolean, если каждое значение 0 или 1, иначе smallintBOOL в MySQL - это TINYINT(1), который может хранить любое число от -128 до 127. Столбец только с 0 и 1 становится boolean; столбец с 2 или -1 остается числом, чтобы ни одно значение не изменило смысл.bool_kept_numeric
UNSIGNED integersследующий более широкий целый тип с CHECK на неотрицательность; BIGINT UNSIGNED становится bigint, если все значения помещаются, иначе numeric(20,0)В PostgreSQL нет беззнаковых целых. Более широкий тип вмещает весь беззнаковый диапазон, а проверка не пропускает отрицательные значения, как в MySQL.unsigned_widened
ZEROFILL and display widthsудаляетсяДополнение нулями - это способ показа числа, а не его часть. Числа сохраняются; если дополнение важно, форматируйте их при чтении.zerofill_dropped
FLOAT(M,D)real или double precision, без масштабаУ чисел с плавающей точкой в PostgreSQL нет фиксированного масштаба. Записанные значения копируются как есть.float_scale_dropped
BIT(1), BIT(n)boolean, bit(n)Один бит - это да или нет; более широкие битовые поля сохраняют каждый бит.
zero, partial or impossible dates (0000-00-00, 2024-02-30)NULLPostgreSQL хранит только настоящие календарные даты. MySQL сохраняет нулевые и невозможные даты, если это позволяет режим SQL; они становятся NULL, а отчет их подсчитывает.invalid_date_null
NOT NULL columns with values that become NULLNOT NULL снимаетсяСтолбец, значения которого пришлось заменить на NULL, не может сохранить NOT NULL, иначе загрузка остановится.not_null_relaxed
DEFAULT '0000-00-00'без значения по умолчаниюЗначение по умолчанию, которое PostgreSQL не может хранить, опускается, а не заменяется выдуманной датой.zero_date_default
TIMEtime, если каждое значение укладывается в сутки, иначе intervalTIME в MySQL - это длительность от -838:59:59 до 838:59:59. Столбец, значения которого укладываются в сутки, остается временем суток; столбец с более длинными или отрицательными значениями становится interval.time_as_interval
YEARsmallint с CHECK диапазонаВ PostgreSQL нет типа для года; проверка допускает те же значения, что и MySQL.
CHAR(n)varchar(n)MySQL убирает пробелы в конце значений CHAR при чтении, а char(n) в PostgreSQL добавил бы их обратно, поэтому varchar(n) хранит значения такими, какими их возвращает MySQL.
DATETIMEtimestampDATETIME - это показание часов без часового пояса, как timestamp в PostgreSQL.
TIMESTAMPtimestamptz в часовом поясе, указанном в дампе, или UTC, если он не указанTIMESTAMP - это момент времени. Дампы указывают пояс, в котором он записан (mysqldump пишет UTC); без этого значения читаются как UTC, и отчет это отмечает.timestamp_zone_assumed
ENUMtext с CHECK значенийТекст с проверкой хранит те же значения, и его проще изменить, чем тип enum в PostgreSQL.
ENUM holding '' (MySQL's error value)пустое значение, которое допускает проверкаMySQL записывает пустую строку, когда недопустимое значение попадает в ENUM в нестрогом режиме SQL. Такие строки сохраняются, и проверка их допускает.enum_invalid_value
ENUM or SET holding values outside its listбез CHECKЗначения, которых нет в списке, не прошли бы проверку, поэтому она не создается.enum_check_skipped
SETtext[] с CHECK, что каждый элемент есть в спискеМассив хранит каждый элемент отдельно, поэтому запросы могут проверять вхождение.
JSONjsonb; json, если значение содержит \u0000jsonb - это тип, который PostgreSQL хорошо индексирует и запрашивает, но он не принимает экранирование \u0000, поэтому столбец с ним остается json.json_not_jsonb
NUL bytes in textудаляетсяТекст в PostgreSQL не может содержать байт NUL. Байт удаляется, а отчет подсчитывает такие значения.nul_removed
text that isn't valid in its character setневерные байты заменяются символом заменыТекст в PostgreSQL должен быть корректным UTF-8.invalid_utf8_replaced
text decoded twice (ñ)копируется как естьДамп содержит именно эти символы, поэтому они копируются; отчет на них указывает.mojibake_suspected
AUTO_INCREMENTGENERATED BY DEFAULT AS IDENTITY, счетчик выставлен после скопированных idСтолбцы identity принимают скопированные id, а счетчик продолжается после наибольшего из них или после AUTO_INCREMENT дампа, смотря что больше.
MyISAM AUTO_INCREMENT on the second column of a keyодин счетчик на таблицуMyISAM считает отдельно для каждой группы первого столбца ключа; в PostgreSQL один счетчик на столбец.myisam_group_autoincrement
ON UPDATE CURRENT_TIMESTAMPтриггер BEFORE UPDATEТриггер записывает в столбец текущее время, когда строка меняется, а обновление не задало его, как это делает MySQL.on_update_trigger
generated columnsSTOREDPostgreSQL с 13 по 17 поддерживает только хранимые генерируемые столбцы; формула та же.virtual_as_stored
generated columns with functions PostgreSQL lacksобычный столбецФормула, которую нельзя записать для PostgreSQL, оставляет обычный столбец и строку в отчете.generated_not_translated
INVISIBLE columnsобычные столбцыВ PostgreSQL нет невидимых столбцов.invisible_column
CHECK constraintsпереводится, внутри CREATE TABLEВстроенные проверки выполняются при загрузке каждой строки, а не отдельным проходом для каждой проверки после загрузки.
CHECK constraints with functions PostgreSQL lacksне создаетсяПроверка, которую нельзя записать для PostgreSQL, опускается и попадает в отчет.check_skipped
CHECK ... NOT ENFORCEDне создаетсяMySQL хранит эти проверки, но не применяет их, поэтому строки могут их нарушать.check_not_enforced
defaults with functions PostgreSQL lacksбез значения по умолчаниюЗначение по умолчанию, которое нельзя записать для PostgreSQL, опускается и попадает в отчет.default_not_translated
keys and indexes on a prefix, c(20)индекс по left(c, 20)PostgreSQL индексирует выражения, поэтому индексируется тот же префикс.prefix_unique
FULLTEXT indexesGIN по to_tsvector('simple', ...)Полнотекстовый поиск работает через @@ вместо MATCH ... AGAINST.fulltext_as_gin
indexes on values over 2,000 byteshashЗапись btree не вмещает такие длинные значения; индекс hash все равно находит равные значения.index_on_wide_values
SPATIAL indexesне создается без PostGISПространственным индексам нужен PostGIS.spatial_index_skipped
functional indexes PostgreSQL can't writeне создаетсяИндекс по выражению, которое нельзя записать для PostgreSQL, опускается и попадает в отчет.index_skipped
foreign keysпосле данных, NOT VALID, затем проверка с предупреждением о строках без родителяДампы загружаются с FOREIGN_KEY_CHECKS=0, а MyISAM ничего не проверяет, поэтому строки без родительской записи встречаются часто. Ключ создается первым и проверяется последним; при строках без родителя он остается NOT VALID с предупреждением, и загрузка не останавливается.
foreign keys to columns without a unique keyне создаетсяPostgreSQL требует уникальный ключ на столбцах, на которые ссылается внешний ключ; InnoDB - нет.foreign_key_skipped
table and column namesнижний регистр, если имена остаются уникальнымиИмена в нижнем регистре можно писать в PostgreSQL без кавычек.identifier_renamed
names over 63 bytesсокращается с хешемИмена в PostgreSQL вмещают 63 байта; хеш не дает сокращенным именам совпасть.name_shortened
GEOMETRY, POINT, POLYGON...WKB в byteaБез PostGIS стандартный формат well-known binary точно сохраняет каждую геометрию.geometry_as_wkb
INET4, INET6, UUID (MariaDB)inet, uuidВ PostgreSQL есть такие же типы.
BINARY, VARBINARY, BLOBbyteaБайты остаются байтами.
PARTITION BYодна таблицаСтроки те же; при необходимости секционируйте таблицу заново в PostgreSQL.partitions_dropped
WITH SYSTEM VERSIONING (MariaDB)таблица с текущими строкамиДамп содержит только текущие строки.system_versioning_dropped
MyISAM, MEMORY and other enginesобычная таблицаВ PostgreSQL один движок таблиц.engine_dropped
views, triggers, procedures, functions and eventsперечисляются в отчетеИх код написан на языке MySQL, поэтому они перечислены, чтобы вы создали их заново.not_converted_objects
dumps without CREATE TABLEтипы определяются по значениямДамп, созданный с --no-create-info, содержит только строки, поэтому типы берутся из значений.no_schema
geometries in a dump without CREATE TABLEWKB в byteaФормат геометрии MySQL распознается по значениям и сохраняется как стандартный WKB.geometry_inferred
_ci collationsточное сравнениеPostgreSQL сравнивает текст точно, если не указано иное.case_insensitive_collation
SET NAMES utf8 from utf8mb4 tablesконвертируется с предупреждениемmysqldump из MySQL 5.x по умолчанию пишет 3-байтовую utf8 и заменяет каждый эмодзи вопросительным знаком еще до того, как файл увидит какой-либо конвертер.dump_lost_four_byte_chars
dumps without SET NAMES whose text isn't UTF-8читается как Latin-1 (Windows-1252)latin1 в MySQL - это Windows-1252, обычная кодировка таких дампов.charset_guessed
sjis, cp932, gbk, big5 dumpsчитается как UTF-8, с предупреждениемЭти кодировки пока не декодируются.unsupported_charset
UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rowsвычисляютсяНекоторые программы дампа записывают значения как такие вызовы; они читаются как значения, которые возвращают, а в географическом WKT долгота ставится первой.
other expressions in rowsNULLКонвертер, который не запускает базу данных, не может их вычислить.expression_value
DEFAULT in VALUESзначение столбца по умолчаниюЛитеральное значение по умолчанию копируется в строку.default_keyword_filled
DEFAULT in VALUES without a literal defaultNULLКопировать нечего.default_keyword_null
REPLACE and INSERT IGNOREобычные строкиВ дампе одна строка на ключ, поэтому строки те же.replace_as_insert
types IntoSQL doesn't knowtextТип text вмещает любое значение; измените тип после загрузки.unknown_type
values that don't fit their columnNULLПоврежденный или написанный вручную дамп может содержать значения, которые столбец не вмещает; они становятся NULL, чтобы остальное загрузилось.invalid_value_null
unreadable geometriesNULLБайты, которые не являются геометрией, нельзя сохранить как геометрию.bad_geometry
CREATE SEQUENCE (MariaDB)CREATE SEQUENCE с текущим значениемПоследовательности PostgreSQL принимают те же параметры.

Загрузите скрипт в PostgreSQL

Скрипт создает таблицы, копирует строки, затем добавляет ключи, индексы и внешние ключи, поэтому загрузка идет быстро и останавливается на первой ошибке.

psql -v ON_ERROR_STOP=1 -d mydb -f mysql.postgresql.sql

Внешние ключи добавляются как NOT VALID, а затем проверяются. Если строка ссылается на несуществующую строку, скрипт сообщает, какое ограничение нарушено, а не прерывается на полпути.

Для большого дампа сначала создайте базу данных и запустите скрипт через psql на той же машине, где работает сервер.

Как создать дамп MySQL для лучшего результата

Конвертер читает то, что есть в дампе. Эти параметры сохраняют в нем больше ваших данных:

  • --default-character-set=utf8mb4 сохраняет эмодзи и другие 4-байтовые символы, которые дамп в utf8 теряет еще до конвертера.
  • --hex-blob записывает двоичные столбцы в шестнадцатеричном виде, который не портится при копировании между системами.
  • --routines --triggers --events добавляют эти объекты в дамп, чтобы отчет мог их перечислить.

Что не конвертируется

Представления, триггеры, хранимые процедуры, функции и события написаны на собственном языке каждой базы данных. Они перечислены в отчете по имени и никогда не удаляются молча, чтобы вы могли переписать их для PostgreSQL.

Сравнение с pgloader

Одни и те же дампы, конвертированные и загруженные IntoSQL и pgloader 3.6.7 на одной машине (10-ядерный i9-10900K с SATA SSD) в октябре 2026 года.

  • Столбец TINYINT(1) со значениями 2, -1 и -5: pgloader загружает для каждого true, без предупреждения. IntoSQL сохраняет числа, а отчет объясняет почему.
  • Дамп со значением по умолчанию 'it's', таблицей с обратной кавычкой в имени, ENUM с пустым значением и TIME больше 24 часов: pgloader останавливается. IntoSQL конвертирует и загружает его.
  • В том, что загружает pgloader, теряются первичные, уникальные и внешние ключи и identity. IntoSQL сохраняет их все.
  • Дамп 5.3 GB на 30 миллионов строк: pgloader требует сначала восстановить его в работающий MySQL, что занимает 18 минут, а затем с настройками по умолчанию ему не хватает памяти. IntoSQL конвертирует дамп за 10 секунд, а psql загружает скрипт примерно за 3 минуты.
  • 476 дампов из MySQL с 5.5 по 9 и MariaDB с 10.3 по 12, загруженных в PostgreSQL 13 и 18: ни одной ошибки загрузки, и ни одно значение не изменилось без строки в отчете.

Вопросы о MySQL в PostgreSQL

Нет ответа на ваш вопрос? Напишите нам через страницу контактов, и вам ответит человек. Страница контактов

Мой дамп загружается на сервер?

Нет. Конвертер работает в вашем браузере и читает дамп с диска по частям, поэтому он никогда не покидает ваш компьютер. Приложение для компьютера и командная строка тоже конвертируют на вашем компьютере.

Насколько большим может быть дамп?

Конвертер никогда не держит весь дамп в памяти: он читает файл дважды, по диапазонам, и пишет скрипт по ходу чтения. Дампы в несколько гигабайт конвертируются в браузере, в приложении для компьютера и в командной строке.

Читает ли он дампы MariaDB?

Да. Дампы из mariadb-dump и из MariaDB с 10.3 по 12 конвертируются так же, включая столбцы INET6, INET4 и UUID в MariaDB.

Что происходит с датами 0000-00-00?

В PostgreSQL нет нулевой даты, поэтому они становятся NULL, а столбец допускает NULL. Отчет показывает, сколько их было в каждом столбце.

Сохраняются ли значения AUTO_INCREMENT?

Да. Каждый столбец AUTO_INCREMENT становится столбцом identity, каждая строка сохраняет свой id, а следующий id идет после наибольшего или после AUTO_INCREMENT таблицы, если он больше.

Становится ли TINYINT(1) типом boolean?

Только если каждое значение в столбце равно 0 или 1. Если в нем есть другие числа, например 2 или -1, он остается числом, а отчет объясняет почему, так что ни одно значение случайно не станет true.

А хранимые процедуры и триггеры?

Они перечислены в отчете по имени и не конвертируются, потому что каждая база данных пишет их на своем языке. Исключение - ON UPDATE CURRENT_TIMESTAMP: он становится триггером PostgreSQL.

На каких версиях PostgreSQL загружается скрипт?

PostgreSQL с 13 по 18. Один и тот же скрипт загружается на каждой из них и останавливается на первой ошибке, если что-то пойдет не так.