跳到正文
IntoSQL 首页

将 Oracle 导出迁移到更旧或更新的 Oracle

拖入 SQL Developer 的数据库导出或 SQLcl 写出的 .sql 文件,包含表和 Insert 语句,即可下载可在 Oracle 19c 及以上导入的脚本。NUMBER、DATE、TIMESTAMP、LOB、标识列和序列保持不变,XMLTYPE 和 JSON 的文本保存在 CLOB 中,每项更改都会列在报告中。

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

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

显示

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

  • customers写作 CUSTOMERS8 行
    7 列
    IDNUMBER(10,0) not null
    NAMEVARCHAR2(100 CHAR) not null
    EMAILVARCHAR2(150 CHAR) not null
    COUNTRYCHAR(2 BYTE) not null
    IS_ACTIVENUMBER(1,0) not null
    SIGNED_UPDATE
    CREATED_ATTIMESTAMP(0) not null
  • orders写作 ORDERS10 行
    9 列
    IDNUMBER(10,0) not null
    CUSTOMER_IDNUMBER(10,0) not null
    INVOICENUMBER(10,0)
    STATUSVARCHAR2(10 CHAR) not null
    TOTALNUMBER(10,2) not null
    ITEMSNUMBER(5,0) not null
    ORDERED_ATDATE not null
    SHIPPED_ATDATE
    NOTEVARCHAR2(255 CHAR)
-- Written by IntoSQL from a Oracle dump. Load it with: NLS_LANG=.AL32UTF8 sqlplus -S -L <user>/<password>@<database> @<file>
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
SET DEFINE OFF;
SET SQLBLANKLINES ON;
SET FEEDBACK OFF;
SET SERVEROUTPUT ON;
CREATE OR REPLACE FUNCTION "INTOSQL_CLOB" (p SYS.ODCIVARCHAR2LIST) RETURN CLOB IS
    r CLOB;
BEGIN
    DBMS_LOB.CREATETEMPORARY(r, TRUE);
    FOR i IN 1 .. p.COUNT LOOP
        IF p(i) IS NOT NULL THEN
            DBMS_LOB.WRITEAPPEND(r, LENGTH2(p(i)), p(i));
        END IF;
    END LOOP;
    RETURN r;
END;
/
CREATE OR REPLACE FUNCTION "INTOSQL_BLOB" (p SYS.ODCIVARCHAR2LIST) RETURN BLOB IS
    r BLOB;
    piece RAW(2000);
BEGIN
    DBMS_LOB.CREATETEMPORARY(r, TRUE);
    FOR i IN 1 .. p.COUNT LOOP
        piece := HEXTORAW(p(i));
        DBMS_LOB.WRITEAPPEND(r, UTL_RAW.LENGTH(piece), piece);
    END LOOP;
    RETURN r;
END;
/

CREATE SEQUENCE "INVOICE_NUMBERS" START WITH 1020 INCREMENT BY 1 MINVALUE 1;
CREATE TABLE "CUSTOMERS" (
    "ID" NUMBER(10,0) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1),
    "NAME" VARCHAR2(100 CHAR) NOT NULL,
    "EMAIL" VARCHAR2(150 CHAR) NOT NULL,
    "COUNTRY" CHAR(2 BYTE) DEFAULT 'US' NOT NULL,
    "IS_ACTIVE" NUMBER(1,0) DEFAULT 1 NOT NULL,
    "SIGNED_UP" DATE,
    "CREATED_AT" TIMESTAMP(0) DEFAULT LOCALTIMESTAMP NOT NULL,
    CONSTRAINT "CHECK1" CHECK ("IS_ACTIVE" IN (0, 1))
);

CREATE TABLE "ORDERS" (
    "ID" NUMBER(10,0) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1),
    "CUSTOMER_ID" NUMBER(10,0) NOT NULL,
    "INVOICE" NUMBER(10,0) DEFAULT ("INVOICE_NUMBERS".NEXTVAL),
    "STATUS" VARCHAR2(10 CHAR) DEFAULT 'pending' NOT NULL,
    "TOTAL" NUMBER(10,2) NOT NULL,
    "ITEMS" NUMBER(5,0) DEFAULT 1 NOT NULL,
    "ORDERED_AT" DATE NOT NULL,
    "SHIPPED_AT" DATE,
    "NOTE" VARCHAR2(255 CHAR),
    CONSTRAINT "CHECK1_2" CHECK ("STATUS" IN ('pending', 'paid', 'shipped', 'cancelled'))
);

BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
1,
'Ana Martínez',
'ana@example.com',
'MX',
1,
TIMESTAMP '2023-01-15 00:00:00',
TIMESTAMP '2023-01-15 10:24:00.000000000'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
2,
'Zoë Müller',
'zoe@example.de',
'DE',
1,
TIMESTAMP '2023-02-03 00:00:00',
TIMESTAMP '2023-02-03 08:11:42.000000000'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
3,
'José Peña',
'jose@example.es',
'ES',
0,
TIMESTAMP '2023-03-21 00:00:00',
TIMESTAMP '2023-03-21 19:05:17.000000000'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
4,
'李雷',
'lilei@example.cn',
'CN',
1,
TIMESTAMP '2023-05-09 00:00:00',
TIMESTAMP '2023-05-09 02:40:00.000000000'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
5,
'Noah O''Brien',
'noah@example.ie',
'IE',
1,
NULL,
TIMESTAMP '2023-06-30 14:00:00.000000000'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
6,
'Amélie Laurent',
'amelie@example.fr',
'FR',
1,
TIMESTAMP '2024-01-02 00:00:00',
TIMESTAMP '2024-01-02 09:30:00.000000000'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
7,
'Ravi Patel',
'ravi@example.in',
'IN',
0,
TIMESTAMP '2024-02-29 00:00:00',
TIMESTAMP '2024-02-29 23:59:59.000000000'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
8,
'Sofia Rossi 🌻',
'sofia@example.it',
'IT',
1,
TIMESTAMP '2024-04-12 00:00:00',
TIMESTAMP '2024-04-12 12:12:12.000000000'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
1,
1,
1000,
'shipped',
129.9,
3,
TIMESTAMP '2024-03-01 10:00:00',
TIMESTAMP '2024-03-02 16:30:00',
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
2,
2,
1001,
'paid',
54,
1,
TIMESTAMP '2024-03-02 11:15:00',
NULL,
'Gift wrap 🎁'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
3,
1,
1002,
'cancelled',
12.5,
1,
TIMESTAMP '2024-03-03 09:45:00',
NULL,
'Customer changed their mind'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
4,
4,
1003,
'shipped',
980,
12,
TIMESTAMP '2024-03-05 02:10:00',
TIMESTAMP '2024-03-07 08:00:00',
'请小心轻放'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
5,
5,
1004,
'pending',
45.75,
2,
TIMESTAMP '2024-03-08 17:20:00',
NULL,
'Leave at the door; ring twice'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
6,
6,
1005,
'shipped',
310.4,
5,
TIMESTAMP '2024-03-10 13:00:00',
TIMESTAMP '2024-03-11 09:00:00',
'Fragile: "glass"'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
7,
8,
1006,
'paid',
76.2,
2,
TIMESTAMP '2024-03-11 18:45:00',
NULL,
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
8,
2,
1007,
'paid',
19.99,
1,
TIMESTAMP '2024-03-12 08:00:00',
NULL,
'Paid at the counter'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
9,
3,
1008,
'shipped',
64,
2,
TIMESTAMP '2024-03-14 15:30:00',
NULL,
'Shipping date never recorded'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"INVOICE",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE"
) VALUES (
10,
7,
1009,
'paid',
1499,
1,
TIMESTAMP '2024-03-15 21:05:00',
NULL,
'C:\Users\ravi\invoice.pdf'
);
COMMIT;
END;
/

-- Keys, indexes, foreign keys, counters and triggers, after the rows.
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "PK_CUSTOMERS" PRIMARY KEY ("ID");
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "UQ_CUSTOMERS_CUSTOMERS_EMAIL_UK" UNIQUE ("EMAIL");
ALTER TABLE "ORDERS" ADD CONSTRAINT "PK_ORDERS" PRIMARY KEY ("ID");
CREATE INDEX "IX_ORDERS_ORDERS_STATUS_DATE_IX" ON "ORDERS" ("STATUS", "ORDERED_AT");
ALTER TABLE "ORDERS" ADD CONSTRAINT "ORDERS_CUSTOMER_FK" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "CUSTOMERS" ("ID") ENABLE NOVALIDATE;
BEGIN
    EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" ENABLE VALIDATE CONSTRAINT "ORDERS_CUSTOMER_FK"';
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('Foreign key ' || '"ORDERS_CUSTOMER_FK"' || ' has rows without a parent: it stays unvalidated, and new rows are checked.');
END;
/
DECLARE
    next_id NUMBER;
BEGIN
    SELECT NVL(MAX("ID"), 0) + 1 INTO next_id FROM "CUSTOMERS";
    IF next_id < 1 THEN
        next_id := 1;
    END IF;
    EXECUTE IMMEDIATE 'ALTER TABLE "CUSTOMERS" MODIFY ("ID" GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH ' || next_id || '))';
END;
/
COMMENT ON TABLE "CUSTOMERS" IS 'People who bought at least once';
DECLARE
    next_id NUMBER;
BEGIN
    SELECT NVL(MAX("ID"), 0) + 1 INTO next_id FROM "ORDERS";
    IF next_id < 1 THEN
        next_id := 1;
    END IF;
    EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" MODIFY ("ID" GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH ' || next_id || '))';
END;
/
DROP FUNCTION "INTOSQL_CLOB";
DROP FUNCTION "INTOSQL_BLOB";
COMMIT;
EXIT;

修正

没有需要修正的内容。

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

其他示例:

文件与脚本之间的变化

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

  • BOOLEAN (23ai)

    23ai 上为 BOOLEAN,否则为 NUMBER(1),并带有限定 0 和 1 的 CHECK

    TRUE 和 FALSE 仍为 true 和 false。

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

    相同的类型,保留其 BYTE 或 CHAR 长度

    相同的文本类型;LONG 变为 CLOB,这是版本 8 以来每个版本都推荐的类型。

  • VARCHAR2 and NVARCHAR2 past what the target's own types hold

    每个值都不超过 4000 字节时为 VARCHAR2(4000 CHAR),否则为 CLOB

    VARCHAR2 默认容纳 4000 字节,而 Oracle 无法为 CLOB 建立索引,因此值能容纳时文本保持为 VARCHAR2,否则为 CLOB。

    报告记录: text_as_lob

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

    相同的 NUMBER 类型

    相同的 NUMBER 和 FLOAT 类型,保留每一位数字。

  • INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND

    相同的 INTERVAL 类型

    interval 相同。

  • DATE, TIMESTAMP(p)

    DATE 和 TIMESTAMP(p),与声明一致

    类型相同,因此每个日期都保留精确到秒的时间。

  • TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE

    相同的类型

    Oracle 保留 -12:00 到 +14:00 的偏移量;偏移量超出 -12:00 的值以 UTC 写出,仍是同一时刻。

  • JSON (21c), and CLOB holding JSON

    21c 及更高版本为 JSON,否则为 CLOB

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

  • BLOB, RAW(n), LONG RAW

    相同的类型;LONG RAW 为 BLOB

    字节仍然是字节。

  • ROWID, UROWID, XMLTYPE, SDO_GEOMETRY

    CLOB,存放其文本

    XMLTYPE、ROWID 和 UROWID 将其文本保存在 CLOB 中,因此脚本可在 19c 起的每个版本上导入。

    报告记录: type_replaced

  • collations that ignore case (BINARY_CI)

    精确比较

    不写出列的排序规则,因此原本不区分大小写 (BINARY_CI) 的列现在会区分 Ana 和 ana。

    报告记录: case_insensitive_collation

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

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

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

  • identity columns the target can't count

    普通整数

    Oracle 每个表只有一个标识列计数;其他列保留其值,不带计数器。

    报告记录: counter_dropped

  • CREATE SEQUENCE

    CREATE SEQUENCE,选项相同

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

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

    虚拟列

    虚拟列相同。

    报告记录: stored_as_virtual

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

    普通列

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

    报告记录: generated_not_translated

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

    无默认值

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

    报告记录: default_not_translated

  • CHECK constraints

    已转换

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

  • CHECK constraints with functions IntoSQL doesn't write

    不创建

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

    报告记录: 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

    在数据之后以 ENABLE NOVALIDATE 添加,然后验证,有孤立行时给出警告

    外键立即检查新行,最后再验证;有孤立行时外键保持未验证状态并给出警告,而不是中止导入。

  • ON DELETE CASCADE that cascades in a cycle or along a second path

    去除

    Oracle 的外键只在删除时执行操作,可用 CASCADE 或 SET NULL。

    报告记录: foreign_key_action_unsupported

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

    不创建

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

    报告记录: foreign_key_skipped

  • names longer than Oracle 12.1 allows

    缩短

    从 12.2 起,Oracle 名称最多 128 字节;更长的名称会被缩短。

    报告记录: name_shortened

  • partitioned tables

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

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

    报告记录: partitions_dropped

  • several schemas in one export

    单个 schema,每个表名前加上其 schema 名

    脚本会导入到运行它的用户的 schema 中,因此其他 schema 的表名前会加上其 schema 名;只含一个 schema 的导出保留其表名。

    报告记录: schemas_merged

  • 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

    CLOB

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

    报告记录: 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

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

  • NUL characters in text

    保留

    VARCHAR2 和 CLOB 可以包含 NUL 字符,因此值按原样复制。

  • text that isn't valid in its encoding

    错误的字节变为替换字符

    脚本是 UTF-8,每个值都必须是有效文本。

    报告记录: invalid_utf8_replaced

  • text decoded twice (ñ)

    按原样复制

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

    报告记录: mojibake_suspected

文件中脚本中报告记录
BOOLEAN (23ai)23ai 上为 BOOLEAN,否则为 NUMBER(1),并带有限定 0 和 1 的 CHECKTRUE 和 FALSE 仍为 true 和 false。
VARCHAR2(n BYTE|CHAR), NVARCHAR2(n), CHAR(n), NCHAR(n), CLOB, NCLOB, LONG相同的类型,保留其 BYTE 或 CHAR 长度相同的文本类型;LONG 变为 CLOB,这是版本 8 以来每个版本都推荐的类型。
VARCHAR2 and NVARCHAR2 past what the target's own types hold每个值都不超过 4000 字节时为 VARCHAR2(4000 CHAR),否则为 CLOBVARCHAR2 默认容纳 4000 字节,而 Oracle 无法为 CLOB 建立索引,因此值能容纳时文本保持为 VARCHAR2,否则为 CLOB。text_as_lob
NUMBER, NUMBER(p,s), FLOAT(b)相同的 NUMBER 类型相同的 NUMBER 和 FLOAT 类型,保留每一位数字。
INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND相同的 INTERVAL 类型interval 相同。
DATE, TIMESTAMP(p)DATE 和 TIMESTAMP(p),与声明一致类型相同,因此每个日期都保留精确到秒的时间。
TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE相同的类型Oracle 保留 -12:00 到 +14:00 的偏移量;偏移量超出 -12:00 的值以 UTC 写出,仍是同一时刻。
JSON (21c), and CLOB holding JSON21c 及更高版本为 JSON,否则为 CLOBJSON 值相同;导出写为 'null' 的 SQL NULL 仍为 NULL。
BLOB, RAW(n), LONG RAW相同的类型;LONG RAW 为 BLOB字节仍然是字节。
ROWID, UROWID, XMLTYPE, SDO_GEOMETRYCLOB,存放其文本XMLTYPE、ROWID 和 UROWID 将其文本保存在 CLOB 中,因此脚本可在 19c 起的每个版本上导入。type_replaced
collations that ignore case (BINARY_CI)精确比较不写出列的排序规则,因此原本不区分大小写 (BINARY_CI) 的列现在会区分 Ana 和 ana。case_insensitive_collation
identity columns, and a sequence a BEFORE INSERT trigger assignsGENERATED BY DEFAULT ON NULL AS IDENTITY,从最大的 id 之后继续复制的 id 按原样导入,计数器从最大的 id 之后继续。由触发器从序列取值填充的列(12c 之前的做法)也会成为标识列。
identity columns the target can't count普通整数Oracle 每个表只有一个标识列计数;其他列保留其值,不带计数器。counter_dropped
CREATE SEQUENCECREATE SEQUENCE,选项相同导出会把序列当前到达的位置写为其 START WITH,因此序列从那里继续。
virtual columns (GENERATED ALWAYS AS ... VIRTUAL)虚拟列虚拟列相同。stored_as_virtual
virtual columns with functions IntoSQL doesn't write, and the || operator普通列无法为 Oracle 写出的公式会留下一个普通列和一条报告记录;导出为虚拟列写出的值会被省略,Oracle 也没有可计算的值。generated_not_translated
defaults with functions IntoSQL doesn't write (SYS_GUID(), ||)无默认值无法写出的默认值会被省略,并在报告中列出。default_not_translated
CHECK constraints已转换检查约束相同,在导入每一行时检查。
CHECK constraints with functions IntoSQL doesn't write不创建无法写出的检查约束会被省略,并在报告中列出。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在数据之后以 ENABLE NOVALIDATE 添加,然后验证,有孤立行时给出警告外键立即检查新行,最后再验证;有孤立行时外键保持未验证状态并给出警告,而不是中止导入。
ON DELETE CASCADE that cascades in a cycle or along a second path去除Oracle 的外键只在删除时执行操作,可用 CASCADE 或 SET NULL。foreign_key_action_unsupported
foreign keys to tables the export doesn't create, and DISABLE or NOVALIDATE ones不创建外键无法引用不存在的表,而 Oracle 不检查的外键可能存在没有父行的行。foreign_key_skipped
names longer than Oracle 12.1 allows缩短从 12.2 起,Oracle 名称最多 128 字节;更长的名称会被缩短。name_shortened
partitioned tables单个表,包含每个分区的行行保持不变;如有需要,请在 Oracle 中重新对该表分区。partitions_dropped
several schemas in one export单个 schema,每个表名前加上其 schema 名脚本会导入到运行它的用户的 schema 中,因此其他 schema 的表名前会加上其 schema 名;只含一个 schema 的导出保留其表名。schemas_merged
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 typesCLOB文本可以容纳任何值;请在导入后更改类型。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 和 InfinityOracle 的浮点类型可以存储 NaN 和 infinity。
NUL characters in text保留VARCHAR2 和 CLOB 可以包含 NUL 字符,因此值按原样复制。
text that isn't valid in its encoding错误的字节变为替换字符脚本是 UTF-8,每个值都必须是有效文本。invalid_utf8_replaced
text decoded twice (ñ)按原样复制脚本中存储的正是这些字符,因此按原样复制;报告会指出它们。mojibake_suspected

将脚本导入 Oracle

脚本先创建表、复制行,再添加键、索引和外键,因此导入速度快,并会在遇到第一个错误时停止。

NLS_LANG=.AL32UTF8 sqlplus -S -L user@//localhost/mydb @oracle.oracle.sql

外键以 ENABLE NOVALIDATE 添加,因此新行会立即检查,之后再验证。如果某个旧行指向不存在的行,脚本会说明是哪个约束,并让它保持未验证状态,而不是中途失败。

对于较大的转储,请在数据库所在的机器上运行 SQL*Plus。脚本每 100 行提交一次。运行脚本的用户需要 CREATE TABLE、CREATE SEQUENCE、CREATE TRIGGER 和 CREATE PROCEDURE 权限,以及其表空间上的配额。

如何转储 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 导出。

哪些内容不会转换

视图、触发器、存储过程、函数等用 Oracle 自己的语言编写的对象,会按名称列在报告中,绝不会被悄悄丢弃,你可以先在要导入的 Oracle 版本上逐一检查再重建。

关于在 Oracle 版本之间迁移的问题

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

我的转储会被上传吗?

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

转储可以多大?

转换器从不把整个转储放进内存:它按范围读取文件两次,边读边写出脚本。几 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 保留其精度,DATE、TIMESTAMP、interval,CHAR 和 VARCHAR2 保留其长度,RAW 和 LOB 也一样。XMLTYPE 和 JSON 将其文本保存在 CLOB 中,因此脚本可在 19c 上导入。

标识列和序列会保留吗?

是的。标识列和序列保持不变,并从导出记录的到达位置继续。

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

它们会按名称在报告中列出,但不会转换,以便你在导入表之后重新创建它们。

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

Oracle 19c 及更高版本。每个测试导出都能在 21c 和 23ai 上导入,如有问题会在第一个错误处停止。