跳到正文
IntoSQL 首页

将 PostgreSQL 转储迁移到更旧或更新的 PostgreSQL

拖入由 pg_dump 或 pg_dumpall 生成的纯文本转储,格式为 .sql 或 .sql.gz,无论转储来自哪个版本,都能下载一个可在 PostgreSQL 13 到 18 导入的脚本。标识列、枚举、数组和 jsonb 保持不变,扩展带来的类型变为文本,每项更改都会列在报告中。

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

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

显示

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

  • customers8 行
    8 列
    idinteger not null
    nametext not null
    emailtext not null
    countryvarchar(2) not null
    is_activeboolean not null
    tagstext[] not null
    signed_update
    created_attimestamptz(6) not null
  • orders10 行
    10 列
    idinteger not null
    customer_idinteger not null
    statusorder_status not null
    totalnumeric(10,2) not null
    itemssmallint not null
    ordered_attimestamp(6) not null
    shipped_attimestamp(6)
    notetext
    detailsjsonb
    deliveryinterval

未转换

  • 视图 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相同的类型和值类型相同:每一位数字都按转储的写法复制。
moneynumeric(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 multirangestext,存放 PostgreSQL 的文本脚本既不创建扩展,也不创建复合类型,因此每个值保留 PostgreSQL 写出的文本;请在导入后创建该类型并修改该列。type_replaced
citexttext,精确比较脚本不创建 citext 扩展,因此这些列精确比较文本;请在导入后创建该扩展,并将这些列改回原类型。case_insensitive_collation
json, jsonb相同的类型json 按写入的原样保留文本;jsonb 保留服务器规范化后的值。
timestamp with time zonetimestamptz,时刻相同每个值保留转储写入的偏移量,因此在任何时区都是同一时刻。
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 valuesNULL不运行数据库的转换器无法对它们求值。expression_value
types IntoSQL doesn't knowtext文本可以容纳任何值;请在导入后更改类型。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,无论转储由哪个版本写出。同一个脚本在每个版本上都能导入,如有问题会在第一个错误处停止。