将 PostgreSQL 转换为 MariaDB
拖入由 pg_dump 或 pg_dumpall 生成的纯文本转储(.sql 或 .sql.gz),即可下载包含相同表、键、索引和数据的 MariaDB 脚本。MariaDB 无法原样存储的每个值,以及它不支持的每个对象,都会在报告中列出。
已转换 18 行,3 处修正,无拒绝
shop_2024_postgres.sql 中的表PostgreSQL 18.6 转储 · 由 pg_dump 写出 · utf8mb4
customers8 行2
8 列 id int not null name text not null email varchar(768) not null country char(2) not null is_active tinyint(1) not null tags json not null signed_up date created_at datetime(6) not null orders10 行1
10 列 id int not null customer_id int not null status enum('pending','paid','shipped','cancelled') not null total decimal(10,2) not null items smallint not null ordered_at datetime(6) not null shipped_at datetime(6) note text details json delivery varchar(100)
未转换
- 视图 paid_orders
每种数据库都用自己的语言编写这些对象。请为 MariaDB 重写它们。
-- Written by IntoSQL from a PostgreSQL dump. Load it with: mariadb --default-character-set=utf8mb4 <database> < <file>
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
SET UNIQUE_CHECKS = 0;
SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO,ALLOW_INVALID_DATES';
CREATE TABLE `customers` (
`id` int NOT NULL AUTO_INCREMENT,
`name` text NOT NULL,
`email` varchar(768) NOT NULL,
`country` char(2) NOT NULL DEFAULT 'US',
`is_active` tinyint(1) NOT NULL DEFAULT 1,
`tags` json NOT NULL,
`signed_up` date,
`created_at` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
UNIQUE KEY `customers_email_key` (`email`),
PRIMARY KEY (`id`)
) AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='People who bought at least once';
CREATE TABLE `orders` (
`id` int NOT NULL AUTO_INCREMENT,
`customer_id` int NOT NULL,
`status` enum('pending','paid','shipped','cancelled') NOT NULL DEFAULT 'pending',
`total` decimal(10,2) NOT NULL,
`items` smallint NOT NULL DEFAULT 1,
`ordered_at` datetime(6) NOT NULL,
`shipped_at` datetime(6),
`note` text,
`details` json,
`delivery` varchar(100),
PRIMARY KEY (`id`),
KEY `idx_orders_customer` (`customer_id`),
KEY `idx_orders_status_date` (`status`,`ordered_at`),
CONSTRAINT `orders_total_check` CHECK (`total` >= (0)),
CONSTRAINT `orders_customer_id_fkey` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`)
) AUTO_INCREMENT=5001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
INSERT INTO `customers` (`id`,`name`,`email`,`country`,`is_active`,`tags`,`signed_up`,`created_at`) VALUES (1,'Ana Martínez','ana@example.com','MX',1,'["vip"]','2023-01-15','2023-01-15 10:24:00'),(2,'Zoë Müller','zoe@example.de','DE',1,'[]','2023-02-03','2023-02-03 08:11:42'),(3,'José Peña','jose@example.es','ES',0,'["wholesale","late payer"]','2023-03-21','2023-03-21 19:05:17'),(4,'李雷','lilei@example.cn','CN',1,'[]','2023-05-09','2023-05-09 02:40:00'),(5,'Noah O\'Brien','noah@example.ie','IE',1,'[]',NULL,'2023-06-30 14:00:00'),(6,'Amélie Laurent','amelie@example.fr','FR',1,'["vip"]','2024-01-02','2024-01-02 09:30:00'),(7,'Ravi Patel','ravi@example.in','IN',0,'[]','2024-02-29','2024-02-29 23:59:59'),(8,'Sofia Rossi 🌻','sofia@example.it','IT',1,'[]','2024-04-12','2024-04-12 12:12:12');
INSERT INTO `orders` (`id`,`customer_id`,`status`,`total`,`items`,`ordered_at`,`shipped_at`,`note`,`details`,`delivery`) VALUES (1,1,'shipped',129.90,3,'2024-03-01 10:00:00','2024-03-02 16:30:00',NULL,'{"gift": false}','1 day 06:30:00'),(2,2,'paid',54.00,1,'2024-03-02 11:15:00',NULL,'Gift wrap 🎁','{"gift": true, "wrap": "red"}',NULL),(3,1,'cancelled',12.50,1,'2024-03-03 09:45:00',NULL,'Customer changed their mind',NULL,NULL),(4,4,'shipped',980.00,12,'2024-03-05 02:10:00','2024-03-07 08:00:00','请小心轻放','{"fragile": true}','2 days 05:50:00'),(5,5,'pending',45.75,2,'2024-03-08 17:20:00',NULL,'Leave at the door; ring twice',NULL,NULL),(6,6,'shipped',310.40,5,'2024-03-10 13:00:00','2024-03-11 09:00:00','Fragile: "glass"','{"fragile": true}','20:00:00'),(7,8,'paid',76.20,2,'2024-03-11 18:45:00',NULL,NULL,NULL,NULL),(8,2,'shipped',19.99,1,'2024-03-12 08:00:00',NULL,'Shipped date set to infinity by an old import',NULL,NULL),(9,3,'shipped',64.00,2,'2024-03-14 15:30:00','2024-03-15 10:00:00','Two parcels','{"parcels": [1, 2]}','18:30:00'),(10,7,'paid',1499.00,1,'2024-03-15 21:05:00',NULL,'C:\\Users\\ravi\\invoice.pdf',NULL,NULL);
SET UNIQUE_CHECKS = 1;
SET FOREIGN_KEY_CHECKS = 1;
修正
- customers 的 "created_at" 包含带时区的时间点;MariaDB 没有能保留时区的类型,因此以 UTC 存储为 datetime(6)。
- customers 的 "tags" 是 text[],MariaDB 没有该类型,因此为 json,值保持不变。
- orders 的 "delivery" 是 interval,MariaDB 没有该类型,因此为 varchar(100),值保持不变。
需要检查
- 1 个视图、触发器、例程或事件未转换;报告逐一列出了它们。 请在 MariaDB 中手动重新创建它们。
- customers 中 "tags" 的默认值无法为 MariaDB 写出(a value its type can't hold),因此该列没有默认值。 如果新行需要,请手动添加默认值。
- orders 上的索引 idx_orders_details 使用了无法为 MariaDB 写出的表达式(neither MySQL 5.7 nor MariaDB index an expression),因此未创建。 如果查询需要,请手动创建该索引。
- orders 的 "shipped_at" 中有 1 个值是 MariaDB 无法存储的日期,例如 infinity,因此设为 NULL。 MariaDB 存储 1 到 9999 年,不支持无穷值;如果这些日期很重要,请在源数据中替换它们。
文件在这台电脑上转换,永远不会上传。
其他示例:
从 PostgreSQL 到 MariaDB 的变化
每一行是转换器应用的一条规则,以及该规则更改你的数据时在报告中写入的记录。
boolean
tinyint(1)
MariaDB 的 BOOLEAN 就是 TINYINT(1):true 为 1,false 为 0。
varchar(n), char(n), text
不超过 1024 个字符时为 varchar(n),不超过 255 时为 char(n),更长则为 text
文本以 utf8mb4 保留每个字符。键中的列最多为 varchar(768),这是键能容纳的最大长度。
numeric(p,s) past 65 digits or 30 decimals, and numeric values past what decimal(65,30) holds
varchar
MariaDB 的 decimal 可容纳 65 位数字,其中 30 位小数。更宽的数字保存为文本,使每一位都保持精确;不带精度的 numeric 在其值能容纳时为 decimal(65,30)。
报告记录: decimal_as_text
money
decimal(19,2)
MariaDB 没有 money 类型。金额保存为数字,不带服务器区域设置添加的货币符号。
报告记录: type_replaced
interval
varchar(100),存放 PostgreSQL 的文本
MariaDB 的 TIME 可容纳最长 838 小时的时长,但 interval 包含月和天;其文本保留每个部分。
报告记录: type_replaced
arrays (integer[], text[]...)
json 数组
MariaDB 没有数组。JSON 数组保留每个元素和 NULL,JSON 函数可以读取它。
报告记录: type_replaced
ranges, geometric types, tsvector, xml, hstore, composite and extension types
longtext,存放 PostgreSQL 的文本
MariaDB 没有对应的类型,因此每个值保留 PostgreSQL 写出的文本。
报告记录: type_replaced
json, jsonb
json
JSON 值相同;jsonb 的键顺序和空格由服务器决定。
timestamp
datetime(p)
不带时区的 timestamp 是挂钟读数,与 datetime 相同。
timestamp with time zone
UTC 的 datetime(p)
MariaDB 的 TIMESTAMP 只到 2038 年,因此时间点以 UTC 存储为 datetime;无论转储写入的偏移量是多少,都是同一时刻。
报告记录: moments_as_utc
time
time(p)
MariaDB 的 TIME 可容纳一天中的每个时刻,包括 24:00:00。
infinity, -infinity, BC dates and years past 9999
NULL
MariaDB 存储 1000 到 9999 年,不支持无穷值。这些值变为 NULL,报告会统计其数量。
报告记录: date_out_of_range
NaN and Infinity in numeric, real and double precision
NULL
MariaDB 的数字没有 NaN 或 Infinity,因此这些值变为 NULL,报告会统计其数量。
报告记录: invalid_value_null
NOT NULL columns with values that become NULL
去除 NOT NULL
值必须变为 NULL 的列无法保留 NOT NULL,否则导入会中止。
报告记录: not_null_relaxed
enum types
enum(...),标签相同
MariaDB 的 ENUM 按原顺序保留标签。
uuid, inet, cidr
uuid 为 uuid,inet 和 cidr 为 varchar(43)
MariaDB 有 uuid 类型;地址保留其文本,包括掩码。
bytea
blob、mediumblob 或 longblob;键中为 varbinary(3072)
字节仍然是字节。
bit(n)
不超过 64 位时为 bit(n),更长则为文本
不超过 64 位的位串存为其各位组成的数字;更长的位串保留其数字。
citext and nondeterministic collations
精确比较
表使用 utf8mb4_bin,因此文本像 PostgreSQL 一样精确比较;源数据中不区分大小写的列会失去这一点。
报告记录: case_insensitive_collation
serial, identity
AUTO_INCREMENT,从最大的 id 之后继续
由主键的第一列计数;计数器从序列所在的位置继续。
a second serial or identity column in a table
普通整数
MariaDB 每个表只为一列计数;其他列保留其值,不带计数器。
报告记录: counter_dropped
sequences not owned by a column
CREATE SEQUENCE,从它下一个要分配的值开始
MariaDB 序列的工作方式相同。
generated columns
生成列,与源数据一样为 STORED
MariaDB 以相同方式计算它们。
generated columns with functions MariaDB lacks
普通列
无法为 MariaDB 写出的公式会留下一个普通列和一条报告记录。
报告记录: generated_not_translated
defaults with functions MariaDB lacks, and defaults from a sequence
无默认值
无法为 MariaDB 写出的默认值会被省略,并在报告中列出。
报告记录: default_not_translated
CHECK constraints
已转换,内联在 CREATE TABLE 中
MySQL 8.0.16 和 MariaDB 会执行它们;MySQL 5.7 保留它们但不检查。
CHECK constraints with functions MariaDB lacks
不创建
无法为 MariaDB 写出的检查约束会被省略,并在报告中列出。
报告记录: check_skipped
CHECK ... NOT VALID
不创建
PostgreSQL 从未检查之前已有的行,因此它们可能违反该约束。
报告记录: check_not_valid
gin, gist, brin and hash indexes, partial and expression indexes
不创建
MariaDB 只有 b-tree、全文和空间索引,建立在整列上,不带 WHERE。
报告记录: index_skipped
foreign keys
外键,以 FOREIGN_KEY_CHECKS=0 导入
行可以按任意顺序导入,之后外键会检查新行。
foreign keys to tables the dump doesn't create
不创建
外键无法引用不存在的表。
报告记录: foreign_key_skipped
partitioned tables
单个表,包含每个分区的行
行保持不变;如有需要,请在 MariaDB 中重新对该表分区。
报告记录: partitions_dropped
schemas
单个数据库,每个表名前加上其 schema 名
MariaDB 的 schema 就是数据库,而导入到单个数据库的脚本无法创建数据库;public 中的表保留原名。
报告记录: schemas_merged
views, functions, procedures, triggers, rules, policies, extensions and types
在报告中列出
它们的代码用 PostgreSQL 的语言编写,因此会列出来,由你重新创建。
报告记录: not_converted_objects
dumps without CREATE TABLE (--data-only)
根据值推断类型
只含数据的转储只有行,因此类型来自值。
报告记录: no_schema
expressions in INSERT values
NULL
不运行数据库的转换器无法对它们求值。
报告记录: expression_value
types IntoSQL doesn't know
longtext
文本可以容纳任何值;请在导入后更改类型。
报告记录: unknown_type
text that isn't valid in its encoding
错误的字节变为替换字符
文本必须是有效的 utf8mb4。
报告记录: invalid_utf8_replaced
text decoded twice (ñ)
按原样复制
转储中存储的正是这些字符,因此按原样复制;报告会指出它们。
报告记录: mojibake_suspected
| 在 PostgreSQL 中 | 在 MariaDB 中 | 报告记录 |
|---|---|---|
| boolean | tinyint(1)MariaDB 的 BOOLEAN 就是 TINYINT(1):true 为 1,false 为 0。 | |
| varchar(n), char(n), text | 不超过 1024 个字符时为 varchar(n),不超过 255 时为 char(n),更长则为 text文本以 utf8mb4 保留每个字符。键中的列最多为 varchar(768),这是键能容纳的最大长度。 | |
| numeric(p,s) past 65 digits or 30 decimals, and numeric values past what decimal(65,30) holds | varcharMariaDB 的 decimal 可容纳 65 位数字,其中 30 位小数。更宽的数字保存为文本,使每一位都保持精确;不带精度的 numeric 在其值能容纳时为 decimal(65,30)。 | decimal_as_text |
| money | decimal(19,2)MariaDB 没有 money 类型。金额保存为数字,不带服务器区域设置添加的货币符号。 | type_replaced |
| interval | varchar(100),存放 PostgreSQL 的文本MariaDB 的 TIME 可容纳最长 838 小时的时长,但 interval 包含月和天;其文本保留每个部分。 | type_replaced |
| arrays (integer[], text[]...) | json 数组MariaDB 没有数组。JSON 数组保留每个元素和 NULL,JSON 函数可以读取它。 | type_replaced |
| ranges, geometric types, tsvector, xml, hstore, composite and extension types | longtext,存放 PostgreSQL 的文本MariaDB 没有对应的类型,因此每个值保留 PostgreSQL 写出的文本。 | type_replaced |
| json, jsonb | jsonJSON 值相同;jsonb 的键顺序和空格由服务器决定。 | |
| timestamp | datetime(p)不带时区的 timestamp 是挂钟读数,与 datetime 相同。 | |
| timestamp with time zone | UTC 的 datetime(p)MariaDB 的 TIMESTAMP 只到 2038 年,因此时间点以 UTC 存储为 datetime;无论转储写入的偏移量是多少,都是同一时刻。 | moments_as_utc |
| time | time(p)MariaDB 的 TIME 可容纳一天中的每个时刻,包括 24:00:00。 | |
| infinity, -infinity, BC dates and years past 9999 | NULLMariaDB 存储 1000 到 9999 年,不支持无穷值。这些值变为 NULL,报告会统计其数量。 | date_out_of_range |
| NaN and Infinity in numeric, real and double precision | NULLMariaDB 的数字没有 NaN 或 Infinity,因此这些值变为 NULL,报告会统计其数量。 | invalid_value_null |
| NOT NULL columns with values that become NULL | 去除 NOT NULL值必须变为 NULL 的列无法保留 NOT NULL,否则导入会中止。 | not_null_relaxed |
| enum types | enum(...),标签相同MariaDB 的 ENUM 按原顺序保留标签。 | |
| uuid, inet, cidr | uuid 为 uuid,inet 和 cidr 为 varchar(43)MariaDB 有 uuid 类型;地址保留其文本,包括掩码。 | |
| bytea | blob、mediumblob 或 longblob;键中为 varbinary(3072)字节仍然是字节。 | |
| bit(n) | 不超过 64 位时为 bit(n),更长则为文本不超过 64 位的位串存为其各位组成的数字;更长的位串保留其数字。 | |
| citext and nondeterministic collations | 精确比较表使用 utf8mb4_bin,因此文本像 PostgreSQL 一样精确比较;源数据中不区分大小写的列会失去这一点。 | case_insensitive_collation |
| serial, identity | AUTO_INCREMENT,从最大的 id 之后继续由主键的第一列计数;计数器从序列所在的位置继续。 | |
| a second serial or identity column in a table | 普通整数MariaDB 每个表只为一列计数;其他列保留其值,不带计数器。 | counter_dropped |
| sequences not owned by a column | CREATE SEQUENCE,从它下一个要分配的值开始MariaDB 序列的工作方式相同。 | |
| generated columns | 生成列,与源数据一样为 STOREDMariaDB 以相同方式计算它们。 | |
| generated columns with functions MariaDB lacks | 普通列无法为 MariaDB 写出的公式会留下一个普通列和一条报告记录。 | generated_not_translated |
| defaults with functions MariaDB lacks, and defaults from a sequence | 无默认值无法为 MariaDB 写出的默认值会被省略,并在报告中列出。 | default_not_translated |
| CHECK constraints | 已转换,内联在 CREATE TABLE 中MySQL 8.0.16 和 MariaDB 会执行它们;MySQL 5.7 保留它们但不检查。 | |
| CHECK constraints with functions MariaDB lacks | 不创建无法为 MariaDB 写出的检查约束会被省略,并在报告中列出。 | check_skipped |
| CHECK ... NOT VALID | 不创建PostgreSQL 从未检查之前已有的行,因此它们可能违反该约束。 | check_not_valid |
| gin, gist, brin and hash indexes, partial and expression indexes | 不创建MariaDB 只有 b-tree、全文和空间索引,建立在整列上,不带 WHERE。 | index_skipped |
| foreign keys | 外键,以 FOREIGN_KEY_CHECKS=0 导入行可以按任意顺序导入,之后外键会检查新行。 | |
| foreign keys to tables the dump doesn't create | 不创建外键无法引用不存在的表。 | foreign_key_skipped |
| partitioned tables | 单个表,包含每个分区的行行保持不变;如有需要,请在 MariaDB 中重新对该表分区。 | partitions_dropped |
| schemas | 单个数据库,每个表名前加上其 schema 名MariaDB 的 schema 就是数据库,而导入到单个数据库的脚本无法创建数据库;public 中的表保留原名。 | schemas_merged |
| views, functions, procedures, triggers, rules, policies, extensions and types | 在报告中列出它们的代码用 PostgreSQL 的语言编写,因此会列出来,由你重新创建。 | not_converted_objects |
| dumps without CREATE TABLE (--data-only) | 根据值推断类型只含数据的转储只有行,因此类型来自值。 | no_schema |
| expressions in INSERT values | NULL不运行数据库的转换器无法对它们求值。 | expression_value |
| types IntoSQL doesn't know | longtext文本可以容纳任何值;请在导入后更改类型。 | unknown_type |
| text that isn't valid in its encoding | 错误的字节变为替换字符文本必须是有效的 utf8mb4。 | invalid_utf8_replaced |
| text decoded twice (ñ) | 按原样复制转储中存储的正是这些字符,因此按原样复制;报告会指出它们。 | mojibake_suspected |
将脚本导入 MariaDB
脚本先创建表、复制行,再添加键、索引和外键,因此导入速度快,并会在遇到第一个错误时停止。
mariadb --default-character-set=utf8mb4 mydb < postgresql.mariadb.sql外键按转储中的声明创建,导入行时使用 FOREIGN_KEY_CHECKS=0,与 mysqldump 的做法相同。
对于较大的转储,请在服务器所在的机器上运行客户端;如果单行非常大,请调高 max_allowed_packet。
IntoSQL Pro 可以通过桌面应用或命令行将文件直接导入 MariaDB,无需生成脚本。
如何转储 PostgreSQL 以获得最佳结果
转换器读取转储中的内容。以下选项能让转储保留更多数据:
- --format=plain 是 pg_dump 的默认格式,写出 SQL。custom 或 directory 归档(-Fc、-Fd)可用 pg_restore -f dump.sql 转为 SQL,无需数据库服务器。
- --no-owner --no-privileges 会省略角色和授权,转换器本来也会跳过它们,因此转储更小。
- pg_dumpall 将每个数据库转储到一个文件中;每个数据库的表名前会加上该数据库名,因此不会冲突。
哪些内容不会转换
视图、物化视图、函数、存储过程、触发器、规则、行安全策略、扩展和类型都是用 PostgreSQL 自己的语言编写的。它们会按名称在报告中列出,绝不会被悄悄丢弃,以便你为 MariaDB 重写。
关于 PostgreSQL 转 MariaDB 的问题
这里没有你要的答案?请通过联系页面给我们留言,会有专人回复。 联系页面
我的转储会被上传吗?
不会。转换器在你的浏览器中运行,分块从磁盘读取转储,因此转储不会离开你的电脑。桌面应用和命令行也在你的电脑上转换。
转储可以多大?
转换器从不把整个转储放进内存:它按范围读取文件两次,边读边写出脚本。几 GB 的转储可以在浏览器、桌面应用和命令行中转换。
它能读取 pg_dump -Fc 归档吗?
不能直接读取:custom 归档是二进制格式。pg_restore -f dump.sql dump.backup 会将其转为转换器读取的纯 SQL,无需连接服务器。转换器收到归档时会给出提示。
转储可以来自哪些 PostgreSQL 版本?
由 PostgreSQL 10 及更高版本的 pg_dump 和 pg_dumpall 写出的转储,行可以是 COPY 或 INSERT。每个测试转储都来自 PostgreSQL 13 和 18,并与其源数据逐个单元格比较。
serial 和标识列的值会保留吗?
会,每个表一列:作为主键第一列的 serial 或标识列变为 AUTO_INCREMENT,从最大的 id 之后继续。不属于任何列的序列变为 MariaDB 序列,从它们已达到的值开始。
数组、enum 和其他 PostgreSQL 类型会怎样处理?
数组变为 JSON 数组,布尔值变为 tinyint(1),enum 变为标签相同的 ENUM,uuid 变为 UUID,money 变为 decimal。range、几何类型、hstore 和复合类型保留 PostgreSQL 的文本,报告会说明是哪些列。
函数、触发器和视图怎么处理?
它们会按名称在报告中列出,但不会转换,因为每种数据库都用自己的语言编写它们。
脚本可以导入哪些 MariaDB 版本?
MariaDB 10.11 及更高版本。每个测试转储都能在 10.11 和 11.4 上导入,如有问题会在第一个错误处停止。