Przejdź do treści
Strona główna IntoSQL

Konwertuj PostgreSQL do Oracle

Upuść zwykły zrzut z pg_dump lub pg_dumpall jako .sql lub .sql.gz i pobierz skrypt Oracle z tymi samymi tabelami, kluczami, indeksami i danymi. Każda wartość, której Oracle nie może przechować bez zmian, i każdy obiekt, którego nie przenosi, są wymienione w raporcie.

Twój plik
sqlshop_2024_postgres.sqlPlik przykładowy, 6,2 kB
Twoja baza danych

18 wierszy przekonwertowanych, 2 poprawki, brak odrzuconych

Pokaż

Tabele w pliku shop_2024_postgres.sqlZrzut PostgreSQL 18.6 · zapisany przez pg_dump · utf8mb4

  • customerszapisana jako CUSTOMERS8 wierszy1
    8 kolumn
    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
  • orderszapisana jako ORDERS10 wierszy1
    10 kolumn
    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)

Nieprzekonwertowane

  • Widok paid_orders

Każda baza danych zapisuje je we własnym języku. Przepisz je dla 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;

Poprawki

  1. "tags" w tabeli customers to text[], czego Oracle nie ma, więc ma typ CLOB z tymi samymi wartościami.
  2. "delivery" w tabeli orders to interval, czego Oracle nie ma, więc ma typ VARCHAR2(100 CHAR) z tymi samymi wartościami.

Do sprawdzenia

  • Widoki, wyzwalacze, procedury i zdarzenia nie są konwertowane: 1 obiekt, każdy wymieniony w raporcie. Utwórz je ręcznie w Oracle.
  • Wartości domyślnej "tags" w tabeli customers nie da się zapisać dla Oracle (a value its type can't hold), więc kolumna nie ma wartości domyślnej. Dodaj wartość domyślną ręcznie, jeśli nowe wiersze jej potrzebują.
  • Indeks idx_orders_details w tabeli orders używa wyrażenia, którego nie da się zapisać dla Oracle (a gin index), więc go nie utworzono. Utwórz indeks ręcznie, jeśli zapytania go potrzebują.
  • W "shipped_at" tabeli orders 1 data poza zakresem Oracle, np. infinity, staje się NULL. Oracle przechowuje lata od 1 do 9999 bez nieskończoności; jeśli te daty są ważne, zastąp je w źródle.

Plik jest konwertowany na tym komputerze i nigdy nie jest wysyłany.

Inne przykłady:

Co zmienia się między PostgreSQL a Oracle

Każdy wiersz to reguła stosowana przez konwerter, z wpisem, który dodaje do raportu, gdy reguła coś zmienia w twoich danych.

  • boolean

    NUMBER(1) z CHECK 0 i 1

    Oracle 21c nie ma typu kolumny logicznej; 1 i 0 zachowują true i false w każdej wersji.

  • varchar(n), char(n)

    VARCHAR2(n CHAR), liczony w znakach

    Długości liczą znaki, tak jak w PostgreSQL.

  • text

    VARCHAR2(4000 CHAR), gdy każda wartość mieści się w 4000 bajtach (750 znakach w kluczu), w przeciwnym razie CLOB

    VARCHAR2 mieści domyślnie 4000 bajtów, a Oracle nie indeksuje CLOB, więc tekst zostaje VARCHAR2, gdy jego wartości się mieszczą, a CLOB, gdy nie.

    Wpis w raporcie: text_as_lob

  • empty strings and empty bytea values

    NULL

    Oracle zapisuje pusty ciąg jako NULL, więc wartość ' jest odczytywana jako NULL. Raport liczy je w każdej kolumnie.

    Wpis w raporcie: empty_string_null

  • citext

    dokładne porównanie

    Oracle porównuje tekst dokładnie, chyba że ustawisz inaczej, jak text w PostgreSQL; kolumny citext przestają ignorować wielkość liter.

    Wpis w raporcie: case_insensitive_collation

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

    NUMBER, gdy wartości mieszczą się w 38 cyfrach, w przeciwnym razie VARCHAR2

    NUMBER w Oracle mieści 38 cyfr przy dowolnej skali. Szersze liczby są zapisywane jako tekst, aby każda cyfra pozostała dokładna.

    Wpis w raporcie: decimal_as_text

  • money

    NUMBER(19,2)

    Oracle nie ma typu money. Kwota jest zapisywana jako liczba, bez symbolu waluty dodanego przez ustawienia regionalne serwera.

    Wpis w raporcie: type_replaced

  • interval

    VARCHAR2(100 CHAR) z tekstem PostgreSQL

    interval łączy miesiące z dniami i sekundami, które Oracle trzyma w dwóch różnych typach; tekst zachowuje każdą część.

    Wpis w raporcie: type_replaced

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

    CLOB z tablicą JSON

    Oracle nie ma tablic. Tablica JSON zachowuje każdy element i NULL, a JSON_TABLE ją odczytuje.

    Wpis w raporcie: type_replaced

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

    VARCHAR2 lub CLOB z tekstem PostgreSQL

    Oracle nie ma odpowiedniego typu, więc każda wartość zachowuje tekst zapisany przez PostgreSQL.

    Wpis w raporcie: type_replaced

  • json, jsonb

    CLOB

    Funkcje JSON w Oracle odczytują JSON z tekstu w każdej wersji, a CLOB mieści wartości dowolnego rozmiaru.

  • timestamp

    TIMESTAMP

    timestamp bez strefy czasowej to wskazanie zegara, jak TIMESTAMP w Oracle. date staje się DATE, który zawiera też godzinę, ustawioną na północ.

  • timestamp with time zone

    TIMESTAMP WITH TIME ZONE w UTC

    Każda wartość jest zapisywana w UTC, ten sam moment niezależnie od przesunięcia w zrzucie.

  • time

    INTERVAL DAY TO SECOND od północy

    Oracle nie ma typu godziny dnia; interwał od północy mieści każdą wartość, łącznie z 24:00:00.

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

    NULL

    Skrypt zapisuje lata od 1 do 9999, a Oracle nie ma nieskończoności. Te wartości stają się NULL, a raport je liczy.

    Wpis w raporcie: date_out_of_range

  • NaN and Infinity in numeric

    NULL

    NUMBER w Oracle nie ma NaN ani Infinity, więc te wartości stają się NULL, a raport je liczy.

    Wpis w raporcie: invalid_value_null

  • NOT NULL columns with values that become NULL

    NOT NULL usunięte

    Kolumna, której wartości musiały stać się NULL, nie może zachować NOT NULL, bo ładowanie by się zatrzymało.

    Wpis w raporcie: not_null_relaxed

  • enum types

    VARCHAR2 z CHECK jego etykiet

    Tekst z ograniczeniem CHECK zachowuje te same wartości.

  • enum columns holding values outside their labels

    VARCHAR2 bez CHECK

    Wartości spoza etykiet nie przeszłyby ograniczenia CHECK, więc nie jest ono tworzone.

    Wpis w raporcie: enum_check_skipped

  • uuid, inet, cidr, macaddr

    VARCHAR2

    Oracle nie ma takich typów; tekst zachowuje każdą wartość.

  • bytea

    BLOB

    Bajty pozostają bajtami.

  • bit(n), bit varying

    NUMBER z wartością bitów do 63 bitów; powyżej cyfry jako tekst

    Ciągi bitów są zapisywane jako liczba, którą tworzą ich bity.

  • oid, xid, cid

    NUMBER(10) z CHECK, że wartość nie jest ujemna

    NUMBER mieści każdą wartość.

  • serial, identity

    GENERATED BY DEFAULT ON NULL AS IDENTITY, kontynuowane po najwyższym id

    Skopiowane id ładują się bez zmian, a licznik idzie dalej od najwyższego z nich lub od następnej wartości sekwencji, zależnie od tego, która jest wyższa.

  • a second serial or identity column in a table

    zwykła liczba całkowita

    Oracle liczy jedną kolumnę identity na tabelę; każda inna zachowuje wartości bez licznika.

    Wpis w raporcie: counter_dropped

  • sequences not owned by a column

    CREATE SEQUENCE, od osiągniętej wartości

    Sekwencje w Oracle działają tak samo.

  • generated columns

    kolumny wirtualne

    Oracle oblicza kolumny generowane tylko przy odczycie; kolumny STORED stają się wirtualne z tymi samymi wartościami.

    Wpis w raporcie: stored_as_virtual

  • generated columns with functions Oracle lacks

    zwykła kolumna z wartościami

    Formuła, której nie da się zapisać dla Oracle, zostawia zwykłą kolumnę z wartościami ze zrzutu i wpis w raporcie.

    Wpis w raporcie: generated_not_translated

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

    brak wartości domyślnej

    Wartość domyślna, której nie da się zapisać dla Oracle, jest pomijana i zgłaszana w raporcie.

    Wpis w raporcie: default_not_translated

  • CHECK constraints

    przetłumaczone, wewnątrz CREATE TABLE

    CHECK w definicji tabeli działa przy ładowaniu każdego wiersza.

  • CHECK constraints with functions Oracle lacks

    nie jest tworzone

    Ograniczenie CHECK, którego nie da się zapisać dla Oracle, jest pomijane i zgłaszane w raporcie.

    Wpis w raporcie: check_skipped

  • CHECK ... NOT VALID

    nie jest tworzone

    PostgreSQL nigdy nie sprawdził wierszy, które były wcześniej, więc mogą je łamać.

    Wpis w raporcie: check_not_valid

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

    nie jest tworzone

    IntoSQL zapisuje dla Oracle indeksy b-tree na kolumnach, a Oracle nie indeksuje CLOB; pozostałe utwórz ponownie po załadowaniu.

    Wpis w raporcie: index_skipped

  • foreign keys

    po danych z ENABLE NOVALIDATE, potem walidowany z ostrzeżeniem o osieroconych wierszach

    Klucz od razu sprawdza nowe wiersze i jest walidowany na końcu; wiersze bez rodzica zostawiają go niezwalidowanym z ostrzeżeniem, zamiast zatrzymać ładowanie.

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

    usunięte

    Klucze obce w Oracle działają tylko przy usuwaniu, z CASCADE lub SET NULL.

    Wpis w raporcie: foreign_key_action_unsupported

  • foreign keys to tables the dump doesn't create

    nie jest tworzone

    Klucz nie może wskazywać tabeli, której nie ma.

    Wpis w raporcie: foreign_key_skipped

  • names over 128 bytes

    skrócone

    Nazwy w Oracle 12.2 i nowszym mają do 128 bajtów, więcej niż 63 w PostgreSQL.

    Wpis w raporcie: name_shortened

  • partitioned tables

    jedna tabela z wierszami wszystkich partycji

    Wiersze są te same; jeśli trzeba, podziel tabelę na partycje ponownie w Oracle.

    Wpis w raporcie: partitions_dropped

  • schemas

    jeden schemat, nazwa każdej tabeli zaczyna się od nazwy jej schematu

    Skrypt ładuje się do schematu użytkownika, który go uruchamia, więc tabele z różnych schematów dostają na początku nazwę swojego schematu; tabele z public zachowują nazwy.

    Wpis w raporcie: schemas_merged

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

    wymienione w raporcie

    Ich kod jest napisany w języku PostgreSQL, więc trafiają na listę do ręcznego odtworzenia.

    Wpis w raporcie: not_converted_objects

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

    typy odczytane z wartości

    Zrzut samych danych zawiera tylko wiersze, więc typy pochodzą z wartości.

    Wpis w raporcie: no_schema

  • expressions in INSERT values

    NULL

    Konwerter, który nie uruchamia bazy danych, nie może ich obliczyć.

    Wpis w raporcie: expression_value

  • types IntoSQL doesn't know

    CLOB

    Tekst mieści każdą wartość; zmień typ po załadowaniu.

    Wpis w raporcie: unknown_type

  • text that isn't valid in its encoding

    błędne bajty jako znak zastępczy

    Skrypt jest w UTF-8 i ładuje się z NLS_LANG=.AL32UTF8.

    Wpis w raporcie: invalid_utf8_replaced

  • text decoded twice (ñ)

    skopiowane bez zmian

    Zrzut zawiera dokładnie te znaki, więc są kopiowane; raport je wskazuje.

    Wpis w raporcie: mojibake_suspected

W PostgreSQLW OracleWpis w raporcie
booleanNUMBER(1) z CHECK 0 i 1Oracle 21c nie ma typu kolumny logicznej; 1 i 0 zachowują true i false w każdej wersji.
varchar(n), char(n)VARCHAR2(n CHAR), liczony w znakachDługości liczą znaki, tak jak w PostgreSQL.
textVARCHAR2(4000 CHAR), gdy każda wartość mieści się w 4000 bajtach (750 znakach w kluczu), w przeciwnym razie CLOBVARCHAR2 mieści domyślnie 4000 bajtów, a Oracle nie indeksuje CLOB, więc tekst zostaje VARCHAR2, gdy jego wartości się mieszczą, a CLOB, gdy nie.text_as_lob
empty strings and empty bytea valuesNULLOracle zapisuje pusty ciąg jako NULL, więc wartość ' jest odczytywana jako NULL. Raport liczy je w każdej kolumnie.empty_string_null
citextdokładne porównanieOracle porównuje tekst dokładnie, chyba że ustawisz inaczej, jak text w PostgreSQL; kolumny citext przestają ignorować wielkość liter.case_insensitive_collation
numeric(p,s) past 38 digits; numeric without a precisionNUMBER, gdy wartości mieszczą się w 38 cyfrach, w przeciwnym razie VARCHAR2NUMBER w Oracle mieści 38 cyfr przy dowolnej skali. Szersze liczby są zapisywane jako tekst, aby każda cyfra pozostała dokładna.decimal_as_text
moneyNUMBER(19,2)Oracle nie ma typu money. Kwota jest zapisywana jako liczba, bez symbolu waluty dodanego przez ustawienia regionalne serwera.type_replaced
intervalVARCHAR2(100 CHAR) z tekstem PostgreSQLinterval łączy miesiące z dniami i sekundami, które Oracle trzyma w dwóch różnych typach; tekst zachowuje każdą część.type_replaced
arrays (integer[], text[]...)CLOB z tablicą JSONOracle nie ma tablic. Tablica JSON zachowuje każdy element i NULL, a JSON_TABLE ją odczytuje.type_replaced
ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension typesVARCHAR2 lub CLOB z tekstem PostgreSQLOracle nie ma odpowiedniego typu, więc każda wartość zachowuje tekst zapisany przez PostgreSQL.type_replaced
json, jsonbCLOBFunkcje JSON w Oracle odczytują JSON z tekstu w każdej wersji, a CLOB mieści wartości dowolnego rozmiaru.
timestampTIMESTAMPtimestamp bez strefy czasowej to wskazanie zegara, jak TIMESTAMP w Oracle. date staje się DATE, który zawiera też godzinę, ustawioną na północ.
timestamp with time zoneTIMESTAMP WITH TIME ZONE w UTCKażda wartość jest zapisywana w UTC, ten sam moment niezależnie od przesunięcia w zrzucie.
timeINTERVAL DAY TO SECOND od północyOracle nie ma typu godziny dnia; interwał od północy mieści każdą wartość, łącznie z 24:00:00.
infinity, -infinity, BC dates and years past 9999NULLSkrypt zapisuje lata od 1 do 9999, a Oracle nie ma nieskończoności. Te wartości stają się NULL, a raport je liczy.date_out_of_range
NaN and Infinity in numericNULLNUMBER w Oracle nie ma NaN ani Infinity, więc te wartości stają się NULL, a raport je liczy.invalid_value_null
NOT NULL columns with values that become NULLNOT NULL usunięteKolumna, której wartości musiały stać się NULL, nie może zachować NOT NULL, bo ładowanie by się zatrzymało.not_null_relaxed
enum typesVARCHAR2 z CHECK jego etykietTekst z ograniczeniem CHECK zachowuje te same wartości.
enum columns holding values outside their labelsVARCHAR2 bez CHECKWartości spoza etykiet nie przeszłyby ograniczenia CHECK, więc nie jest ono tworzone.enum_check_skipped
uuid, inet, cidr, macaddrVARCHAR2Oracle nie ma takich typów; tekst zachowuje każdą wartość.
byteaBLOBBajty pozostają bajtami.
bit(n), bit varyingNUMBER z wartością bitów do 63 bitów; powyżej cyfry jako tekstCiągi bitów są zapisywane jako liczba, którą tworzą ich bity.
oid, xid, cidNUMBER(10) z CHECK, że wartość nie jest ujemnaNUMBER mieści każdą wartość.
serial, identityGENERATED BY DEFAULT ON NULL AS IDENTITY, kontynuowane po najwyższym idSkopiowane id ładują się bez zmian, a licznik idzie dalej od najwyższego z nich lub od następnej wartości sekwencji, zależnie od tego, która jest wyższa.
a second serial or identity column in a tablezwykła liczba całkowitaOracle liczy jedną kolumnę identity na tabelę; każda inna zachowuje wartości bez licznika.counter_dropped
sequences not owned by a columnCREATE SEQUENCE, od osiągniętej wartościSekwencje w Oracle działają tak samo.
generated columnskolumny wirtualneOracle oblicza kolumny generowane tylko przy odczycie; kolumny STORED stają się wirtualne z tymi samymi wartościami.stored_as_virtual
generated columns with functions Oracle lackszwykła kolumna z wartościamiFormuła, której nie da się zapisać dla Oracle, zostawia zwykłą kolumnę z wartościami ze zrzutu i wpis w raporcie.generated_not_translated
defaults with functions Oracle lacks, and defaults from a sequencebrak wartości domyślnejWartość domyślna, której nie da się zapisać dla Oracle, jest pomijana i zgłaszana w raporcie.default_not_translated
CHECK constraintsprzetłumaczone, wewnątrz CREATE TABLECHECK w definicji tabeli działa przy ładowaniu każdego wiersza.
CHECK constraints with functions Oracle lacksnie jest tworzoneOgraniczenie CHECK, którego nie da się zapisać dla Oracle, jest pomijane i zgłaszane w raporcie.check_skipped
CHECK ... NOT VALIDnie jest tworzonePostgreSQL nigdy nie sprawdził wierszy, które były wcześniej, więc mogą je łamać.check_not_valid
gin, gist, brin and hash indexes, partial and expression indexes, and indexes on CLOB columnsnie jest tworzoneIntoSQL zapisuje dla Oracle indeksy b-tree na kolumnach, a Oracle nie indeksuje CLOB; pozostałe utwórz ponownie po załadowaniu.index_skipped
foreign keyspo danych z ENABLE NOVALIDATE, potem walidowany z ostrzeżeniem o osieroconych wierszachKlucz od razu sprawdza nowe wiersze i jest walidowany na końcu; wiersze bez rodzica zostawiają go niezwalidowanym z ostrzeżeniem, zamiast zatrzymać ładowanie.
ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULTusunięteKlucze obce w Oracle działają tylko przy usuwaniu, z CASCADE lub SET NULL.foreign_key_action_unsupported
foreign keys to tables the dump doesn't createnie jest tworzoneKlucz nie może wskazywać tabeli, której nie ma.foreign_key_skipped
names over 128 bytesskróconeNazwy w Oracle 12.2 i nowszym mają do 128 bajtów, więcej niż 63 w PostgreSQL.name_shortened
partitioned tablesjedna tabela z wierszami wszystkich partycjiWiersze są te same; jeśli trzeba, podziel tabelę na partycje ponownie w Oracle.partitions_dropped
schemasjeden schemat, nazwa każdej tabeli zaczyna się od nazwy jej schematuSkrypt ładuje się do schematu użytkownika, który go uruchamia, więc tabele z różnych schematów dostają na początku nazwę swojego schematu; tabele z public zachowują nazwy.schemas_merged
views, functions, procedures, triggers, rules, policies, extensions and typeswymienione w raporcieIch kod jest napisany w języku PostgreSQL, więc trafiają na listę do ręcznego odtworzenia.not_converted_objects
dumps without CREATE TABLE (--data-only)typy odczytane z wartościZrzut samych danych zawiera tylko wiersze, więc typy pochodzą z wartości.no_schema
expressions in INSERT valuesNULLKonwerter, który nie uruchamia bazy danych, nie może ich obliczyć.expression_value
types IntoSQL doesn't knowCLOBTekst mieści każdą wartość; zmień typ po załadowaniu.unknown_type
text that isn't valid in its encodingbłędne bajty jako znak zastępczySkrypt jest w UTF-8 i ładuje się z NLS_LANG=.AL32UTF8.invalid_utf8_replaced
text decoded twice (ñ)skopiowane bez zmianZrzut zawiera dokładnie te znaki, więc są kopiowane; raport je wskazuje.mojibake_suspected

Załaduj skrypt do Oracle

Skrypt tworzy tabele, kopiuje wiersze, a potem dodaje klucze, indeksy i klucze obce, więc ładuje się szybko i zatrzymuje przy pierwszym błędzie.

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

Klucze obce są dodawane z ENABLE NOVALIDATE, więc nowe wiersze są sprawdzane od razu, a potem walidowane. Jeśli stary wiersz wskazuje na nieistniejący wiersz, skrypt podaje, którego ograniczenia to dotyczy, i zostawia je niezwalidowane, zamiast przerwać w połowie.

Przy dużym zrzucie uruchom SQL*Plus na tej samej maszynie co baza danych. Skrypt zatwierdza co 100 wierszy. Użytkownik, który go uruchamia, potrzebuje CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER i CREATE PROCEDURE oraz limitu w swojej przestrzeni tabel.

Jak zrobić zrzut PostgreSQL dla najlepszego wyniku

Konwerter odczytuje to, co zawiera zrzut. Te opcje zachowują w nim więcej twoich danych:

  • --format=plain, domyślny w pg_dump, zapisuje SQL. Archiwum custom lub directory (-Fc, -Fd) zamienisz na SQL poleceniem pg_restore -f dump.sql, bez serwera bazy danych.
  • --no-owner --no-privileges pomijają role i uprawnienia, które konwerter i tak pomija, więc zrzut jest mniejszy.
  • pg_dumpall zapisuje każdą bazę danych w jednym pliku; nazwy tabel każdej z nich zaczynają się od jej nazwy, więc nic się nie powtarza.

Co nie jest konwertowane

Widoki, widoki zmaterializowane, funkcje, procedury, wyzwalacze, reguły, polityki bezpieczeństwa wierszy, rozszerzenia i typy są pisane we własnym języku PostgreSQL. Raport wymienia je z nazwy i nigdy nie pomija ich po cichu, więc możesz je przepisać dla Oracle.

Pytania o konwersję PostgreSQL do Oracle

Nie ma tu odpowiedzi? Napisz do nas przez stronę kontaktu, a odpowie człowiek. Strona kontaktu

Czy mój zrzut jest wysyłany?

Nie. Konwerter działa w przeglądarce i odczytuje zrzut z dysku po kawałku, więc nigdy nie opuszcza on twojego komputera. Aplikacja na komputer i wiersz poleceń też konwertują na twoim komputerze.

Jak duży może być zrzut?

Konwerter nigdy nie trzyma całego zrzutu w pamięci: czyta plik dwa razy, fragmentami, i zapisuje skrypt na bieżąco. Zrzuty wielogigabajtowe konwertują się w przeglądarce, w aplikacji na komputer i w wierszu poleceń.

Czy odczytuje archiwa pg_dump -Fc?

Nie bezpośrednio: archiwum custom to format binarny. pg_restore -f dump.sql dump.backup zamienia je na zwykły SQL, który czyta konwerter, bez łączenia z serwerem. Konwerter informuje o tym, gdy dostanie archiwum.

Z jakich wersji PostgreSQL może pochodzić zrzut?

Zrzuty zapisane przez pg_dump i pg_dumpall z PostgreSQL od wersji 10, z wierszami COPY lub INSERT. Każdy testowy zrzut pochodzi z PostgreSQL 13 i 18 i jest porównywany ze źródłem komórka po komórce.

Czy wartości serial i identity są zachowywane?

Tak. Kolumna serial lub identity każdej tabeli staje się kolumną identity, każdy wiersz zachowuje swoje id, a kolejne id idzie po najwyższym. Sekwencje niepowiązane z kolumną stają się sekwencjami Oracle od osiągniętej wartości.

Co dzieje się z tablicami, typami enum i innymi typami PostgreSQL?

Tablice stają się tablicami JSON, wartości logiczne NUMBER(1), znaczniki czasu ze strefą TIMESTAMP WITH TIME ZONE, a tekst VARCHAR2, gdy wartości się mieszczą, w przeciwnym razie CLOB. Puste ciągi stają się NULL, bo tak zapisuje je Oracle, a raport je liczy.

A funkcje, wyzwalacze i widoki?

Raport wymienia je z nazwy, ale nie są konwertowane, bo każda baza danych zapisuje je we własnym języku.

Na jakich wersjach Oracle ładuje się skrypt?

Oracle 19c i nowsze. Każdy testowy zrzut ładuje się na 21c i 23ai i zatrzymuje przy pierwszym błędzie, jeśli coś pójdzie nie tak.