将数据库转换为另一种数据库
拖入由 mysqldump、mariadb-dump、pg_dump、SSMS、SQL Developer 或 SQLcl 生成的转储,或 SQLite .db 文件,即可下载适用于 PostgreSQL、MySQL、MariaDB、SQLite、SQL Server 或 Oracle 的脚本,表、键、索引和数据都相同。每项更改都会列在报告中,转储不会离开你的电脑。
已转换 18 行,8 处修正,无拒绝
shop_2024.sql 中的表MySQL 8.0.46 转储 · 由 mysqldump 写出 · utf8mb4
customers8 行3
7 列 id bigint not null name varchar(100) not null email varchar(150) not null country varchar(2) not null is_active boolean not null signed_up date created_at timestamptz(0) not null orders10 行5
9 列 id bigint not null customer_id bigint not null status text not null total numeric(10,2) not null items integer not null ordered_at timestamp(0) not null shipped_at timestamp(0) note varchar(255) updated_at timestamptz(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();
修正
- customers 的 "id" 是无符号的,因此变为 bigint,并带有不能为负数的检查约束。
- customers 的 "signed_up" 现在允许 NULL:它的部分值无法存储,已设为 NULL。
- customers 中 "signed_up" 的默认值 0000‑00‑00 不是 PostgreSQL 接受的日期,因此该列没有默认值。
- orders 的 "customer_id" 是无符号的,因此变为 bigint,并带有不能为负数的检查约束。
- orders 的 "id" 是无符号的,因此变为 bigint,并带有不能为负数的检查约束。
- orders 的 "items" 是无符号的,因此变为 integer,并带有不能为负数的检查约束。
- orders 中 "status" 有 1 行包含 MySQL 为无效输入存储的空值;对其值的检查约束允许该值。
- orders 的 "updated_at" 在每次更新时变为当前时间;在 PostgreSQL 中由触发器完成。
需要检查
- customers 的 "signed_up" 中有 1 个值是零日期或不可能的日期,例如 0000‑00‑00,PostgreSQL 无法存储,因此设为 NULL。 如果这些日期有意义,请在转储前于源数据中替换为真实日期。
- orders 的 "shipped_at" 中有 1 个值是零日期或不可能的日期,例如 0000‑00‑00 00:00:00,PostgreSQL 无法存储,因此设为 NULL。 如果这些日期有意义,请在转储前于源数据中替换为真实日期。
文件在这台电脑上转换,永远不会上传。
其他示例:
所有数据库组合
行是转储来源的数据库,列是脚本面向的数据库。每个组合都有自己的页面,提供为其设置好的转换器、适用的规则以及导入脚本的方法。
- MySQL
- MariaDB
- PostgreSQL
- SQL Server
- SQLite
- Oracle
保留什么,报告什么
转换器无需数据库服务器,直接读取转储,并根据其内容写出脚本。每个组合的页面列出它适用的规则 (每个组合 25 到 67 条),以及每条规则写入报告的内容。
保留在脚本中
- 表和列,各自使用目标中最接近的类型,并保留长度和精度。
- 主键、唯一键、外键、索引和默认值。
- AUTO_INCREMENT、标识列和 serial 列,保留每行的 ID,计数器从转储停下的地方继续。
- 每一行,日期、小数、文本和二进制值与转储中一致。
列在报告中
- 目标无法原样存储的值,例如 PostgreSQL 中的 0000-00-00 日期,并注明所在列和数量。
invalid_date_null - 目标没有的类型,例如 ENUM 或 INET6,以及各自转换后的类型。
type_replaced - 视图、触发器、存储过程、函数和事件,按名称列出:它们用各数据库自己的语言编写,因此不做转换。
not_converted_objects - 在其字符集中无效的文本,以及已经丢失 4 字节字符的转储。
invalid_utf8_replaced
与 pgloader 的实测对比
2026 年 10 月,在同一台机器(10 核 i9-10900K,配 SATA SSD)上,用 IntoSQL 和 pgloader 3.6.7 转换并导入相同的转储。
- 一个包含 2、-1 和 -5 的 TINYINT(1) 列:pgloader 将每个值都导入为 true,且没有警告。IntoSQL 保留这些数字,报告会说明原因。
- 一个转储包含默认值 'it's'、名称带反引号的表、包含空值的 ENUM 以及超过 24 小时的 TIME:pgloader 会中止。IntoSQL 能转换并导入它。
- pgloader 导入的结果丢失了主键、唯一键、外键和标识列。IntoSQL 全部保留。
- 一个 5.3 GB、3000 万行的转储:pgloader 需要先将其恢复到运行中的 MySQL,耗时 18 分钟,之后在默认设置下内存不足。IntoSQL 在 10 秒内转换该转储,psql 导入脚本约需 3 分钟。
- 476 个来自 MySQL 5.5 到 9 和 MariaDB 10.3 到 12 的转储,导入 PostgreSQL 13 和 18:没有导入错误,也没有任何值在报告中无记录的情况下被更改。
导出你的数据库
转换器读取的是文件,而不是正在运行的服务器。每种数据库都用自己的工具写出文件:
MySQL
由 mysqldump、mysqlpump、phpMyAdmin 或 Adminer 生成的转储,格式为 .sql 或 .sql.gz。使用 --default-character-set=utf8mb4 --hex-blob --routines --triggers --events 可保留最多内容。
MySQL 到 PostgreSQL 迁移指南MariaDB
由 mariadb-dump、mysqldump、phpMyAdmin 或 Adminer 生成的转储,格式为 .sql 或 .sql.gz,选项与 MySQL 相同。
MariaDB 到 PostgreSQL 迁移指南PostgreSQL
由 pg_dump 或 pg_dumpall 生成的纯文本转储。自定义归档 (-Fc) 可用 pg_restore -f dump.sql 转为纯文本,无需服务器。
PostgreSQL 到 MySQL 迁移指南SQL Server
SSMS 的生成脚本功能写出的脚本,需将要编写脚本的数据类型设为架构和数据。dbatools 和 mssql-scripter 写出的也一样。
SQL Server 到 PostgreSQL 迁移指南SQLite
数据库文件本身 (.db、.sqlite、.sqlite3),或 sqlite3 app.db .dump 写出的 SQL。
SQLite 到 PostgreSQL 迁移指南Oracle
SQL Developer 的数据库导出或 SQLcl 写出的 .sql 文件,包含 DDL 和 Insert 语句。来自 exp 或 expdp 的 .dmp 文件需要先导入再重新导出。
Oracle 到 PostgreSQL 迁移指南
关于数据库迁移的问题
这里没有你要的答案?请通过联系页面给我们留言,会有专人回复。 联系页面
我的转储会被上传吗?
不会。转换器在你的浏览器中运行,分块从磁盘读取转储,因此转储不会离开你的电脑。桌面应用和命令行也在你的电脑上转换。
转储可以多大?
转换器从不把整个转储放进内存:它按范围读取文件两次,边读边写出脚本。几 GB 的转储可以在浏览器、桌面应用和命令行中转换。
转储可以来自哪些版本?
MySQL 5.5 到 9、MariaDB 10.3 到 12、PostgreSQL 10 及以上、SQL Server 2017 及以上、SQLite 3.0 及以上,以及 Oracle 11g 及以上。每个组合的页面会说明其脚本可导入哪些版本。
需要正在运行的数据库服务器吗?
不需要。转换器直接读取转储文件,源数据库无需在任何地方运行。脚本可用目标自带的客户端导入,例如 psql、mysql 或 sqlcmd。
哪些内容不会被转换?
视图、触发器、存储过程、函数和事件用各数据库自己的语言编写,因此改为按名称列在报告中。表、键、索引和行都在脚本中。
可以把脚本直接导入我的数据库吗?
桌面应用和 intosql load 命令可免费直接写入 SQLite,使用 IntoSQL Pro 可直接写入 PostgreSQL、MySQL 和 MariaDB。SQL Server 和 Oracle 请用 sqlcmd 或 sqlplus 运行脚本。