跳到正文
IntoSQL 首页

将 PostgreSQL 转换为 MariaDB

拖入由 pg_dump 或 pg_dumpall 生成的纯文本转储(.sql 或 .sql.gz),即可下载包含相同表、键、索引和数据的 MariaDB 脚本。MariaDB 无法原样存储的每个值,以及它不支持的每个对象,都会在报告中列出。

你的文件
sqlshop_2024_postgres.sql示例文件,6.2 kB
你的数据库

已转换 18 行,3 处修正,无拒绝

显示

shop_2024_postgres.sql 中的表PostgreSQL 18.6 转储 · 由 pg_dump 写出 · utf8mb4

  • customers8 行2
    8 列
    idint not null
    nametext not null
    emailvarchar(768) not null
    countrychar(2) not null
    is_activetinyint(1) not null
    tagsjson not null
    signed_update
    created_atdatetime(6) not null
  • orders10 行1
    10 列
    idint not null
    customer_idint not null
    statusenum('pending','paid','shipped','cancelled') not null
    totaldecimal(10,2) not null
    itemssmallint not null
    ordered_atdatetime(6) not null
    shipped_atdatetime(6)
    notetext
    detailsjson
    deliveryvarchar(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;

修正

  1. customers 的 "created_at" 包含带时区的时间点;MariaDB 没有能保留时区的类型,因此以 UTC 存储为 datetime(6)。
  2. customers 的 "tags" 是 text[],MariaDB 没有该类型,因此为 json,值保持不变。
  3. 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 中报告记录
booleantinyint(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) holdsvarcharMariaDB 的 decimal 可容纳 65 位数字,其中 30 位小数。更宽的数字保存为文本,使每一位都保持精确;不带精度的 numeric 在其值能容纳时为 decimal(65,30)。decimal_as_text
moneydecimal(19,2)MariaDB 没有 money 类型。金额保存为数字,不带服务器区域设置添加的货币符号。type_replaced
intervalvarchar(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 typeslongtext,存放 PostgreSQL 的文本MariaDB 没有对应的类型,因此每个值保留 PostgreSQL 写出的文本。type_replaced
json, jsonbjsonJSON 值相同;jsonb 的键顺序和空格由服务器决定。
timestampdatetime(p)不带时区的 timestamp 是挂钟读数,与 datetime 相同。
timestamp with time zoneUTC 的 datetime(p)MariaDB 的 TIMESTAMP 只到 2038 年,因此时间点以 UTC 存储为 datetime;无论转储写入的偏移量是多少,都是同一时刻。moments_as_utc
timetime(p)MariaDB 的 TIME 可容纳一天中的每个时刻,包括 24:00:00。
infinity, -infinity, BC dates and years past 9999NULLMariaDB 存储 1000 到 9999 年,不支持无穷值。这些值变为 NULL,报告会统计其数量。date_out_of_range
NaN and Infinity in numeric, real and double precisionNULLMariaDB 的数字没有 NaN 或 Infinity,因此这些值变为 NULL,报告会统计其数量。invalid_value_null
NOT NULL columns with values that become NULL去除 NOT NULL值必须变为 NULL 的列无法保留 NOT NULL,否则导入会中止。not_null_relaxed
enum typesenum(...),标签相同MariaDB 的 ENUM 按原顺序保留标签。
uuid, inet, cidruuid 为 uuid,inet 和 cidr 为 varchar(43)MariaDB 有 uuid 类型;地址保留其文本,包括掩码。
byteablob、mediumblob 或 longblob;键中为 varbinary(3072)字节仍然是字节。
bit(n)不超过 64 位时为 bit(n),更长则为文本不超过 64 位的位串存为其各位组成的数字;更长的位串保留其数字。
citext and nondeterministic collations精确比较表使用 utf8mb4_bin,因此文本像 PostgreSQL 一样精确比较;源数据中不区分大小写的列会失去这一点。case_insensitive_collation
serial, identityAUTO_INCREMENT,从最大的 id 之后继续由主键的第一列计数;计数器从序列所在的位置继续。
a second serial or identity column in a table普通整数MariaDB 每个表只为一列计数;其他列保留其值,不带计数器。counter_dropped
sequences not owned by a columnCREATE 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 valuesNULL不运行数据库的转换器无法对它们求值。expression_value
types IntoSQL doesn't knowlongtext文本可以容纳任何值;请在导入后更改类型。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 上导入,如有问题会在第一个错误处停止。