跳到正文
IntoSQL 首页

将 Oracle 转换为 PostgreSQL

拖入 SQL Developer 的 Database Export 或 SQLcl 写出的 .sql 文件(包含表和 Insert 语句),即可下载包含相同表、键、索引和数据的 PostgreSQL 脚本。PostgreSQL 无法原样存储的每个值,以及它不支持的每个对象,都会在报告中列出。

你的文件
sqlshop_2024_oracle.sql示例文件,9.3 kB
你的数据库

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

显示

shop_2024_oracle.sql 中的表Oracle 转储 · 由 SQL Developer 写出 · utf-8

  • customers8 行
    7 列
    idbigint not null
    namevarchar(100) not null
    emailvarchar(150) not null
    countryvarchar(2) not null
    is_activesmallint not null
    signed_uptimestamp(0)
    created_attimestamp(0) not null
  • orders10 行
    9 列
    idbigint not null
    customer_idbigint not null
    invoicebigint
    statusvarchar(10) not null
    totalnumeric(10,2) not null
    itemsinteger not null
    ordered_attimestamp(0) not null
    shipped_attimestamp(0)
    notevarchar(255)
-- Written by IntoSQL from a Oracle 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 SEQUENCE invoice_numbers INCREMENT BY 1 MINVALUE 1 START WITH 1020;
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 smallint DEFAULT 1 NOT NULL,
    signed_up timestamp(0),
    created_at timestamp(0) DEFAULT LOCALTIMESTAMP NOT NULL,
    CONSTRAINT customers_check1 CHECK (is_active IN (0, 1))
);

CREATE TABLE orders (
    id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
    customer_id bigint NOT NULL,
    invoice bigint DEFAULT (nextval('invoice_numbers')),
    status varchar(10) 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),
    CONSTRAINT orders_check1 CHECK (status IN ('pending', 'paid', 'shipped', 'cancelled'))
);

COPY customers (id, name, email, country, is_active, signed_up, created_at) FROM stdin;
1	Ana Martínez	ana@example.com	MX	1	2023-01-15 00:00:00	2023-01-15 10:24:00.000000
2	Zoë Müller	zoe@example.de	DE	1	2023-02-03 00:00:00	2023-02-03 08:11:42.000000
3	José Peña	jose@example.es	ES	0	2023-03-21 00:00:00	2023-03-21 19:05:17.000000
4	李雷	lilei@example.cn	CN	1	2023-05-09 00:00:00	2023-05-09 02:40:00.000000
5	Noah O'Brien	noah@example.ie	IE	1	\N	2023-06-30 14:00:00.000000
6	Amélie Laurent	amelie@example.fr	FR	1	2024-01-02 00:00:00	2024-01-02 09:30:00.000000
7	Ravi Patel	ravi@example.in	IN	0	2024-02-29 00:00:00	2024-02-29 23:59:59.000000
8	Sofia Rossi 🌻	sofia@example.it	IT	1	2024-04-12 00:00:00	2024-04-12 12:12:12.000000
\.

COPY orders (id, customer_id, invoice, status, total, items, ordered_at, shipped_at, note) FROM stdin;
1	1	1000	shipped	129.9	3	2024-03-01 10:00:00	2024-03-02 16:30:00	\N
2	2	1001	paid	54	1	2024-03-02 11:15:00	\N	Gift wrap 🎁
3	1	1002	cancelled	12.5	1	2024-03-03 09:45:00	\N	Customer changed their mind
4	4	1003	shipped	980	12	2024-03-05 02:10:00	2024-03-07 08:00:00	请小心轻放
5	5	1004	pending	45.75	2	2024-03-08 17:20:00	\N	Leave at the door; ring twice
6	6	1005	shipped	310.4	5	2024-03-10 13:00:00	2024-03-11 09:00:00	Fragile: "glass"
7	8	1006	paid	76.2	2	2024-03-11 18:45:00	\N	\N
8	2	1007	paid	19.99	1	2024-03-12 08:00:00	\N	Paid at the counter
9	3	1008	shipped	64	2	2024-03-14 15:30:00	\N	Shipping date never recorded
10	7	1009	paid	1499	1	2024-03-15 21:05:00	\N	C:\\Users\\ravi\\invoice.pdf
\.


-- Keys, indexes and constraints, after the rows so each builds once.
CREATE UNIQUE INDEX customers_customers_pk ON customers (id);
CREATE UNIQUE INDEX customers_customers_email_uk ON customers (email);
CREATE UNIQUE INDEX orders_orders_pk ON orders (id);
CREATE INDEX orders_orders_status_date_ix ON orders (status, ordered_at);
ALTER TABLE customers ADD CONSTRAINT customers_customers_pk PRIMARY KEY USING INDEX customers_customers_pk;
ALTER TABLE customers ADD CONSTRAINT customers_customers_email_uk UNIQUE USING INDEX customers_customers_email_uk;
ALTER TABLE orders ADD CONSTRAINT orders_orders_pk PRIMARY KEY USING INDEX orders_orders_pk;
ALTER TABLE orders ADD CONSTRAINT orders_customer_fk FOREIGN KEY (customer_id) REFERENCES customers (id) NOT VALID;
DO $f$ BEGIN
    ALTER TABLE orders VALIDATE CONSTRAINT orders_customer_fk;
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_fk';
END $f$;
SELECT setval(pg_get_serial_sequence('customers', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM customers)::numeric, 0) + 1, 1), 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, 1), 9223372036854775807)::bigint, false);

修正

没有需要修正的内容。

文件在这台电脑上转换,永远不会上传。

其他示例:

从 Oracle 到 PostgreSQL 的变化

每一行是转换器应用的一条规则,以及该规则更改你的数据时在报告中写入的记录。

  • BOOLEAN (23ai)

    boolean

    TRUE 和 FALSE 仍为 true 和 false。

  • VARCHAR2(n BYTE|CHAR), NVARCHAR2(n), CHAR(n), NCHAR(n), CLOB, NCLOB, LONG

    varchar(n) 和 text

    无论 Oracle 按字节还是按字符计数,长度都按字符计算,因此每个值都能容纳。

  • NUMBER, NUMBER(p,s), FLOAT(b)

    numeric(p,s),或 bigint

    NUMBER 保留每一位数字;没有精度的 NUMBER 若所有值都是不超过 18 位的整数,则为 64 位整数;负的小数位数会在小数点前保留同样多的位数。

  • DATE, TIMESTAMP(p)

    timestamp(p)

    Oracle 的 DATE 包含精确到秒的时间,因此是日期和时间。在美式或德式会话中导出时,日期不含时间和世纪(DD-MON-RR);请在 ISO 会话(SYYYY-MM-DD HH24:MI:SS)中导出以保留它们。

  • TIMESTAMP(7) to TIMESTAMP(9)

    秒保留六位小数,第七位截断

    PostgreSQL 保留到微秒;第七位(100 纳秒)直接截断,从不四舍五入,因此没有值会进到下一秒或下一天。

    报告记录: fraction_cut

  • TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE

    timestamptz,时刻相同

    timestamptz 保留时刻;PostgreSQL 以会话的时区显示,而不是每个值原有的偏移量。

  • JSON (21c), and CLOB holding JSON

    jsonb

    JSON 值相同;导出写为 'null' 的 SQL NULL 仍为 NULL。

  • BLOB, RAW(n), LONG RAW

    bytea

    字节仍然是字节。

  • ROWID, UROWID, XMLTYPE, SDO_GEOMETRY

    text,XMLTYPE 为 xml

    Oracle 自有的类型没有对应类型;其值保留文本,包括 ROWID 值,尽管它们离开 Oracle 就没有意义。

    报告记录: type_replaced

  • collations that ignore case (BINARY_CI)

    精确比较

    PostgreSQL 精确比较文本,因此在 Oracle 中不区分大小写的列现在会区分 Ana 和 ana。

    报告记录: case_insensitive_collation

  • identity columns, and a sequence a BEFORE INSERT trigger assigns

    GENERATED BY DEFAULT AS IDENTITY,从最大的 id 之后继续

    复制的 id 按原样导入,计数器从最大的 id 之后继续。由触发器从序列取值填充的列(12c 之前的做法)也会成为标识列。

  • CREATE SEQUENCE

    CREATE SEQUENCE,选项相同

    导出会把序列当前到达的位置写为其 START WITH,因此序列从那里继续。

  • virtual columns (GENERATED ALWAYS AS ... VIRTUAL)

    生成列,STORED

    PostgreSQL 13 到 17 只支持存储的生成列;公式相同,|| 的写法让 NULL 像在 Oracle 中一样视为空。

    报告记录: virtual_as_stored

  • virtual columns with functions IntoSQL doesn't write, and the || operator

    普通列

    无法为 PostgreSQL 写出的公式会留下一个普通列和一条报告记录;导出为虚拟列写出的值会被省略,PostgreSQL 也没有可计算的值。

    报告记录: generated_not_translated

  • defaults with functions IntoSQL doesn't write (SYS_GUID(), ||)

    无默认值

    无法为 PostgreSQL 写出的默认值会被省略,并在报告中列出。

    报告记录: default_not_translated

  • CHECK constraints

    已转换

    检查约束相同,在导入每一行时检查。

  • CHECK constraints with functions IntoSQL doesn't write

    不创建

    无法为 PostgreSQL 写出的检查约束会被省略,并在报告中列出。

    报告记录: check_skipped

  • CHECK constraints that are DISABLE or ENABLE NOVALIDATE

    不创建

    Oracle 不对已有的行执行这些检查约束,因此行可能违反它们。

    报告记录: check_not_enforced

  • function-based, bitmap and domain indexes

    不创建

    IntoSQL 在列上写出 b-tree 索引;其他索引请在导入后重新创建。

    报告记录: index_skipped

  • foreign keys

    外键,在行之后创建

    行可以按任意顺序导入,之后由外键检查。

  • foreign keys to tables the export doesn't create, and DISABLE or NOVALIDATE ones

    不创建

    外键无法引用不存在的表,而 Oracle 不检查的外键可能存在没有父行的行。

    报告记录: foreign_key_skipped

  • partitioned tables

    单个表,包含每个分区的行

    行保持不变;如有需要,请在 PostgreSQL 中重新对该表分区。

    报告记录: partitions_dropped

  • NOT NULL columns with values that become NULL

    去除 NOT NULL

    值必须变为 NULL 的列无法保留 NOT NULL,否则导入会中止。

    报告记录: not_null_relaxed

  • views, synonyms, types, packages, procedures, functions and other triggers

    在报告中列出

    它们的代码用 PL/SQL 编写,因此会列出来,由你重新创建。

    报告记录: not_converted_objects

  • exports without CREATE TABLE (data only)

    根据值推断类型

    只含数据的导出只有行,因此类型来自值。

    报告记录: no_schema

  • expressions in INSERT values other than the ones exports write

    NULL

    不运行数据库的转换器无法对它们求值;导出写出的 to_date、to_timestamp、TO_CLOB、HEXTORAW 等会被读取。

    报告记录: expression_value

  • types IntoSQL doesn't know, and object types

    text

    文本可以容纳任何值;请在导入后更改类型。

    报告记录: unknown_type

  • dates before year 1 and time zones given as region names

    NULL

    不是日期的值变为 NULL,报告会统计其数量。

    报告记录: date_out_of_range

  • NaN and Infinity in BINARY_FLOAT and BINARY_DOUBLE

    保留 NaN 和 Infinity

    PostgreSQL 的浮点类型可以存储 NaN 和 infinity。

  • NUL characters in text

    删除

    PostgreSQL 的 text 不能存储 NUL 字符。该字符会被删除,报告会统计受影响的值。

    报告记录: nul_removed

  • text that isn't valid in its encoding

    错误的字节变为替换字符

    PostgreSQL 文本必须是有效的 UTF-8。

    报告记录: invalid_utf8_replaced

  • text decoded twice (ñ)

    按原样复制

    脚本中存储的正是这些字符,因此按原样复制;报告会指出它们。

    报告记录: mojibake_suspected

在 Oracle 中在 PostgreSQL 中报告记录
BOOLEAN (23ai)booleanTRUE 和 FALSE 仍为 true 和 false。
VARCHAR2(n BYTE|CHAR), NVARCHAR2(n), CHAR(n), NCHAR(n), CLOB, NCLOB, LONGvarchar(n) 和 text无论 Oracle 按字节还是按字符计数,长度都按字符计算,因此每个值都能容纳。
NUMBER, NUMBER(p,s), FLOAT(b)numeric(p,s),或 bigintNUMBER 保留每一位数字;没有精度的 NUMBER 若所有值都是不超过 18 位的整数,则为 64 位整数;负的小数位数会在小数点前保留同样多的位数。
DATE, TIMESTAMP(p)timestamp(p)Oracle 的 DATE 包含精确到秒的时间,因此是日期和时间。在美式或德式会话中导出时,日期不含时间和世纪(DD-MON-RR);请在 ISO 会话(SYYYY-MM-DD HH24:MI:SS)中导出以保留它们。
TIMESTAMP(7) to TIMESTAMP(9)秒保留六位小数,第七位截断PostgreSQL 保留到微秒;第七位(100 纳秒)直接截断,从不四舍五入,因此没有值会进到下一秒或下一天。fraction_cut
TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONEtimestamptz,时刻相同timestamptz 保留时刻;PostgreSQL 以会话的时区显示,而不是每个值原有的偏移量。
JSON (21c), and CLOB holding JSONjsonbJSON 值相同;导出写为 'null' 的 SQL NULL 仍为 NULL。
BLOB, RAW(n), LONG RAWbytea字节仍然是字节。
ROWID, UROWID, XMLTYPE, SDO_GEOMETRYtext,XMLTYPE 为 xmlOracle 自有的类型没有对应类型;其值保留文本,包括 ROWID 值,尽管它们离开 Oracle 就没有意义。type_replaced
collations that ignore case (BINARY_CI)精确比较PostgreSQL 精确比较文本,因此在 Oracle 中不区分大小写的列现在会区分 Ana 和 ana。case_insensitive_collation
identity columns, and a sequence a BEFORE INSERT trigger assignsGENERATED BY DEFAULT AS IDENTITY,从最大的 id 之后继续复制的 id 按原样导入,计数器从最大的 id 之后继续。由触发器从序列取值填充的列(12c 之前的做法)也会成为标识列。
CREATE SEQUENCECREATE SEQUENCE,选项相同导出会把序列当前到达的位置写为其 START WITH,因此序列从那里继续。
virtual columns (GENERATED ALWAYS AS ... VIRTUAL)生成列,STOREDPostgreSQL 13 到 17 只支持存储的生成列;公式相同,|| 的写法让 NULL 像在 Oracle 中一样视为空。virtual_as_stored
virtual columns with functions IntoSQL doesn't write, and the || operator普通列无法为 PostgreSQL 写出的公式会留下一个普通列和一条报告记录;导出为虚拟列写出的值会被省略,PostgreSQL 也没有可计算的值。generated_not_translated
defaults with functions IntoSQL doesn't write (SYS_GUID(), ||)无默认值无法为 PostgreSQL 写出的默认值会被省略,并在报告中列出。default_not_translated
CHECK constraints已转换检查约束相同,在导入每一行时检查。
CHECK constraints with functions IntoSQL doesn't write不创建无法为 PostgreSQL 写出的检查约束会被省略,并在报告中列出。check_skipped
CHECK constraints that are DISABLE or ENABLE NOVALIDATE不创建Oracle 不对已有的行执行这些检查约束,因此行可能违反它们。check_not_enforced
function-based, bitmap and domain indexes不创建IntoSQL 在列上写出 b-tree 索引;其他索引请在导入后重新创建。index_skipped
foreign keys外键,在行之后创建行可以按任意顺序导入,之后由外键检查。
foreign keys to tables the export doesn't create, and DISABLE or NOVALIDATE ones不创建外键无法引用不存在的表,而 Oracle 不检查的外键可能存在没有父行的行。foreign_key_skipped
partitioned tables单个表,包含每个分区的行行保持不变;如有需要,请在 PostgreSQL 中重新对该表分区。partitions_dropped
NOT NULL columns with values that become NULL去除 NOT NULL值必须变为 NULL 的列无法保留 NOT NULL,否则导入会中止。not_null_relaxed
views, synonyms, types, packages, procedures, functions and other triggers在报告中列出它们的代码用 PL/SQL 编写,因此会列出来,由你重新创建。not_converted_objects
exports without CREATE TABLE (data only)根据值推断类型只含数据的导出只有行,因此类型来自值。no_schema
expressions in INSERT values other than the ones exports writeNULL不运行数据库的转换器无法对它们求值;导出写出的 to_date、to_timestamp、TO_CLOB、HEXTORAW 等会被读取。expression_value
types IntoSQL doesn't know, and object typestext文本可以容纳任何值;请在导入后更改类型。unknown_type
dates before year 1 and time zones given as region namesNULL不是日期的值变为 NULL,报告会统计其数量。date_out_of_range
NaN and Infinity in BINARY_FLOAT and BINARY_DOUBLE保留 NaN 和 InfinityPostgreSQL 的浮点类型可以存储 NaN 和 infinity。
NUL characters in text删除PostgreSQL 的 text 不能存储 NUL 字符。该字符会被删除,报告会统计受影响的值。nul_removed
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 oracle.postgresql.sql

外键先以 NOT VALID 添加,然后再验证。如果某行指向不存在的行,脚本会告诉你是哪个约束,而不是中途失败。

对于较大的转储,请先创建数据库,然后在服务器所在的机器上用 psql 运行脚本。

IntoSQL Pro 可以通过桌面应用或命令行将文件直接导入 PostgreSQL,无需生成脚本。

如何转储 Oracle 以获得最佳结果

转换器读取转储中的内容。以下选项能让转储保留更多数据:

  • 在 SQL Developer 中选择 Tools、Database Export,并选择 DDL 和 Insert 数据格式。SQLcl 使用 SET SQLFORMAT INSERT 也会写出相同内容。
  • 导出前请执行 ALTER SESSION SET NLS_DATE_FORMAT = 'SYYYY-MM-DD HH24:MI:SS':默认格式写出的日期不含时间和世纪。
  • exp 或 expdp 生成的 .dmp 文件是二进制的:请将其导入 Oracle 数据库(例如 Docker 中的 Oracle Database Free),再用 SQL Developer 导出。

哪些内容不会转换

视图、包、存储过程、函数、触发器、类型和同义词都是用 PL/SQL 编写的。它们会按名称在报告中列出,绝不会被悄悄丢弃,以便你为 PostgreSQL 重写。

关于 Oracle 转 PostgreSQL 的问题

这里没有你要的答案?请通过联系页面给我们留言,会有专人回复。 联系页面

我的转储会被上传吗?

不会。转换器在你的浏览器中运行,分块从磁盘读取转储,因此转储不会离开你的电脑。桌面应用和命令行也在你的电脑上转换。

转储可以多大?

转换器从不把整个转储放进内存:它按范围读取文件两次,边读边写出脚本。几 GB 的转储可以在浏览器、桌面应用和命令行中转换。

可以转换 exp 或 expdp 生成的 .dmp 文件吗?

不能直接转换:Data Pump 和原始的 Export 写出的是只有 Oracle 能读取的二进制格式。请将其导入任意 Oracle 数据库(Oracle Database Free 可在 Docker 中运行),再用 SQL Developer 的 Database Export 或 SQLcl 导出。转换器收到 .dmp 文件时会给出提示。

导出可以来自哪些 Oracle 版本?

由 SQL Developer 和 SQLcl 从 Oracle 11g 及更高版本写出、带有 DBMS_METADATA 表定义的导出。每个测试导出都来自 Oracle 21c 和 23ai,涵盖美式、德式和 ISO 会话,并与其源数据逐个单元格比较。

NUMBER、DATE 和其他 Oracle 类型会怎样?

NUMBER 变为 numeric,所有值都是整数时为 bigint;DATE 变为 timestamp,保留其时间;CLOB 变为 text,BLOB 和 RAW 变为 bytea,BINARY_DOUBLE 变为 double precision 并保留 NaN 和 Infinity,interval 变为 interval。

标识列和序列会保留吗?

是的。标识列仍为标识列,并从最大的 id 之后继续,由触发器从序列取值填充的列也是如此。序列从导出记录的到达位置继续。

PL/SQL 包、存储过程和触发器怎么处理?

它们会按名称在报告中列出,但不会转换,因为每种数据库都用自己的语言编写它们。

脚本可以导入哪些 PostgreSQL 版本?

PostgreSQL 13 到 18。同一个脚本在每个版本上都能导入,如有问题会在第一个错误处停止。