将 PostgreSQL 转储迁移到更旧或更新的 PostgreSQL
拖入由 pg_dump 或 pg_dumpall 生成的纯文本转储,格式为 .sql 或 .sql.gz,无论转储来自哪个版本,都能下载一个可在 PostgreSQL 13 到 18 导入的脚本。标识列、枚举、数组和 jsonb 保持不变,扩展带来的类型变为文本,每项更改都会列在报告中。
已转换 18 行,无修正,无拒绝
shop_2024_postgres.sql 中的表PostgreSQL 18.6 转储 · 由 pg_dump 写出 · utf8mb4
customers8 行
8 列 id integer not null name text not null email text not null country varchar(2) not null is_active boolean not null tags text[] not null signed_up date created_at timestamptz(6) not null orders10 行
10 列 id integer not null customer_id integer not null status order_status not null total numeric(10,2) not null items smallint not null ordered_at timestamp(6) not null shipped_at timestamp(6) note text details jsonb delivery interval
未转换
- 视图 paid_orders
每种数据库都用自己的语言编写这些对象。请为 PostgreSQL 重写它们。
-- Written by IntoSQL from a PostgreSQL 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 TYPE order_status AS ENUM ('pending', 'paid', 'shipped', 'cancelled');
CREATE TABLE customers (
id integer GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name text NOT NULL,
email text NOT NULL,
country varchar(2) DEFAULT 'US' NOT NULL,
is_active boolean DEFAULT true NOT NULL,
tags text[] DEFAULT '{}' NOT NULL,
signed_up date,
created_at timestamptz(6) DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE TABLE orders (
id integer GENERATED BY DEFAULT AS IDENTITY NOT NULL,
customer_id integer NOT NULL,
status order_status DEFAULT 'pending' NOT NULL,
total numeric(10,2) NOT NULL,
items smallint DEFAULT 1 NOT NULL,
ordered_at timestamp(6) NOT NULL,
shipped_at timestamp(6),
note text,
details jsonb,
delivery interval,
CONSTRAINT orders_total_check CHECK (total >= (0))
);
COPY customers (id, name, email, country, is_active, tags, signed_up, created_at) FROM stdin;
1 Ana Martínez ana@example.com MX t {vip} 2023-01-15 2023-01-15 10:24:00+00
2 Zoë Müller zoe@example.de DE t {} 2023-02-03 2023-02-03 08:11:42+00
3 José Peña jose@example.es ES f {wholesale,"late payer"} 2023-03-21 2023-03-21 19:05:17+00
4 李雷 lilei@example.cn CN t {} 2023-05-09 2023-05-09 02:40:00+00
5 Noah O'Brien noah@example.ie IE t {} \N 2023-06-30 14:00:00+00
6 Amélie Laurent amelie@example.fr FR t {vip} 2024-01-02 2024-01-02 09:30:00+00
7 Ravi Patel ravi@example.in IN f {} 2024-02-29 2024-02-29 23:59:59+00
8 Sofia Rossi 🌻 sofia@example.it IT t {} 2024-04-12 2024-04-12 12:12:12+00
\.
COPY orders (id, customer_id, status, total, items, ordered_at, shipped_at, note, details, delivery) FROM stdin;
1 1 shipped 129.90 3 2024-03-01 10:00:00 2024-03-02 16:30:00 \N {"gift": false} 1 day 06:30:00
2 2 paid 54.00 1 2024-03-02 11:15:00 \N Gift wrap 🎁 {"gift": true, "wrap": "red"} \N
3 1 cancelled 12.50 1 2024-03-03 09:45:00 \N Customer changed their mind \N \N
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 \N Leave at the door; ring twice \N \N
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 \N \N \N \N
8 2 shipped 19.99 1 2024-03-12 08:00:00 infinity Shipped date set to infinity by an old import \N \N
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 \N C:\\Users\\ravi\\invoice.pdf \N \N
\.
-- Keys, indexes and constraints, after the rows so each builds once.
CREATE UNIQUE INDEX customers_email_key ON customers (email);
CREATE UNIQUE INDEX customers_pkey ON customers (id);
CREATE UNIQUE INDEX orders_pkey ON orders (id);
CREATE INDEX idx_orders_customer ON orders (customer_id);
CREATE INDEX idx_orders_status_date ON orders (status, ordered_at);
ALTER TABLE customers ADD CONSTRAINT customers_email_key UNIQUE USING INDEX customers_email_key;
ALTER TABLE customers ADD CONSTRAINT customers_pkey PRIMARY KEY USING INDEX customers_pkey;
ALTER TABLE orders ADD CONSTRAINT orders_pkey PRIMARY KEY USING INDEX orders_pkey;
ALTER TABLE orders ADD CONSTRAINT orders_customer_id_fkey FOREIGN KEY (customer_id) REFERENCES customers (id) NOT VALID;
DO $f$ BEGIN
ALTER TABLE orders VALIDATE CONSTRAINT orders_customer_id_fkey;
EXCEPTION WHEN foreign_key_violation THEN
RAISE WARNING 'foreign key % has rows without a parent: it stays NOT VALID, and new rows are checked', 'orders_customer_id_fkey';
END $f$;
SELECT setval(pg_get_serial_sequence('customers', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM customers)::numeric, 0) + 1, 1001), 2147483647)::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), 2147483647)::bigint, false);
修正
没有需要修正的内容。
需要检查
- 1 个视图、触发器、例程或事件未转换;报告逐一列出了它们。 请在 PostgreSQL 中手动重新创建它们。
- orders 上的索引 idx_orders_details 使用了无法为 PostgreSQL 写出的表达式(a gin index),因此未创建。 如果查询需要,请手动创建该索引。
文件在这台电脑上转换,永远不会上传。
其他示例:
文件与脚本之间的变化
每一行是转换器应用的一条规则,以及该规则更改你的数据时在报告中写入的记录。
varchar(n), char(n), text
相同的类型
相同的类型,长度也相同。
numeric(p,s), numeric without a precision, NaN and Infinity
相同的类型和值
类型相同:每一位数字都按转储的写法复制。
money
numeric(19,2)
money 的写法取决于服务器的 lc_monetary,因此金额保存为不带货币符号的数字,无论目标的区域设置如何都能导入。
报告记录: type_replaced
enum types
相同的 enum 类型,在表之前创建
标签保持原顺序。
enum columns holding values outside their labels
不加检查约束的 text
该类型会拒绝这些值,因此该列为 text,保留全部值。
报告记录: enum_check_skipped
composite and range types the dump defines, extension types (citext, hstore, ltree, PostGIS) and multiranges
text,存放 PostgreSQL 的文本
脚本既不创建扩展,也不创建复合类型,因此每个值保留 PostgreSQL 写出的文本;请在导入后创建该类型并修改该列。
报告记录: type_replaced
citext
text,精确比较
脚本不创建 citext 扩展,因此这些列精确比较文本;请在导入后创建该扩展,并将这些列改回原类型。
报告记录: case_insensitive_collation
json, jsonb
相同的类型
json 按写入的原样保留文本;jsonb 保留服务器规范化后的值。
timestamp with time zone
timestamptz,时刻相同
每个值保留转储写入的偏移量,因此在任何时区都是同一时刻。
time, time with time zone
相同的类型
相同的类型,包括 24:00:00。
infinity, -infinity and BC dates
保留
PostgreSQL 按原样保存它们。
NaN and Infinity in numeric, real and double precision
保留
PostgreSQL 按原样保存它们。
generated columns
相同的生成列
公式相同,由目标数据库计算。
generated columns with functions IntoSQL doesn't write
带有这些值的普通列
IntoSQL 无法写出的公式会留下一个带有转储中值的普通列和一条报告记录。
报告记录: generated_not_translated
defaults with functions IntoSQL doesn't write
无默认值
IntoSQL 无法写出的默认值会被省略,并在报告中列出。
报告记录: default_not_translated
CHECK constraints with functions IntoSQL doesn't write
不创建
IntoSQL 无法写出的检查约束会被省略,并在报告中列出。
报告记录: check_skipped
CHECK ... NOT VALID
在行之后以 NOT VALID 添加
之前已有的行从未被检查,因此检查约束在这些行之后添加,仍为未验证状态。
gin, gist, brin and hash indexes, partial and expression indexes
不创建
IntoSQL 在列上写出 b-tree 索引;其他索引请在导入后重新创建。
报告记录: index_skipped
foreign keys to tables the dump doesn't create
不创建
外键无法引用不存在的表。
报告记录: foreign_key_skipped
NOT NULL columns with values that become NULL
去除 NOT NULL
值必须变为 NULL 的列无法保留 NOT NULL,否则导入会中止。
报告记录: not_null_relaxed
partitioned tables
单个表,包含每个分区的行
行保持不变;如有需要,请重新对该表分区。
报告记录: partitions_dropped
views, functions, procedures, triggers, rules, policies, extensions and types other than enums
在报告中列出
IntoSQL 转换表及其行;其余对象会列出来,由你重新创建。
报告记录: not_converted_objects
dumps without CREATE TABLE (--data-only)
根据值推断类型
只含数据的转储只有行,因此类型来自值。
报告记录: no_schema
expressions in INSERT values
NULL
不运行数据库的转换器无法对它们求值。
报告记录: expression_value
types IntoSQL doesn't know
text
文本可以容纳任何值;请在导入后更改类型。
报告记录: unknown_type
text that isn't valid in its encoding
错误的字节变为替换字符
PostgreSQL 文本必须是有效的 UTF-8。
报告记录: invalid_utf8_replaced
text decoded twice (ñ)
按原样复制
转储中存储的正是这些字符,因此按原样复制;报告会指出它们。
报告记录: mojibake_suspected
| 文件中 | 脚本中 | 报告记录 |
|---|---|---|
| varchar(n), char(n), text | 相同的类型相同的类型,长度也相同。 | |
| numeric(p,s), numeric without a precision, NaN and Infinity | 相同的类型和值类型相同:每一位数字都按转储的写法复制。 | |
| money | numeric(19,2)money 的写法取决于服务器的 lc_monetary,因此金额保存为不带货币符号的数字,无论目标的区域设置如何都能导入。 | type_replaced |
| enum types | 相同的 enum 类型,在表之前创建标签保持原顺序。 | |
| enum columns holding values outside their labels | 不加检查约束的 text该类型会拒绝这些值,因此该列为 text,保留全部值。 | enum_check_skipped |
| composite and range types the dump defines, extension types (citext, hstore, ltree, PostGIS) and multiranges | text,存放 PostgreSQL 的文本脚本既不创建扩展,也不创建复合类型,因此每个值保留 PostgreSQL 写出的文本;请在导入后创建该类型并修改该列。 | type_replaced |
| citext | text,精确比较脚本不创建 citext 扩展,因此这些列精确比较文本;请在导入后创建该扩展,并将这些列改回原类型。 | case_insensitive_collation |
| json, jsonb | 相同的类型json 按写入的原样保留文本;jsonb 保留服务器规范化后的值。 | |
| timestamp with time zone | timestamptz,时刻相同每个值保留转储写入的偏移量,因此在任何时区都是同一时刻。 | |
| time, time with time zone | 相同的类型相同的类型,包括 24:00:00。 | |
| infinity, -infinity and BC dates | 保留PostgreSQL 按原样保存它们。 | |
| NaN and Infinity in numeric, real and double precision | 保留PostgreSQL 按原样保存它们。 | |
| generated columns | 相同的生成列公式相同,由目标数据库计算。 | |
| generated columns with functions IntoSQL doesn't write | 带有这些值的普通列IntoSQL 无法写出的公式会留下一个带有转储中值的普通列和一条报告记录。 | generated_not_translated |
| defaults with functions IntoSQL doesn't write | 无默认值IntoSQL 无法写出的默认值会被省略,并在报告中列出。 | default_not_translated |
| CHECK constraints with functions IntoSQL doesn't write | 不创建IntoSQL 无法写出的检查约束会被省略,并在报告中列出。 | check_skipped |
| CHECK ... NOT VALID | 在行之后以 NOT VALID 添加之前已有的行从未被检查,因此检查约束在这些行之后添加,仍为未验证状态。 | |
| gin, gist, brin and hash indexes, partial and expression indexes | 不创建IntoSQL 在列上写出 b-tree 索引;其他索引请在导入后重新创建。 | index_skipped |
| foreign keys to tables the dump doesn't create | 不创建外键无法引用不存在的表。 | foreign_key_skipped |
| NOT NULL columns with values that become NULL | 去除 NOT NULL值必须变为 NULL 的列无法保留 NOT NULL,否则导入会中止。 | not_null_relaxed |
| partitioned tables | 单个表,包含每个分区的行行保持不变;如有需要,请重新对该表分区。 | partitions_dropped |
| views, functions, procedures, triggers, rules, policies, extensions and types other than enums | 在报告中列出IntoSQL 转换表及其行;其余对象会列出来,由你重新创建。 | not_converted_objects |
| dumps without CREATE TABLE (--data-only) | 根据值推断类型只含数据的转储只有行,因此类型来自值。 | no_schema |
| expressions in INSERT values | NULL不运行数据库的转换器无法对它们求值。 | expression_value |
| types IntoSQL doesn't know | text文本可以容纳任何值;请在导入后更改类型。 | unknown_type |
| text that isn't valid in its encoding | 错误的字节变为替换字符PostgreSQL 文本必须是有效的 UTF-8。 | invalid_utf8_replaced |
| text decoded twice (ñ) | 按原样复制转储中存储的正是这些字符,因此按原样复制;报告会指出它们。 | mojibake_suspected |
将脚本导入 PostgreSQL
脚本先创建表、复制行,再添加键、索引和外键,因此导入速度快,并会在遇到第一个错误时停止。
psql -v ON_ERROR_STOP=1 -d mydb -f postgresql.postgresql.sql外键先以 NOT VALID 添加,然后再验证。如果某行指向不存在的行,脚本会告诉你是哪个约束,而不是中途失败。
对于较大的转储,请先创建数据库,然后在服务器所在的机器上用 psql 运行脚本。
IntoSQL Pro 可以通过桌面应用或命令行将文件直接导入 PostgreSQL,无需生成脚本。
如何转储 PostgreSQL 以获得最佳结果
转换器读取转储中的内容。以下选项能让转储保留更多数据:
- --format=plain 是 pg_dump 的默认格式,写出 SQL。custom 或 directory 归档(-Fc、-Fd)可用 pg_restore -f dump.sql 转为 SQL,无需数据库服务器。
- --no-owner --no-privileges 会省略角色和授权,转换器本来也会跳过它们,因此转储更小。
- pg_dumpall 将每个数据库转储到一个文件中;每个数据库的表名前会加上该数据库名,因此不会冲突。
哪些内容不会转换
视图、触发器、存储过程、函数等用 PostgreSQL 自己的语言编写的对象,会按名称列在报告中,绝不会被悄悄丢弃,你可以先在要导入的 PostgreSQL 版本上逐一检查再重建。
关于在 PostgreSQL 版本之间迁移的问题
这里没有你要的答案?请通过联系页面给我们留言,会有专人回复。 联系页面
我的转储会被上传吗?
不会。转换器在你的浏览器中运行,分块从磁盘读取转储,因此转储不会离开你的电脑。桌面应用和命令行也在你的电脑上转换。
转储可以多大?
转换器从不把整个转储放进内存:它按范围读取文件两次,边读边写出脚本。几 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 和标识列保持为标识列,每行保留其 id,每个计数器从转储中序列已达到的值继续。
数组、enum 和其他 PostgreSQL 类型会怎样处理?
它们保持原样:数组、range、json 和 jsonb、位串,money 除外。enum 类型会以其标签重新创建。扩展带来的类型(citext、hstore、PostGIS)和复合类型变为文本,报告会说明是哪些列。
函数、触发器和视图怎么处理?
它们会按名称在报告中列出,但不会转换,以便你在表导入后重新创建。NOT VALID 检查约束在行之后添加,仍为未验证状态。
脚本可以导入哪些 PostgreSQL 版本?
PostgreSQL 13 到 18,无论转储由哪个版本写出。同一个脚本在每个版本上都能导入,如有问题会在第一个错误处停止。