Converti PostgreSQL in Oracle
Trascina un dump plain di pg_dump o pg_dumpall, come .sql o .sql.gz, e scarica uno script per Oracle con le stesse tabelle, chiavi, indici e dati. Ogni valore che Oracle non può contenere così com'è, e ogni oggetto che non supporta, è elencato nel report.
18 righe convertite, 2 correzioni, nessuna rifiutata
Tabelle in shop_2024_postgres.sqlDump PostgreSQL 18.6 · scritto da pg_dump · utf8mb4
customersscritta come CUSTOMERS8 righe1
8 colonne ID NUMBER(10) not null NAME VARCHAR2(4000 CHAR) not null EMAIL VARCHAR2(750 CHAR) not null COUNTRY VARCHAR2(2 CHAR) not null IS_ACTIVE NUMBER(1) not null TAGS CLOB not null SIGNED_UP DATE CREATED_AT TIMESTAMP(6) WITH TIME ZONE not null ordersscritta come ORDERS10 righe1
10 colonne ID NUMBER(10) not null CUSTOMER_ID NUMBER(10) not null STATUS VARCHAR2(9 CHAR) not null TOTAL NUMBER(10,2) not null ITEMS NUMBER(5) not null ORDERED_AT TIMESTAMP(6) not null SHIPPED_AT TIMESTAMP(6) NOTE VARCHAR2(4000 CHAR) DETAILS CLOB DELIVERY VARCHAR2(100 CHAR)
Non convertiti
- Vista paid_orders
Ogni database li scrive nel proprio linguaggio. Riscrivili per 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;
Correzioni
- "tags" di customers è text[], che Oracle non ha, quindi è CLOB con gli stessi valori.
- "delivery" di orders è interval, che Oracle non ha, quindi è VARCHAR2(100 CHAR) con gli stessi valori.
Da controllare
- 1 vista, trigger, routine o evento non è convertito; il report li elenca uno per uno. Ricreali a mano in Oracle.
- Il valore predefinito di "tags" in customers non si può scrivere per Oracle (a value its type can't hold), quindi la colonna non ha un valore predefinito. Aggiungi a mano il valore predefinito se le nuove righe ne hanno bisogno.
- L'indice idx_orders_details su orders usa un'espressione che non si può scrivere per Oracle (a gin index), quindi non viene creato. Crea l'indice a mano se le query ne hanno bisogno.
- 1 valore in "shipped_at" di orders è una data che Oracle non può salvare, come infinity, quindi è NULL. Oracle salva gli anni dall'1 al 9999 senza infinito; sostituisci quelle date nella sorgente se contano.
Il tuo file viene convertito su questo computer e non viene mai caricato.
Altri esempi:
Cosa cambia da PostgreSQL a Oracle
Ogni riga è una regola che il convertitore applica, con la riga del report che scrive quando la regola cambia qualcosa nei tuoi dati.
boolean
NUMBER(1) con un CHECK di 0 e 1
Oracle 21c non ha un tipo di colonna booleano; 1 e 0 mantengono true e false su ogni versione.
varchar(n), char(n)
VARCHAR2(n CHAR), contando i caratteri
Le lunghezze contano i caratteri, come quelle di PostgreSQL.
text
VARCHAR2(4000 CHAR) quando ogni valore sta in 4000 byte (750 caratteri in una chiave), altrimenti CLOB
Un VARCHAR2 contiene 4000 byte di default e Oracle non può indicizzare un CLOB, quindi il testo resta VARCHAR2 quando i valori ci stanno ed è un CLOB quando no.
Riga del report: text_as_lob
empty strings and empty bytea values
NULL
Oracle salva una stringa vuota come NULL, quindi un valore che era ' si rilegge come NULL. Il report li conta per colonna.
Riga del report: empty_string_null
citext
confronto esatto
Oracle confronta il testo in modo esatto salvo indicazione diversa, come il text di PostgreSQL; le colonne citext non ignorano più le maiuscole.
Riga del report: case_insensitive_collation
numeric(p,s) past 38 digits; numeric without a precision
NUMBER quando i valori stanno in 38 cifre, altrimenti VARCHAR2
Il NUMBER di Oracle contiene 38 cifre con qualsiasi scala. I numeri più ampi restano testo così ogni cifra resta esatta.
Riga del report: decimal_as_text
money
NUMBER(19,2)
Oracle non ha un tipo money. L'importo resta un numero, senza il simbolo di valuta aggiunto dal locale del server.
Riga del report: type_replaced
interval
VARCHAR2(100 CHAR) con il testo di PostgreSQL
Un interval mescola mesi con giorni e secondi, che Oracle tiene in due tipi diversi; il testo mantiene ogni parte.
Riga del report: type_replaced
arrays (integer[], text[]...)
CLOB con un array JSON
Oracle non ha array. Un array JSON mantiene ogni elemento e i NULL, e JSON_TABLE lo legge.
Riga del report: type_replaced
ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension types
VARCHAR2 o CLOB con il testo di PostgreSQL
Oracle non ha un tipo equivalente, quindi ogni valore mantiene il testo scritto da PostgreSQL.
Riga del report: type_replaced
json, jsonb
CLOB
Le funzioni JSON di Oracle leggono il JSON dal testo su ogni versione, e un CLOB mantiene valori di qualsiasi dimensione.
timestamp
TIMESTAMP
Un timestamp senza fuso orario è l'ora letta su un orologio, come il TIMESTAMP di Oracle. date diventa DATE, che contiene anche un'ora del giorno che resta a mezzanotte.
timestamp with time zone
TIMESTAMP WITH TIME ZONE in UTC
Ogni valore è scritto in UTC, lo stesso istante qualunque offset abbia scritto il dump.
time
INTERVAL DAY TO SECOND dalla mezzanotte
Oracle non ha un tipo per l'ora del giorno; un intervallo dalla mezzanotte contiene ogni valore, 24:00:00 incluso.
infinity, -infinity, BC dates and years past 9999
NULL
Lo script scrive gli anni dall'1 al 9999, e Oracle non ha infinito. Quei valori diventano NULL e il report li conta.
Riga del report: date_out_of_range
NaN and Infinity in numeric
NULL
Il NUMBER di Oracle non ha NaN né Infinity, quindi quei valori diventano NULL e il report li conta.
Riga del report: invalid_value_null
NOT NULL columns with values that become NULL
NOT NULL rimosso
Una colonna i cui valori sono dovuti diventare NULL non può mantenere NOT NULL, altrimenti il caricamento si fermerebbe.
Riga del report: not_null_relaxed
enum types
VARCHAR2 con un CHECK delle sue etichette
Il testo con un vincolo CHECK mantiene gli stessi valori.
enum columns holding values outside their labels
VARCHAR2 senza CHECK
I valori che le etichette non nominano violerebbero il vincolo CHECK, quindi il vincolo non viene creato.
Riga del report: enum_check_skipped
uuid, inet, cidr, macaddr
VARCHAR2
Oracle non ha questi tipi; il testo mantiene ogni valore.
bytea
BLOB
I byte restano byte.
bit(n), bit varying
NUMBER con il valore dei bit fino a 63 bit; cifre come testo oltre
Le stringhe di bit sono salvate come il numero formato dai loro bit.
oid, xid, cid
NUMBER(10) con un CHECK che non sia negativo
NUMBER contiene ogni valore.
serial, identity
GENERATED BY DEFAULT ON NULL AS IDENTITY, che riparte dopo l'id più alto
Gli id copiati si caricano così come sono, e il contatore riparte dopo il più alto o dal valore successivo della sequenza, quello maggiore.
a second serial or identity column in a table
un intero semplice
Oracle conta una colonna identity per tabella; ogni altra mantiene i suoi valori senza contatore.
Riga del report: counter_dropped
sequences not owned by a column
CREATE SEQUENCE, al valore raggiunto
Le sequenze di Oracle funzionano allo stesso modo.
generated columns
colonne virtuali
Oracle calcola le colonne generate solo in lettura; le colonne STORED diventano virtuali con gli stessi valori.
Riga del report: stored_as_virtual
generated columns with functions Oracle lacks
una colonna semplice con i valori
Una formula che non si può scrivere per Oracle lascia una colonna semplice con i valori del dump e una riga nel report.
Riga del report: generated_not_translated
defaults with functions Oracle lacks, and defaults from a sequence
nessun valore predefinito
Un valore predefinito che non si può scrivere per Oracle viene omesso e segnalato.
Riga del report: default_not_translated
CHECK constraints
tradotti, dentro CREATE TABLE
I CHECK nella tabella si verificano mentre ogni riga si carica.
CHECK constraints with functions Oracle lacks
non creato
Un vincolo CHECK che non si può scrivere per Oracle viene omesso e segnalato.
Riga del report: check_skipped
CHECK ... NOT VALID
non creato
PostgreSQL non ha mai verificato le righe che c'erano prima, quindi potrebbero violarlo.
Riga del report: check_not_valid
gin, gist, brin and hash indexes, partial and expression indexes, and indexes on CLOB columns
non creato
IntoSQL scrive indici b-tree su colonne per Oracle, che non può indicizzare un CLOB; ricrea gli altri dopo il caricamento.
Riga del report: index_skipped
foreign keys
dopo i dati ENABLE NOVALIDATE, poi validata con un avviso sulle righe orfane
La chiave verifica subito le nuove righe e viene validata alla fine; righe senza padre la lasciano non validata con un avviso invece di fermare il caricamento.
ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT
rimosso
Le chiavi esterne di Oracle agiscono solo in eliminazione, con CASCADE o SET NULL.
Riga del report: foreign_key_action_unsupported
foreign keys to tables the dump doesn't create
non creato
Una chiave non può riferirsi a una tabella che non c'è.
Riga del report: foreign_key_skipped
names over 128 bytes
accorciato
Da Oracle 12.2 i nomi contengono 128 byte, più dei 63 di PostgreSQL.
Riga del report: name_shortened
partitioned tables
una tabella con le righe di ogni partizione
Le righe sono le stesse; partiziona di nuovo la tabella in Oracle se serve.
Riga del report: partitions_dropped
schemas
uno schema, tabelle con il nome del loro schema davanti
Lo script si carica nello schema dell'utente che lo esegue, quindi le tabelle di schemi diversi hanno davanti il nome del loro schema; le tabelle in public mantengono il loro nome.
Riga del report: schemas_merged
views, functions, procedures, triggers, rules, policies, extensions and types
elencati nel report
Il loro codice è scritto nel linguaggio di PostgreSQL, quindi vengono elencati perché tu li ricrei.
Riga del report: not_converted_objects
dumps without CREATE TABLE (--data-only)
tipi ricavati dai valori
Un dump di soli dati contiene solo righe, quindi i tipi vengono ricavati dai valori.
Riga del report: no_schema
expressions in INSERT values
NULL
Un convertitore che non esegue un database non può valutarle.
Riga del report: expression_value
types IntoSQL doesn't know
CLOB
Il testo contiene qualsiasi valore; cambia il tipo dopo il caricamento.
Riga del report: unknown_type
text that isn't valid in its encoding
i byte errati come carattere di sostituzione
Lo script è UTF-8 e si carica con NLS_LANG=.AL32UTF8.
Riga del report: invalid_utf8_replaced
text decoded twice (ñ)
copiato così com'è
Il dump contiene esattamente questi caratteri, quindi vengono copiati; il report li segnala.
Riga del report: mojibake_suspected
| In PostgreSQL | In Oracle | Riga del report |
|---|---|---|
| boolean | NUMBER(1) con un CHECK di 0 e 1Oracle 21c non ha un tipo di colonna booleano; 1 e 0 mantengono true e false su ogni versione. | |
| varchar(n), char(n) | VARCHAR2(n CHAR), contando i caratteriLe lunghezze contano i caratteri, come quelle di PostgreSQL. | |
| text | VARCHAR2(4000 CHAR) quando ogni valore sta in 4000 byte (750 caratteri in una chiave), altrimenti CLOBUn VARCHAR2 contiene 4000 byte di default e Oracle non può indicizzare un CLOB, quindi il testo resta VARCHAR2 quando i valori ci stanno ed è un CLOB quando no. | text_as_lob |
| empty strings and empty bytea values | NULLOracle salva una stringa vuota come NULL, quindi un valore che era ' si rilegge come NULL. Il report li conta per colonna. | empty_string_null |
| citext | confronto esattoOracle confronta il testo in modo esatto salvo indicazione diversa, come il text di PostgreSQL; le colonne citext non ignorano più le maiuscole. | case_insensitive_collation |
| numeric(p,s) past 38 digits; numeric without a precision | NUMBER quando i valori stanno in 38 cifre, altrimenti VARCHAR2Il NUMBER di Oracle contiene 38 cifre con qualsiasi scala. I numeri più ampi restano testo così ogni cifra resta esatta. | decimal_as_text |
| money | NUMBER(19,2)Oracle non ha un tipo money. L'importo resta un numero, senza il simbolo di valuta aggiunto dal locale del server. | type_replaced |
| interval | VARCHAR2(100 CHAR) con il testo di PostgreSQLUn interval mescola mesi con giorni e secondi, che Oracle tiene in due tipi diversi; il testo mantiene ogni parte. | type_replaced |
| arrays (integer[], text[]...) | CLOB con un array JSONOracle non ha array. Un array JSON mantiene ogni elemento e i NULL, e JSON_TABLE lo legge. | type_replaced |
| ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension types | VARCHAR2 o CLOB con il testo di PostgreSQLOracle non ha un tipo equivalente, quindi ogni valore mantiene il testo scritto da PostgreSQL. | type_replaced |
| json, jsonb | CLOBLe funzioni JSON di Oracle leggono il JSON dal testo su ogni versione, e un CLOB mantiene valori di qualsiasi dimensione. | |
| timestamp | TIMESTAMPUn timestamp senza fuso orario è l'ora letta su un orologio, come il TIMESTAMP di Oracle. date diventa DATE, che contiene anche un'ora del giorno che resta a mezzanotte. | |
| timestamp with time zone | TIMESTAMP WITH TIME ZONE in UTCOgni valore è scritto in UTC, lo stesso istante qualunque offset abbia scritto il dump. | |
| time | INTERVAL DAY TO SECOND dalla mezzanotteOracle non ha un tipo per l'ora del giorno; un intervallo dalla mezzanotte contiene ogni valore, 24:00:00 incluso. | |
| infinity, -infinity, BC dates and years past 9999 | NULLLo script scrive gli anni dall'1 al 9999, e Oracle non ha infinito. Quei valori diventano NULL e il report li conta. | date_out_of_range |
| NaN and Infinity in numeric | NULLIl NUMBER di Oracle non ha NaN né Infinity, quindi quei valori diventano NULL e il report li conta. | invalid_value_null |
| NOT NULL columns with values that become NULL | NOT NULL rimossoUna colonna i cui valori sono dovuti diventare NULL non può mantenere NOT NULL, altrimenti il caricamento si fermerebbe. | not_null_relaxed |
| enum types | VARCHAR2 con un CHECK delle sue etichetteIl testo con un vincolo CHECK mantiene gli stessi valori. | |
| enum columns holding values outside their labels | VARCHAR2 senza CHECKI valori che le etichette non nominano violerebbero il vincolo CHECK, quindi il vincolo non viene creato. | enum_check_skipped |
| uuid, inet, cidr, macaddr | VARCHAR2Oracle non ha questi tipi; il testo mantiene ogni valore. | |
| bytea | BLOBI byte restano byte. | |
| bit(n), bit varying | NUMBER con il valore dei bit fino a 63 bit; cifre come testo oltreLe stringhe di bit sono salvate come il numero formato dai loro bit. | |
| oid, xid, cid | NUMBER(10) con un CHECK che non sia negativoNUMBER contiene ogni valore. | |
| serial, identity | GENERATED BY DEFAULT ON NULL AS IDENTITY, che riparte dopo l'id più altoGli id copiati si caricano così come sono, e il contatore riparte dopo il più alto o dal valore successivo della sequenza, quello maggiore. | |
| a second serial or identity column in a table | un intero sempliceOracle conta una colonna identity per tabella; ogni altra mantiene i suoi valori senza contatore. | counter_dropped |
| sequences not owned by a column | CREATE SEQUENCE, al valore raggiuntoLe sequenze di Oracle funzionano allo stesso modo. | |
| generated columns | colonne virtualiOracle calcola le colonne generate solo in lettura; le colonne STORED diventano virtuali con gli stessi valori. | stored_as_virtual |
| generated columns with functions Oracle lacks | una colonna semplice con i valoriUna formula che non si può scrivere per Oracle lascia una colonna semplice con i valori del dump e una riga nel report. | generated_not_translated |
| defaults with functions Oracle lacks, and defaults from a sequence | nessun valore predefinitoUn valore predefinito che non si può scrivere per Oracle viene omesso e segnalato. | default_not_translated |
| CHECK constraints | tradotti, dentro CREATE TABLEI CHECK nella tabella si verificano mentre ogni riga si carica. | |
| CHECK constraints with functions Oracle lacks | non creatoUn vincolo CHECK che non si può scrivere per Oracle viene omesso e segnalato. | check_skipped |
| CHECK ... NOT VALID | non creatoPostgreSQL non ha mai verificato le righe che c'erano prima, quindi potrebbero violarlo. | check_not_valid |
| gin, gist, brin and hash indexes, partial and expression indexes, and indexes on CLOB columns | non creatoIntoSQL scrive indici b-tree su colonne per Oracle, che non può indicizzare un CLOB; ricrea gli altri dopo il caricamento. | index_skipped |
| foreign keys | dopo i dati ENABLE NOVALIDATE, poi validata con un avviso sulle righe orfaneLa chiave verifica subito le nuove righe e viene validata alla fine; righe senza padre la lasciano non validata con un avviso invece di fermare il caricamento. | |
| ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT | rimossoLe chiavi esterne di Oracle agiscono solo in eliminazione, con CASCADE o SET NULL. | foreign_key_action_unsupported |
| foreign keys to tables the dump doesn't create | non creatoUna chiave non può riferirsi a una tabella che non c'è. | foreign_key_skipped |
| names over 128 bytes | accorciatoDa Oracle 12.2 i nomi contengono 128 byte, più dei 63 di PostgreSQL. | name_shortened |
| partitioned tables | una tabella con le righe di ogni partizioneLe righe sono le stesse; partiziona di nuovo la tabella in Oracle se serve. | partitions_dropped |
| schemas | uno schema, tabelle con il nome del loro schema davantiLo script si carica nello schema dell'utente che lo esegue, quindi le tabelle di schemi diversi hanno davanti il nome del loro schema; le tabelle in public mantengono il loro nome. | schemas_merged |
| views, functions, procedures, triggers, rules, policies, extensions and types | elencati nel reportIl loro codice è scritto nel linguaggio di PostgreSQL, quindi vengono elencati perché tu li ricrei. | not_converted_objects |
| dumps without CREATE TABLE (--data-only) | tipi ricavati dai valoriUn dump di soli dati contiene solo righe, quindi i tipi vengono ricavati dai valori. | no_schema |
| expressions in INSERT values | NULLUn convertitore che non esegue un database non può valutarle. | expression_value |
| types IntoSQL doesn't know | CLOBIl testo contiene qualsiasi valore; cambia il tipo dopo il caricamento. | unknown_type |
| text that isn't valid in its encoding | i byte errati come carattere di sostituzioneLo script è UTF-8 e si carica con NLS_LANG=.AL32UTF8. | invalid_utf8_replaced |
| text decoded twice (ñ) | copiato così com'èIl dump contiene esattamente questi caratteri, quindi vengono copiati; il report li segnala. | mojibake_suspected |
Carica lo script in Oracle
Lo script crea le tabelle, copia le righe, poi aggiunge chiavi, indici e chiavi esterne, così si carica in fretta e si ferma al primo errore.
NLS_LANG=.AL32UTF8 sqlplus -S -L user@//localhost/mydb @postgresql.oracle.sqlLe chiavi esterne vengono aggiunte ENABLE NOVALIDATE, così le nuove righe sono controllate subito, e poi validate. Se una riga vecchia punta a una riga che non esiste, lo script dice quale vincolo e lo lascia non validato, invece di fallire a metà.
Per un dump grande, esegui SQL*Plus sulla stessa macchina del database. Lo script fa il commit ogni 100 righe. L'utente che lo esegue ha bisogno di CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER e CREATE PROCEDURE, e di una quota sul suo tablespace.
Fai il dump di PostgreSQL per il miglior risultato
Il convertitore legge ciò che il dump contiene. Con queste opzioni il dump conserva più dei tuoi dati:
- --format=plain, il default di pg_dump, scrive SQL. Un archivio custom o directory (-Fc, -Fd) diventa SQL con pg_restore -f dump.sql, senza un server di database.
- --no-owner --no-privileges escludono ruoli e permessi, che il convertitore comunque salta, così il dump è più piccolo.
- pg_dumpall esporta ogni database in un solo file; le tabelle di ognuno hanno il suo nome davanti, così niente entra in conflitto.
Cosa non viene convertito
Viste, viste materializzate, funzioni, procedure, trigger, regole, policy di sicurezza a livello di riga, estensioni e tipi sono scritti nel linguaggio di PostgreSQL. Sono elencati per nome nel report, mai rimossi in silenzio, così puoi riscriverli per Oracle.
Domande sulla conversione da PostgreSQL a Oracle
Non trovi la risposta? Scrivici dalla pagina dei contatti e ti risponde una persona. Pagina dei contatti
Il mio dump viene caricato?
No. Il convertitore funziona nel tuo browser e legge il dump dal tuo disco a pezzi, quindi non lascia mai il tuo computer. Anche l'app desktop e la riga di comando convertono sul tuo computer.
Quanto può essere grande il dump?
Il convertitore non tiene mai l'intero dump in memoria: legge il file due volte, per intervalli, e scrive lo script man mano. I dump di più gigabyte si convertono nel browser, nell'app desktop e con la riga di comando.
Legge gli archivi pg_dump -Fc?
Non direttamente: un archivio custom è un formato binario. pg_restore -f dump.sql dump.backup lo trasforma nel SQL plain che il convertitore legge, senza connettersi a un server. Il convertitore lo dice quando riceve un archivio.
Da quali versioni di PostgreSQL può provenire il dump?
Dump scritti da pg_dump e pg_dumpall da PostgreSQL 10 in poi, con righe COPY o INSERT. Ogni dump di test viene da PostgreSQL 13 e 18 ed è confrontato con la sorgente cella per cella.
I valori serial e identity vengono mantenuti?
Sì. La colonna serial o identity di ogni tabella diventa una colonna identity, ogni riga mantiene il suo id e l'id successivo riparte dopo il più alto. Le sequenze non legate a una colonna diventano sequenze di Oracle al valore raggiunto.
Cosa succede ad array, enum e altri tipi di PostgreSQL?
Gli array diventano array JSON, i booleani NUMBER(1), i timestamp con fuso orario TIMESTAMP WITH TIME ZONE e il testo VARCHAR2 quando i valori ci stanno, altrimenti CLOB. Le stringhe vuote diventano NULL, come le salva Oracle, e il report le conta.
E funzioni, trigger e viste?
Sono elencati per nome nel report e non vengono convertiti, perché ogni database li scrive nel proprio linguaggio.
Su quali versioni di Oracle si carica lo script?
Oracle 19c e successive. Ogni dump di test si carica su 21c e 23ai, fermandosi al primo errore se qualcosa va storto.