本文へスキップ
IntoSQL ホーム

PostgreSQL を Oracle に変換

pg_dump または pg_dumpall で作成したプレーン形式のダンプ (.sql または .sql.gz) をドロップすると、同じテーブル、キー、インデックス、データを持つ Oracle スクリプトをダウンロードできます。Oracle がそのまま保持できない値と、引き継がないオブジェクトは、すべてレポートに記載されます。

ファイル
sqlshop_2024_postgres.sqlサンプルファイル、6.2 KB
データベース

18 行を変換、修正 2 件、却下なし

表示

shop_2024_postgres.sql のテーブルPostgreSQL 18.6 のダンプ · pg_dump で作成 · utf8mb4

  • customersCUSTOMERS として書き出し8 行1
    8 列
    IDNUMBER(10) not null
    NAMEVARCHAR2(4000 CHAR) not null
    EMAILVARCHAR2(750 CHAR) not null
    COUNTRYVARCHAR2(2 CHAR) not null
    IS_ACTIVENUMBER(1) not null
    TAGSCLOB not null
    SIGNED_UPDATE
    CREATED_ATTIMESTAMP(6) WITH TIME ZONE not null
  • ordersORDERS として書き出し10 行1
    10 列
    IDNUMBER(10) not null
    CUSTOMER_IDNUMBER(10) not null
    STATUSVARCHAR2(9 CHAR) not null
    TOTALNUMBER(10,2) not null
    ITEMSNUMBER(5) not null
    ORDERED_ATTIMESTAMP(6) not null
    SHIPPED_ATTIMESTAMP(6)
    NOTEVARCHAR2(4000 CHAR)
    DETAILSCLOB
    DELIVERYVARCHAR2(100 CHAR)

未変換

  • ビュー paid_orders

これらはデータベースごとに独自の言語で書かれます。Oracle 用に書き直してください。

-- Written by IntoSQL from a PostgreSQL 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 TABLE "CUSTOMERS" (
    "ID" NUMBER(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1001),
    "NAME" VARCHAR2(4000 CHAR) NOT NULL,
    "EMAIL" VARCHAR2(750 CHAR) NOT NULL,
    "COUNTRY" VARCHAR2(2 CHAR) DEFAULT 'US' NOT NULL,
    "IS_ACTIVE" NUMBER(1) DEFAULT 1 NOT NULL,
    "TAGS" CLOB NOT NULL,
    "SIGNED_UP" DATE,
    "CREATED_AT" TIMESTAMP(6) WITH TIME ZONE DEFAULT SYSTIMESTAMP NOT NULL,
    CONSTRAINT "CK_CUSTOMERS_IS_ACTIVE" CHECK ("IS_ACTIVE" IN (0, 1))
);

CREATE TABLE "ORDERS" (
    "ID" NUMBER(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 5001),
    "CUSTOMER_ID" NUMBER(10) NOT NULL,
    "STATUS" VARCHAR2(9 CHAR) DEFAULT 'pending' NOT NULL,
    "TOTAL" NUMBER(10,2) NOT NULL,
    "ITEMS" NUMBER(5) DEFAULT 1 NOT NULL,
    "ORDERED_AT" TIMESTAMP(6) NOT NULL,
    "SHIPPED_AT" TIMESTAMP(6),
    "NOTE" VARCHAR2(4000 CHAR),
    "DETAILS" CLOB,
    "DELIVERY" VARCHAR2(100 CHAR),
    CONSTRAINT "CK_ORDERS_STATUS" CHECK ("STATUS" IN ('pending', 'paid', 'shipped', 'cancelled')),
    CONSTRAINT "ORDERS_TOTAL_CHECK" CHECK ("TOTAL" >= (0))
);

BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
1,
'Ana Martínez',
'ana@example.com',
'MX',
1,
'["vip"]',
DATE '2023-01-15',
TIMESTAMP '2023-01-15 10:24:00 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
2,
'Zoë Müller',
'zoe@example.de',
'DE',
1,
'[]',
DATE '2023-02-03',
TIMESTAMP '2023-02-03 08:11:42 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
3,
'José Peña',
'jose@example.es',
'ES',
0,
'["wholesale","late payer"]',
DATE '2023-03-21',
TIMESTAMP '2023-03-21 19:05:17 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
4,
'李雷',
'lilei@example.cn',
'CN',
1,
'[]',
DATE '2023-05-09',
TIMESTAMP '2023-05-09 02:40:00 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
5,
'Noah O''Brien',
'noah@example.ie',
'IE',
1,
'[]',
NULL,
TIMESTAMP '2023-06-30 14:00:00 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
6,
'Amélie Laurent',
'amelie@example.fr',
'FR',
1,
'["vip"]',
DATE '2024-01-02',
TIMESTAMP '2024-01-02 09:30:00 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
7,
'Ravi Patel',
'ravi@example.in',
'IN',
0,
'[]',
DATE '2024-02-29',
TIMESTAMP '2024-02-29 23:59:59 +00:00'
);
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"TAGS",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
8,
'Sofia Rossi 🌻',
'sofia@example.it',
'IT',
1,
'[]',
DATE '2024-04-12',
TIMESTAMP '2024-04-12 12:12:12 +00:00'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
1,
1,
'shipped',
129.90,
3,
TIMESTAMP '2024-03-01 10:00:00',
TIMESTAMP '2024-03-02 16:30:00',
NULL,
'{"gift": false}',
'1 day 06:30:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
2,
2,
'paid',
54.00,
1,
TIMESTAMP '2024-03-02 11:15:00',
NULL,
'Gift wrap 🎁',
'{"gift": true, "wrap": "red"}',
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
3,
1,
'cancelled',
12.50,
1,
TIMESTAMP '2024-03-03 09:45:00',
NULL,
'Customer changed their mind',
NULL,
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
4,
4,
'shipped',
980.00,
12,
TIMESTAMP '2024-03-05 02:10:00',
TIMESTAMP '2024-03-07 08:00:00',
'请小心轻放',
'{"fragile": true}',
'2 days 05:50:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
5,
5,
'pending',
45.75,
2,
TIMESTAMP '2024-03-08 17:20:00',
NULL,
'Leave at the door; ring twice',
NULL,
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
6,
6,
'shipped',
310.40,
5,
TIMESTAMP '2024-03-10 13:00:00',
TIMESTAMP '2024-03-11 09:00:00',
'Fragile: "glass"',
'{"fragile": true}',
'20:00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
7,
8,
'paid',
76.20,
2,
TIMESTAMP '2024-03-11 18:45:00',
NULL,
NULL,
NULL,
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
8,
2,
'shipped',
19.99,
1,
TIMESTAMP '2024-03-12 08:00:00',
NULL,
'Shipped date set to infinity by an old import',
NULL,
NULL
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
9,
3,
'shipped',
64.00,
2,
TIMESTAMP '2024-03-14 15:30:00',
TIMESTAMP '2024-03-15 10:00:00',
'Two parcels',
'{"parcels": [1, 2]}',
'18:30:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"DELIVERY"
) VALUES (
10,
7,
'paid',
1499.00,
1,
TIMESTAMP '2024-03-15 21:05:00',
NULL,
'C:\Users\ravi\invoice.pdf',
NULL,
NULL
);
COMMIT;
END;
/

-- Keys, indexes, foreign keys, counters and triggers, after the rows.
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "UQ_CUSTOMERS_CUSTOMERS_EMAIL_KEY" UNIQUE ("EMAIL");
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "PK_CUSTOMERS" PRIMARY KEY ("ID");
ALTER TABLE "ORDERS" ADD CONSTRAINT "PK_ORDERS" PRIMARY KEY ("ID");
CREATE INDEX "IX_ORDERS_IDX_ORDERS_CUSTOMER" ON "ORDERS" ("CUSTOMER_ID");
CREATE INDEX "IX_ORDERS_IDX_ORDERS_STATUS_DATE" ON "ORDERS" ("STATUS", "ORDERED_AT");
ALTER TABLE "ORDERS" ADD CONSTRAINT "ORDERS_CUSTOMER_ID_FKEY" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "CUSTOMERS" ("ID") ENABLE NOVALIDATE;
BEGIN
    EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" ENABLE VALIDATE CONSTRAINT "ORDERS_CUSTOMER_ID_FKEY"';
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('Foreign key ' || '"ORDERS_CUSTOMER_ID_FKEY"' || ' 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 < 1001 THEN
        next_id := 1001;
    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 < 5001 THEN
        next_id := 5001;
    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;

修正

  1. customers の "tags" は text[] ですが、Oracle にはないため、同じ値を持つ CLOB にしました。
  2. orders の "delivery" は interval ですが、Oracle にはないため、同じ値を持つ VARCHAR2(100 CHAR) にしました。

確認が必要

  • 1 件のビュー、トリガー、ルーチン、イベントは変換されません。レポートにそれぞれ記載しています。 Oracle で手動で作り直してください。
  • customers の "tags" のデフォルト値は Oracle 用に書き換えられないため (a value its type can't hold)、列にデフォルト値はありません。 新しい行に必要なら、手動でデフォルト値を追加してください。
  • orders のインデックス idx_orders_details は Oracle 用に書き換えられない式を使っているため (a gin index)、作成しません。 クエリに必要なら、手動でインデックスを作成してください。
  • orders の "shipped_at" にある 1 個の値は infinity のように Oracle が保存できない日付のため、NULL にしました。 Oracle が保存できるのは 1 年から 9999 年までで、infinity はありません。必要ならソースでその日付を置き換えてください。

ファイルはこのコンピューター上で変換され、アップロードされることはありません。

その他のサンプル:

PostgreSQL から Oracle で変わること

各行はコンバーターが適用するルールです。ルールによってデータが変わったときにレポートに書かれる行も示します。

  • boolean

    0 と 1 の CHECK 付きの NUMBER(1)

    Oracle 21c には boolean 列型がありません。1 と 0 ならどのバージョンでも true と false を保てます。

  • varchar(n), char(n)

    VARCHAR2(n CHAR)、文字数で計算

    長さは PostgreSQL と同じく文字数で数えます。

  • text

    すべての値が 4000 バイト (キー内では 750 文字) に収まれば VARCHAR2(4000 CHAR)、それ以外は CLOB

    VARCHAR2 はデフォルトで 4000 バイトまでで、Oracle は CLOB にインデックスを作れません。そのためテキストは値が収まれば VARCHAR2 のまま、収まらなければ CLOB になります。

    レポートの行: text_as_lob

  • empty strings and empty bytea values

    NULL

    Oracle は空文字列を NULL として保存するため、' だった値は NULL として読み出されます。レポートで列ごとの件数を示します。

    レポートの行: empty_string_null

  • citext

    厳密な比較

    Oracle は PostgreSQL のテキストと同じく、指定がない限りテキストを厳密に比較します。citext 列は大文字と小文字を区別しない動作を失います。

    レポートの行: case_insensitive_collation

  • numeric(p,s) past 38 digits; numeric without a precision

    値が 38 桁に収まれば NUMBER、それ以外は VARCHAR2

    Oracle の NUMBER はどのスケールでも 38 桁までです。それより大きな数はすべての桁を正確に保つためテキストにします。

    レポートの行: decimal_as_text

  • money

    NUMBER(19,2)

    Oracle には money 型がありません。金額は、サーバーのロケールが付けた通貨記号を除いて数値として保ちます。

    レポートの行: type_replaced

  • interval

    PostgreSQL のテキストを持つ VARCHAR2(100 CHAR)

    interval は月と日・秒を組み合わせますが、Oracle ではこれらを 2 つの異なる型で扱います。テキストならすべての部分を保てます。

    レポートの行: type_replaced

  • arrays (integer[], text[]...)

    JSON 配列を持つ CLOB

    Oracle には配列がありません。JSON 配列ならすべての要素と NULL を保ち、JSON_TABLE で読めます。

    レポートの行: type_replaced

  • ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension types

    PostgreSQL のテキストを持つ VARCHAR2 または CLOB

    Oracle には同等の型がないため、各値は PostgreSQL が書き出したテキストを保ちます。

    レポートの行: type_replaced

  • json, jsonb

    CLOB

    Oracle の JSON 関数はどのバージョンでもテキストから JSON を読み取れ、CLOB ならどんなサイズの値も保てます。

  • timestamp

    TIMESTAMP

    タイムゾーンなしの timestamp は、Oracle の TIMESTAMP と同じく時計が示す時刻です。date は DATE になり、時刻も持ちますが午前 0 時のままです。

  • timestamp with time zone

    UTC の TIMESTAMP WITH TIME ZONE

    各値は UTC で書き出し、ダンプのオフセットにかかわらず同じ時点です。

  • time

    午前0時からの INTERVAL DAY TO SECOND

    Oracle には時刻の型がありません。午前 0 時からの interval なら 24:00:00 を含むすべての値を保持できます。

  • infinity, -infinity, BC dates and years past 9999

    NULL

    スクリプトが書き出すのは 1 年から 9999 年までで、Oracle には infinity がありません。それらの値は NULL になり、レポートで件数を示します。

    レポートの行: date_out_of_range

  • NaN and Infinity in numeric

    NULL

    Oracle の NUMBER には NaN や Infinity がないため、それらの値は NULL になり、レポートで件数を示します。

    レポートの行: invalid_value_null

  • NOT NULL columns with values that become NULL

    NOT NULL を削除

    値を NULL にする必要があった列は、NOT NULL を保てません。保つと読み込みが止まります。

    レポートの行: not_null_relaxed

  • enum types

    ラベルの CHECK 付きの VARCHAR2

    チェック付きのテキストで同じ値を保ちます。

  • enum columns holding values outside their labels

    チェックなしの VARCHAR2

    ラベルにない値はチェックに違反するため、チェックは作成しません。

    レポートの行: enum_check_skipped

  • uuid, inet, cidr, macaddr

    VARCHAR2

    Oracle にはこれらの型がありません。テキストならすべての値を保てます。

  • bytea

    BLOB

    バイト列はバイト列のままです。

  • bit(n), bit varying

    63 ビットまではビットの値を持つ NUMBER、それを超えるとテキストの桁

    ビット列は、そのビットが表す数値として保存します。

  • oid, xid, cid

    負でないことを確かめる CHECK 付きの NUMBER(10)

    NUMBER はすべての値を保持できます。

  • serial, identity

    GENERATED BY DEFAULT ON NULL AS IDENTITY、最大の ID の後から継続

    コピーした ID はそのまま読み込み、カウンターは最大の ID とシーケンスの次の値のうち大きい方の後から続きます。

  • a second serial or identity column in a table

    普通の整数

    Oracle が採番する IDENTITY 列はテーブルごとに 1 つだけです。それ以外の列はカウンターなしで値を保ちます。

    レポートの行: counter_dropped

  • sequences not owned by a column

    到達していた値から始まる CREATE SEQUENCE

    Oracle のシーケンスも同じように動作します。

  • generated columns

    仮想列

    Oracle は生成列を読み取り時にしか計算しません。STORED の列は同じ値を持つ仮想列になります。

    レポートの行: stored_as_virtual

  • generated columns with functions Oracle lacks

    値を持つ普通の列

    Oracle 用に書き換えられない式は、ダンプの値を持つ普通の列とレポートの 1 行になります。

    レポートの行: generated_not_translated

  • defaults with functions Oracle lacks, and defaults from a sequence

    デフォルト値なし

    Oracle 用に書き換えられないデフォルト値は含めず、レポートに記載します。

    レポートの行: default_not_translated

  • CHECK constraints

    変換して CREATE TABLE 内に記述

    インラインのチェックは各行の読み込み時にテストされます。

  • CHECK constraints with functions Oracle lacks

    作成しない

    Oracle 用に書き換えられないチェックは含めず、レポートに記載します。

    レポートの行: check_skipped

  • CHECK ... NOT VALID

    作成しない

    PostgreSQL は既存の行をチェックしていないため、違反している可能性があります。

    レポートの行: check_not_valid

  • gin, gist, brin and hash indexes, partial and expression indexes, and indexes on CLOB columns

    作成しない

    IntoSQL が Oracle 用に書き出すのは列に対する b-tree インデックスです。Oracle は CLOB にインデックスを作れません。その他は読み込み後に作り直してください。

    レポートの行: index_skipped

  • foreign keys

    データの後に ENABLE NOVALIDATE で作成してから検証し、孤立した行があれば警告

    キーは新しい行をすぐにチェックし、最後に検証します。親のない行があれば、読み込みを止めずにキーを未検証のまま残して警告します。

  • ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT

    削除

    Oracle の外部キーが動作するのは削除時だけで、CASCADE か SET NULL です。

    レポートの行: foreign_key_action_unsupported

  • foreign keys to tables the dump doesn't create

    作成しない

    キーは存在しないテーブルを参照できません。

    レポートの行: foreign_key_skipped

  • names over 128 bytes

    短縮

    Oracle 12.2 以降の名前は 128 バイトまでで、PostgreSQL の 63 より長くできます。

    レポートの行: name_shortened

  • partitioned tables

    すべてのパーティションの行を持つ 1 つのテーブル

    行は同じです。必要なら Oracle でもう一度テーブルをパーティション分割してください。

    レポートの行: partitions_dropped

  • schemas

    1 つのスキーマ、テーブル名の先頭にスキーマ名

    スクリプトは実行したユーザーのスキーマに読み込むため、異なるスキーマのテーブルには先頭にスキーマ名を付けます。public のテーブルは名前を保ちます。

    レポートの行: schemas_merged

  • views, functions, procedures, triggers, rules, policies, extensions and types

    レポートに記載

    コードが PostgreSQL の言語で書かれているため、作り直せるよう一覧にします。

    レポートの行: not_converted_objects

  • dumps without CREATE TABLE (--data-only)

    値から読み取った型

    データのみのダンプには行しかないため、型は値から決まります。

    レポートの行: no_schema

  • expressions in INSERT values

    NULL

    データベースを実行しないコンバーターでは、これらを評価できません。

    レポートの行: expression_value

  • types IntoSQL doesn't know

    CLOB

    テキストはどんな値も保持できます。読み込み後に型を変更してください。

    レポートの行: unknown_type

  • text that isn't valid in its encoding

    不正なバイトを置換文字に

    スクリプトは UTF-8 で、NLS_LANG=.AL32UTF8 で読み込みます。

    レポートの行: invalid_utf8_replaced

  • text decoded twice (ñ)

    そのままコピー

    ダンプにはまさにこの文字が含まれているため、そのままコピーし、レポートで指摘します。

    レポートの行: mojibake_suspected

PostgreSQL ではOracle ではレポートの行
boolean0 と 1 の CHECK 付きの NUMBER(1)Oracle 21c には boolean 列型がありません。1 と 0 ならどのバージョンでも true と false を保てます。
varchar(n), char(n)VARCHAR2(n CHAR)、文字数で計算長さは PostgreSQL と同じく文字数で数えます。
textすべての値が 4000 バイト (キー内では 750 文字) に収まれば VARCHAR2(4000 CHAR)、それ以外は CLOBVARCHAR2 はデフォルトで 4000 バイトまでで、Oracle は CLOB にインデックスを作れません。そのためテキストは値が収まれば VARCHAR2 のまま、収まらなければ CLOB になります。text_as_lob
empty strings and empty bytea valuesNULLOracle は空文字列を NULL として保存するため、' だった値は NULL として読み出されます。レポートで列ごとの件数を示します。empty_string_null
citext厳密な比較Oracle は PostgreSQL のテキストと同じく、指定がない限りテキストを厳密に比較します。citext 列は大文字と小文字を区別しない動作を失います。case_insensitive_collation
numeric(p,s) past 38 digits; numeric without a precision値が 38 桁に収まれば NUMBER、それ以外は VARCHAR2Oracle の NUMBER はどのスケールでも 38 桁までです。それより大きな数はすべての桁を正確に保つためテキストにします。decimal_as_text
moneyNUMBER(19,2)Oracle には money 型がありません。金額は、サーバーのロケールが付けた通貨記号を除いて数値として保ちます。type_replaced
intervalPostgreSQL のテキストを持つ VARCHAR2(100 CHAR)interval は月と日・秒を組み合わせますが、Oracle ではこれらを 2 つの異なる型で扱います。テキストならすべての部分を保てます。type_replaced
arrays (integer[], text[]...)JSON 配列を持つ CLOBOracle には配列がありません。JSON 配列ならすべての要素と NULL を保ち、JSON_TABLE で読めます。type_replaced
ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension typesPostgreSQL のテキストを持つ VARCHAR2 または CLOBOracle には同等の型がないため、各値は PostgreSQL が書き出したテキストを保ちます。type_replaced
json, jsonbCLOBOracle の JSON 関数はどのバージョンでもテキストから JSON を読み取れ、CLOB ならどんなサイズの値も保てます。
timestampTIMESTAMPタイムゾーンなしの timestamp は、Oracle の TIMESTAMP と同じく時計が示す時刻です。date は DATE になり、時刻も持ちますが午前 0 時のままです。
timestamp with time zoneUTC の TIMESTAMP WITH TIME ZONE各値は UTC で書き出し、ダンプのオフセットにかかわらず同じ時点です。
time午前0時からの INTERVAL DAY TO SECONDOracle には時刻の型がありません。午前 0 時からの interval なら 24:00:00 を含むすべての値を保持できます。
infinity, -infinity, BC dates and years past 9999NULLスクリプトが書き出すのは 1 年から 9999 年までで、Oracle には infinity がありません。それらの値は NULL になり、レポートで件数を示します。date_out_of_range
NaN and Infinity in numericNULLOracle の NUMBER には NaN や Infinity がないため、それらの値は NULL になり、レポートで件数を示します。invalid_value_null
NOT NULL columns with values that become NULLNOT NULL を削除値を NULL にする必要があった列は、NOT NULL を保てません。保つと読み込みが止まります。not_null_relaxed
enum typesラベルの CHECK 付きの VARCHAR2チェック付きのテキストで同じ値を保ちます。
enum columns holding values outside their labelsチェックなしの VARCHAR2ラベルにない値はチェックに違反するため、チェックは作成しません。enum_check_skipped
uuid, inet, cidr, macaddrVARCHAR2Oracle にはこれらの型がありません。テキストならすべての値を保てます。
byteaBLOBバイト列はバイト列のままです。
bit(n), bit varying63 ビットまではビットの値を持つ NUMBER、それを超えるとテキストの桁ビット列は、そのビットが表す数値として保存します。
oid, xid, cid負でないことを確かめる CHECK 付きの NUMBER(10)NUMBER はすべての値を保持できます。
serial, identityGENERATED BY DEFAULT ON NULL AS IDENTITY、最大の ID の後から継続コピーした ID はそのまま読み込み、カウンターは最大の ID とシーケンスの次の値のうち大きい方の後から続きます。
a second serial or identity column in a table普通の整数Oracle が採番する IDENTITY 列はテーブルごとに 1 つだけです。それ以外の列はカウンターなしで値を保ちます。counter_dropped
sequences not owned by a column到達していた値から始まる CREATE SEQUENCEOracle のシーケンスも同じように動作します。
generated columns仮想列Oracle は生成列を読み取り時にしか計算しません。STORED の列は同じ値を持つ仮想列になります。stored_as_virtual
generated columns with functions Oracle lacks値を持つ普通の列Oracle 用に書き換えられない式は、ダンプの値を持つ普通の列とレポートの 1 行になります。generated_not_translated
defaults with functions Oracle lacks, and defaults from a sequenceデフォルト値なしOracle 用に書き換えられないデフォルト値は含めず、レポートに記載します。default_not_translated
CHECK constraints変換して CREATE TABLE 内に記述インラインのチェックは各行の読み込み時にテストされます。
CHECK constraints with functions Oracle lacks作成しないOracle 用に書き換えられないチェックは含めず、レポートに記載します。check_skipped
CHECK ... NOT VALID作成しないPostgreSQL は既存の行をチェックしていないため、違反している可能性があります。check_not_valid
gin, gist, brin and hash indexes, partial and expression indexes, and indexes on CLOB columns作成しないIntoSQL が Oracle 用に書き出すのは列に対する b-tree インデックスです。Oracle は CLOB にインデックスを作れません。その他は読み込み後に作り直してください。index_skipped
foreign keysデータの後に ENABLE NOVALIDATE で作成してから検証し、孤立した行があれば警告キーは新しい行をすぐにチェックし、最後に検証します。親のない行があれば、読み込みを止めずにキーを未検証のまま残して警告します。
ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT削除Oracle の外部キーが動作するのは削除時だけで、CASCADE か SET NULL です。foreign_key_action_unsupported
foreign keys to tables the dump doesn't create作成しないキーは存在しないテーブルを参照できません。foreign_key_skipped
names over 128 bytes短縮Oracle 12.2 以降の名前は 128 バイトまでで、PostgreSQL の 63 より長くできます。name_shortened
partitioned tablesすべてのパーティションの行を持つ 1 つのテーブル行は同じです。必要なら Oracle でもう一度テーブルをパーティション分割してください。partitions_dropped
schemas1 つのスキーマ、テーブル名の先頭にスキーマ名スクリプトは実行したユーザーのスキーマに読み込むため、異なるスキーマのテーブルには先頭にスキーマ名を付けます。public のテーブルは名前を保ちます。schemas_merged
views, functions, procedures, triggers, rules, policies, extensions and typesレポートに記載コードが PostgreSQL の言語で書かれているため、作り直せるよう一覧にします。not_converted_objects
dumps without CREATE TABLE (--data-only)値から読み取った型データのみのダンプには行しかないため、型は値から決まります。no_schema
expressions in INSERT valuesNULLデータベースを実行しないコンバーターでは、これらを評価できません。expression_value
types IntoSQL doesn't knowCLOBテキストはどんな値も保持できます。読み込み後に型を変更してください。unknown_type
text that isn't valid in its encoding不正なバイトを置換文字にスクリプトは UTF-8 で、NLS_LANG=.AL32UTF8 で読み込みます。invalid_utf8_replaced
text decoded twice (ñ)そのままコピーダンプにはまさにこの文字が含まれているため、そのままコピーし、レポートで指摘します。mojibake_suspected

スクリプトを Oracle に読み込む

スクリプトはテーブルを作成して行をコピーしてから、キー、インデックス、外部キーを追加します。そのため読み込みが速く、最初のエラーで止まります。

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

外部キーは ENABLE NOVALIDATE で追加するため新しい行はすぐにチェックされ、その後に検証します。古い行が存在しない行を参照していれば、途中で失敗する代わりに、どの制約かをスクリプトが示し、その制約は未検証のまま残します。

大きなダンプでは、データベースと同じマシンで SQL*Plus を実行してください。スクリプトは 100 行ごとにコミットします。実行するユーザーには CREATE TABLE、CREATE SEQUENCE、CREATE TRIGGER、CREATE PROCEDURE の権限と、表領域の割り当てが必要です。

PostgreSQL を最適な方法でダンプする

コンバーターはダンプの内容を読み取ります。次のオプションを使うと、より多くのデータがダンプに残ります。

  • pg_dump のデフォルトである --format=plain は SQL を書き出します。custom または directory 形式のアーカイブ (-Fc, -Fd) は、pg_restore -f dump.sql でデータベースサーバーなしに SQL にできます。
  • --no-owner --no-privileges を使うと、コンバーターがどのみちスキップするロールと権限付与が除かれ、ダンプが小さくなります。
  • pg_dumpall はすべてのデータベースを 1 つのファイルにダンプします。各テーブルにはデータベース名を付けるため、名前は衝突しません。

変換されないもの

ビュー、マテリアライズドビュー、関数、プロシージャ、トリガー、ルール、行セキュリティポリシー、拡張機能、型は PostgreSQL 独自の言語で書かれています。黙って削除することはなく、レポートに名前で一覧するので、Oracle 向けに書き直せます。

PostgreSQL から Oracle への変換に関する質問

ここに答えがない場合は、お問い合わせページからご連絡ください。担当者が返信します。 お問い合わせページ

ダンプはアップロードされますか?

いいえ。コンバーターはブラウザ上で動作し、ダンプをディスクから少しずつ読み込むため、ダンプがコンピューターの外に出ることはありません。デスクトップアプリとコマンドラインも、お使いのコンピューター上で変換します。

ダンプはどのくらいの大きさまで扱えますか?

コンバーターはダンプ全体をメモリに保持しません。ファイルを範囲ごとに 2 回読み、読みながらスクリプトを書き出します。数 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 と identity の値は保持されますか?

はい。各テーブルの serial または identity の列は IDENTITY 列になり、すべての行が ID を保ち、次の ID は最大の ID の後から続きます。列に属さないシーケンスは、到達していた値から始まる Oracle のシーケンスになります。

配列、enum など PostgreSQL の型はどうなりますか?

配列は JSON 配列、boolean は NUMBER(1)、タイムゾーン付きの timestamp は TIMESTAMP WITH TIME ZONE、text は値が収まれば VARCHAR2、それ以外は CLOB になります。空文字列は Oracle の保存方法どおり NULL になり、レポートで件数を示します。

関数、トリガー、ビューはどうなりますか?

データベースごとに独自の言語で書かれるため、変換はせず、レポートに名前で一覧します。

スクリプトはどの Oracle バージョンで読み込めますか?

Oracle 19c 以降です。すべてのテスト用ダンプを 21c と 23ai で読み込み、問題があれば最初のエラーで止まります。