Passer un export Oracle vers un Oracle plus ancien ou plus récent
Déposez le fichier .sql qu'écrit Database Export de SQL Developer ou SQLcl, avec ses tables et ses Insert, et téléchargez un script qui se charge sur Oracle 19c et suivants. NUMBER, DATE, TIMESTAMP, les LOB, identités et séquences restent tels quels, XMLTYPE et JSON gardent leur texte dans un CLOB, et chaque changement figure dans le rapport.
18 lignes converties, aucune correction, aucune rejetée
Tables de shop_2024_oracle.sqlDump Oracle · écrit par SQL Developer · utf-8
customersécrite sous le nom CUSTOMERS8 lignes
7 colonnes ID NUMBER(10,0) not null NAME VARCHAR2(100 CHAR) not null EMAIL VARCHAR2(150 CHAR) not null COUNTRY CHAR(2 BYTE) not null IS_ACTIVE NUMBER(1,0) not null SIGNED_UP DATE CREATED_AT TIMESTAMP(0) not null ordersécrite sous le nom ORDERS10 lignes
9 colonnes ID NUMBER(10,0) not null CUSTOMER_ID NUMBER(10,0) not null INVOICE NUMBER(10,0) STATUS VARCHAR2(10 CHAR) not null TOTAL NUMBER(10,2) not null ITEMS NUMBER(5,0) not null ORDERED_AT DATE not null SHIPPED_AT DATE NOTE VARCHAR2(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;
Corrections
Rien n'avait besoin d'être corrigé.
Votre fichier est converti sur cet ordinateur et n'est jamais envoyé.
Autres exemples :
Ce qui change entre le fichier et le script
Chaque ligne est une règle appliquée par le convertisseur, avec la ligne de rapport qu'il écrit quand la règle change quelque chose dans vos données.
BOOLEAN (23ai)
BOOLEAN sur 23ai, sinon NUMBER(1) avec un CHECK de 0 et 1
TRUE et FALSE restent true et false.
VARCHAR2(n BYTE|CHAR), NVARCHAR2(n), CHAR(n), NCHAR(n), CLOB, NCLOB, LONG
les mêmes types, avec leurs longueurs BYTE ou CHAR
Les mêmes types texte ; LONG devient CLOB, que chaque version depuis la 8 préfère.
VARCHAR2 and NVARCHAR2 past what the target's own types hold
VARCHAR2(4000 CHAR) si chaque valeur tient en 4000 octets, sinon CLOB
Un VARCHAR2 contient 4000 octets par défaut et Oracle ne peut pas indexer un CLOB ; le texte garde donc VARCHAR2 si ses valeurs y tiennent, sinon il devient CLOB.
Ligne du rapport: text_as_lob
NUMBER, NUMBER(p,s), FLOAT(b)
les mêmes types NUMBER
Les mêmes types NUMBER et FLOAT, avec chaque chiffre.
INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND
les mêmes types INTERVAL
Les mêmes intervalles.
DATE, TIMESTAMP(p)
DATE et TIMESTAMP(p), tels que déclarés
Les mêmes types ; chaque date garde donc son heure à la seconde près.
TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE
les mêmes types
Oracle garde les décalages de -12:00 à +14:00 ; une valeur dont le décalage dépasse -12:00 est écrite en UTC, le même instant.
JSON (21c), and CLOB holding JSON
JSON à partir de 21c, sinon CLOB
Les mêmes valeurs JSON ; un NULL SQL que l'export a écrit 'null' reste NULL.
BLOB, RAW(n), LONG RAW
les mêmes types ; LONG RAW en BLOB
Les octets restent des octets.
ROWID, UROWID, XMLTYPE, SDO_GEOMETRY
CLOB avec leur texte
XMLTYPE, ROWID et UROWID gardent leur texte dans un CLOB, pour que le script se charge sur chaque version depuis 19c.
Ligne du rapport: type_replaced
collations that ignore case (BINARY_CI)
comparaison exacte
Les collations de colonne ne sont pas écrites ; une colonne insensible à la casse (BINARY_CI) distingue donc maintenant Ana et ana.
Ligne du rapport: case_insensitive_collation
identity columns, and a sequence a BEFORE INSERT trigger assigns
GENERATED BY DEFAULT ON NULL AS IDENTITY, qui reprend après l'identifiant le plus élevé
Les identifiants copiés se chargent tels quels, et le compteur reprend après le plus élevé. Une colonne qu'un déclencheur remplit depuis une séquence (la méthode d'avant 12c) devient aussi une colonne d'identité.
identity columns the target can't count
un entier simple
Oracle compte une colonne d'identité par table ; toute autre garde ses valeurs sans compteur.
Ligne du rapport: counter_dropped
CREATE SEQUENCE
CREATE SEQUENCE avec les mêmes options
L'export écrit où en est une séquence comme son START WITH ; elle reprend donc à partir de là.
virtual columns (GENERATED ALWAYS AS ... VIRTUAL)
colonnes virtuelles
Les mêmes colonnes virtuelles.
Ligne du rapport: stored_as_virtual
virtual columns with functions IntoSQL doesn't write, and the || operator
une colonne simple
Une formule qui ne peut pas être écrite pour Oracle laisse une colonne simple et une ligne dans le rapport ; les valeurs que l'export a écrites pour les colonnes virtuelles sont omises, et Oracle ne peut pas les calculer.
Ligne du rapport: generated_not_translated
defaults with functions IntoSQL doesn't write (SYS_GUID(), ||)
aucune valeur par défaut
Une valeur par défaut qui ne peut pas être écrite est omise et signalée.
Ligne du rapport: default_not_translated
CHECK constraints
traduites
Les mêmes contraintes CHECK, vérifiées au chargement de chaque ligne.
CHECK constraints with functions IntoSQL doesn't write
non créée
Une contrainte CHECK qui ne peut pas être écrite est omise et signalée.
Ligne du rapport: check_skipped
CHECK constraints that are DISABLE or ENABLE NOVALIDATE
non créée
Oracle n'applique pas ces contraintes CHECK aux lignes déjà présentes, qui peuvent donc les enfreindre.
Ligne du rapport: check_not_enforced
function-based, bitmap and domain indexes
non créée
IntoSQL écrit des index b-tree sur des colonnes entières ; recréez les autres après le chargement.
Ligne du rapport: index_skipped
foreign keys
après les données ENABLE NOVALIDATE, puis validée avec un avertissement sur les orphelins
La clé vérifie tout de suite les nouvelles lignes et est validée en dernier ; des lignes sans parent la laissent non validée avec un avertissement au lieu d'arrêter le chargement.
ON DELETE CASCADE that cascades in a cycle or along a second path
supprimé
Les clés étrangères d'Oracle n'agissent qu'à la suppression, avec CASCADE ou SET NULL.
Ligne du rapport: foreign_key_action_unsupported
foreign keys to tables the export doesn't create, and DISABLE or NOVALIDATE ones
non créée
Une clé ne peut pas désigner une table absente, et une clé qu'Oracle ne vérifie pas peut avoir des lignes sans parent.
Ligne du rapport: foreign_key_skipped
names longer than Oracle 12.1 allows
raccourci
Depuis 12.2, les noms Oracle font 128 octets au plus ; un nom plus long est raccourci.
Ligne du rapport: name_shortened
partitioned tables
une seule table avec les lignes de chaque partition
Les lignes sont les mêmes ; partitionnez à nouveau la table dans Oracle si besoin.
Ligne du rapport: partitions_dropped
several schemas in one export
un seul schéma, tables préfixées par le nom de leur schéma
Le script se charge dans le schéma de l'utilisateur qui l'exécute ; les tables de schémas différents reçoivent donc le nom de leur schéma en préfixe, et un export d'un seul schéma garde le nom de ses tables.
Ligne du rapport: schemas_merged
NOT NULL columns with values that become NULL
NOT NULL retiré
Une colonne dont des valeurs ont dû devenir NULL ne peut pas garder NOT NULL, sinon le chargement s'arrêterait.
Ligne du rapport: not_null_relaxed
views, synonyms, types, packages, procedures, functions and other triggers
listés dans le rapport
Leur code est écrit en PL/SQL ; ils sont donc listés pour que vous les recréiez.
Ligne du rapport: not_converted_objects
exports without CREATE TABLE (data only)
types déduits des valeurs
Un export de données seules ne contient que des lignes, donc les types viennent des valeurs.
Ligne du rapport: no_schema
expressions in INSERT values other than the ones exports write
NULL
Un convertisseur qui n'exécute pas de base de données ne peut pas les évaluer ; to_date, to_timestamp, TO_CLOB, HEXTORAW et les autres que les exports écrivent sont lus.
Ligne du rapport: expression_value
types IntoSQL doesn't know, and object types
CLOB
Le texte contient n'importe quelle valeur ; changez le type après le chargement.
Ligne du rapport: unknown_type
dates before year 1 and time zones given as region names
NULL
Une valeur qui n'est pas une date devient NULL et le rapport la compte.
Ligne du rapport: date_out_of_range
NaN and Infinity in BINARY_FLOAT and BINARY_DOUBLE
NaN et Infinity conservés
Les types à virgule flottante d'Oracle contiennent NaN et l'infini.
NUL characters in text
conservé
VARCHAR2 et CLOB peuvent contenir un caractère NUL, donc la valeur est copiée telle quelle.
text that isn't valid in its encoding
les octets invalides deviennent le caractère de remplacement
Le script est en UTF-8 et chaque valeur doit être du texte valide.
Ligne du rapport: invalid_utf8_replaced
text decoded twice (ñ)
copié tel quel
Le script contient exactement ces caractères, ils sont donc copiés ; le rapport les signale.
Ligne du rapport: mojibake_suspected
| Dans le fichier | Dans le script | Ligne du rapport |
|---|---|---|
| BOOLEAN (23ai) | BOOLEAN sur 23ai, sinon NUMBER(1) avec un CHECK de 0 et 1TRUE et FALSE restent true et false. | |
| VARCHAR2(n BYTE|CHAR), NVARCHAR2(n), CHAR(n), NCHAR(n), CLOB, NCLOB, LONG | les mêmes types, avec leurs longueurs BYTE ou CHARLes mêmes types texte ; LONG devient CLOB, que chaque version depuis la 8 préfère. | |
| VARCHAR2 and NVARCHAR2 past what the target's own types hold | VARCHAR2(4000 CHAR) si chaque valeur tient en 4000 octets, sinon CLOBUn VARCHAR2 contient 4000 octets par défaut et Oracle ne peut pas indexer un CLOB ; le texte garde donc VARCHAR2 si ses valeurs y tiennent, sinon il devient CLOB. | text_as_lob |
| NUMBER, NUMBER(p,s), FLOAT(b) | les mêmes types NUMBERLes mêmes types NUMBER et FLOAT, avec chaque chiffre. | |
| INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND | les mêmes types INTERVALLes mêmes intervalles. | |
| DATE, TIMESTAMP(p) | DATE et TIMESTAMP(p), tels que déclarésLes mêmes types ; chaque date garde donc son heure à la seconde près. | |
| TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE | les mêmes typesOracle garde les décalages de -12:00 à +14:00 ; une valeur dont le décalage dépasse -12:00 est écrite en UTC, le même instant. | |
| JSON (21c), and CLOB holding JSON | JSON à partir de 21c, sinon CLOBLes mêmes valeurs JSON ; un NULL SQL que l'export a écrit 'null' reste NULL. | |
| BLOB, RAW(n), LONG RAW | les mêmes types ; LONG RAW en BLOBLes octets restent des octets. | |
| ROWID, UROWID, XMLTYPE, SDO_GEOMETRY | CLOB avec leur texteXMLTYPE, ROWID et UROWID gardent leur texte dans un CLOB, pour que le script se charge sur chaque version depuis 19c. | type_replaced |
| collations that ignore case (BINARY_CI) | comparaison exacteLes collations de colonne ne sont pas écrites ; une colonne insensible à la casse (BINARY_CI) distingue donc maintenant Ana et ana. | case_insensitive_collation |
| identity columns, and a sequence a BEFORE INSERT trigger assigns | GENERATED BY DEFAULT ON NULL AS IDENTITY, qui reprend après l'identifiant le plus élevéLes identifiants copiés se chargent tels quels, et le compteur reprend après le plus élevé. Une colonne qu'un déclencheur remplit depuis une séquence (la méthode d'avant 12c) devient aussi une colonne d'identité. | |
| identity columns the target can't count | un entier simpleOracle compte une colonne d'identité par table ; toute autre garde ses valeurs sans compteur. | counter_dropped |
| CREATE SEQUENCE | CREATE SEQUENCE avec les mêmes optionsL'export écrit où en est une séquence comme son START WITH ; elle reprend donc à partir de là. | |
| virtual columns (GENERATED ALWAYS AS ... VIRTUAL) | colonnes virtuellesLes mêmes colonnes virtuelles. | stored_as_virtual |
| virtual columns with functions IntoSQL doesn't write, and the || operator | une colonne simpleUne formule qui ne peut pas être écrite pour Oracle laisse une colonne simple et une ligne dans le rapport ; les valeurs que l'export a écrites pour les colonnes virtuelles sont omises, et Oracle ne peut pas les calculer. | generated_not_translated |
| defaults with functions IntoSQL doesn't write (SYS_GUID(), ||) | aucune valeur par défautUne valeur par défaut qui ne peut pas être écrite est omise et signalée. | default_not_translated |
| CHECK constraints | traduitesLes mêmes contraintes CHECK, vérifiées au chargement de chaque ligne. | |
| CHECK constraints with functions IntoSQL doesn't write | non crééeUne contrainte CHECK qui ne peut pas être écrite est omise et signalée. | check_skipped |
| CHECK constraints that are DISABLE or ENABLE NOVALIDATE | non crééeOracle n'applique pas ces contraintes CHECK aux lignes déjà présentes, qui peuvent donc les enfreindre. | check_not_enforced |
| function-based, bitmap and domain indexes | non crééeIntoSQL écrit des index b-tree sur des colonnes entières ; recréez les autres après le chargement. | index_skipped |
| foreign keys | après les données ENABLE NOVALIDATE, puis validée avec un avertissement sur les orphelinsLa clé vérifie tout de suite les nouvelles lignes et est validée en dernier ; des lignes sans parent la laissent non validée avec un avertissement au lieu d'arrêter le chargement. | |
| ON DELETE CASCADE that cascades in a cycle or along a second path | suppriméLes clés étrangères d'Oracle n'agissent qu'à la suppression, avec CASCADE ou SET NULL. | foreign_key_action_unsupported |
| foreign keys to tables the export doesn't create, and DISABLE or NOVALIDATE ones | non crééeUne clé ne peut pas désigner une table absente, et une clé qu'Oracle ne vérifie pas peut avoir des lignes sans parent. | foreign_key_skipped |
| names longer than Oracle 12.1 allows | raccourciDepuis 12.2, les noms Oracle font 128 octets au plus ; un nom plus long est raccourci. | name_shortened |
| partitioned tables | une seule table avec les lignes de chaque partitionLes lignes sont les mêmes ; partitionnez à nouveau la table dans Oracle si besoin. | partitions_dropped |
| several schemas in one export | un seul schéma, tables préfixées par le nom de leur schémaLe script se charge dans le schéma de l'utilisateur qui l'exécute ; les tables de schémas différents reçoivent donc le nom de leur schéma en préfixe, et un export d'un seul schéma garde le nom de ses tables. | schemas_merged |
| NOT NULL columns with values that become NULL | NOT NULL retiréUne colonne dont des valeurs ont dû devenir NULL ne peut pas garder NOT NULL, sinon le chargement s'arrêterait. | not_null_relaxed |
| views, synonyms, types, packages, procedures, functions and other triggers | listés dans le rapportLeur code est écrit en PL/SQL ; ils sont donc listés pour que vous les recréiez. | not_converted_objects |
| exports without CREATE TABLE (data only) | types déduits des valeursUn export de données seules ne contient que des lignes, donc les types viennent des valeurs. | no_schema |
| expressions in INSERT values other than the ones exports write | NULLUn convertisseur qui n'exécute pas de base de données ne peut pas les évaluer ; to_date, to_timestamp, TO_CLOB, HEXTORAW et les autres que les exports écrivent sont lus. | expression_value |
| types IntoSQL doesn't know, and object types | CLOBLe texte contient n'importe quelle valeur ; changez le type après le chargement. | unknown_type |
| dates before year 1 and time zones given as region names | NULLUne valeur qui n'est pas une date devient NULL et le rapport la compte. | date_out_of_range |
| NaN and Infinity in BINARY_FLOAT and BINARY_DOUBLE | NaN et Infinity conservésLes types à virgule flottante d'Oracle contiennent NaN et l'infini. | |
| NUL characters in text | conservéVARCHAR2 et CLOB peuvent contenir un caractère NUL, donc la valeur est copiée telle quelle. | |
| text that isn't valid in its encoding | les octets invalides deviennent le caractère de remplacementLe script est en UTF-8 et chaque valeur doit être du texte valide. | invalid_utf8_replaced |
| text decoded twice (ñ) | copié tel quelLe script contient exactement ces caractères, ils sont donc copiés ; le rapport les signale. | mojibake_suspected |
Charger le script dans Oracle
Le script crée les tables, copie les lignes, puis ajoute les clés, les index et les clés étrangères ; il se charge donc vite et s'arrête à la première erreur.
NLS_LANG=.AL32UTF8 sqlplus -S -L user@//localhost/mydb @oracle.oracle.sqlLes clés étrangères sont ajoutées ENABLE NOVALIDATE, donc les nouvelles lignes sont vérifiées tout de suite, puis validées. Si une ancienne ligne pointe vers une ligne qui n'existe pas, le script indique quelle contrainte et la laisse non validée, au lieu d'échouer à mi-chemin.
Pour un gros dump, exécutez SQL*Plus sur la machine de la base de données. Le script valide toutes les 100 lignes. L'utilisateur qui l'exécute a besoin de CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER et CREATE PROCEDURE, et d'un quota sur son tablespace.
Faire le dump Oracle pour un meilleur résultat
Le convertisseur lit ce que contient le dump. Ces options y gardent davantage de vos données :
- Dans SQL Developer, choisissez Tools, Database Export, avec DDL et le format de données Insert. SQLcl écrit la même chose avec SET SQLFORMAT INSERT.
- Exécutez ALTER SESSION SET NLS_DATE_FORMAT = 'SYYYY-MM-DD HH24:MI:SS' avant l'export : le format par défaut écrit les dates sans leur heure ni leur siècle.
- Un fichier .dmp de exp ou expdp est binaire : importez-le dans une base Oracle, par exemple Oracle Database Free dans Docker, et exportez-le avec SQL Developer.
Ce qui n'est pas converti
Les vues, triggers, procédures, fonctions et autres objets écrits dans le propre langage de Oracle sont listés par nom dans le rapport, jamais supprimés en silence, pour que vous vérifiiez chacun face à la version de Oracle cible avant de le recréer.
Questions sur le passage de Oracle d'une version à l'autre
Pas de réponse ici ? Écrivez-nous depuis la page de contact, une personne vous répond. Page de contact
Mon dump est-il envoyé ?
Non. Le convertisseur s'exécute dans votre navigateur et lit le dump depuis votre disque par morceaux ; il ne quitte donc jamais votre ordinateur. L'application de bureau et la ligne de commande convertissent aussi sur votre ordinateur.
Quelle taille peut avoir le dump ?
Le convertisseur ne garde jamais tout le dump en mémoire : il lit le fichier deux fois, par plages, et écrit le script au fur et à mesure. Les dumps de plusieurs gigaoctets se convertissent dans le navigateur, dans l'application de bureau et avec la ligne de commande.
Puis-je convertir un fichier .dmp de exp ou expdp ?
Pas directement : Data Pump et l'Export d'origine écrivent un format binaire que seul Oracle lit. Importez-le dans n'importe quelle base Oracle, Oracle Database Free tourne dans Docker, et exportez-le avec Database Export de SQL Developer ou SQLcl. Le convertisseur le signale quand il reçoit un fichier .dmp.
De quelles versions de Oracle l'export peut-il venir ?
Les exports de SQL Developer et SQLcl, avec les définitions de tables de DBMS_METADATA, depuis Oracle 11g. Chaque export de test vient de Oracle 21c et 23ai, dans des sessions américaine, allemande et ISO, et est comparé à sa source cellule par cellule.
Que deviennent NUMBER, DATE et les autres types Oracle ?
Ils restent tels quels : NUMBER avec sa précision, DATE, TIMESTAMP, les intervalles, CHAR et VARCHAR2 avec leurs longueurs, RAW et les LOB. XMLTYPE et JSON gardent leur texte dans un CLOB, pour que le script se charge sur 19c.
Les colonnes d'identité et les séquences sont-elles gardées ?
Oui. Les colonnes d'identité et les séquences restent telles quelles et reprennent là où l'export indique qu'elles en étaient.
Et les packages, procédures et déclencheurs PL/SQL ?
Ils sont listés par nom dans le rapport et ne sont pas convertis, pour que vous puissiez les recréer une fois les tables en place.
Sur quelles versions de Oracle le script se charge-t-il ?
Oracle 19c et versions ultérieures. Chaque export de test se charge sur 21c et 23ai, et s'arrête à la première erreur en cas de problème.