Aller au contenu
Accueil IntoSQL

Convertir SQLite en Oracle

Déposez un fichier de base de données SQLite (.db, .sqlite, .sqlite3) ou le SQL qu'écrit le .dump de sqlite3, et téléchargez un script Oracle avec les mêmes tables, clés, index et données. Chaque colonne reçoit le type auquel ses valeurs correspondent, et chaque valeur que Oracle ne peut pas contenir telle quelle est listée dans le rapport.

Votre fichier
sqlshop_2024_sqlite.sqlFichier d'exemple, 3,4 ko
Votre base de données

18 lignes converties, aucune correction, aucune rejetée

Afficher

Tables de shop_2024_sqlite.sqlDump SQLite · écrit par sqlite3 · utf-8

  • customersécrite sous le nom CUSTOMERS8 lignes
    7 colonnes
    IDNUMBER(19) not null
    NAMEVARCHAR2(4000 CHAR) not null
    EMAILVARCHAR2(750 CHAR) not null
    COUNTRYVARCHAR2(4000 CHAR) not null
    IS_ACTIVENUMBER(1) not null
    SIGNED_UPDATE
    CREATED_ATTIMESTAMP(0) not null
  • ordersécrite sous le nom ORDERS10 lignes
    9 colonnes
    IDNUMBER(19) not null
    CUSTOMER_IDNUMBER(19) not null
    STATUSVARCHAR2(750 CHAR) not null
    TOTALNUMBER(10,2) not null
    ITEMSNUMBER(10) not null
    ORDERED_ATTIMESTAMP(0) not null
    SHIPPED_ATTIMESTAMP(0)
    NOTEVARCHAR2(4000 CHAR)
    RECEIPTBLOB

Non converti

  • Vue order_totals
  • Déclencheur orders_shipped

Chaque base de données les écrit dans son propre langage. Réécrivez-les pour Oracle.

-- Written by IntoSQL from a SQLite 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(19) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 9),
    "NAME" VARCHAR2(4000 CHAR) NOT NULL,
    "EMAIL" VARCHAR2(750 CHAR) NOT NULL,
    "COUNTRY" VARCHAR2(4000 CHAR) DEFAULT 'US' NOT NULL,
    "IS_ACTIVE" NUMBER(1) DEFAULT 1 NOT NULL,
    "SIGNED_UP" DATE,
    "CREATED_AT" TIMESTAMP(0) DEFAULT LOCALTIMESTAMP NOT NULL,
    CONSTRAINT "CK_CUSTOMERS_IS_ACTIVE" CHECK ("IS_ACTIVE" IN (0, 1)),
    CONSTRAINT "CHECK1" CHECK (LENGTH("COUNTRY") = 2)
);

CREATE TABLE "ORDERS" (
    "ID" NUMBER(19) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 11),
    "CUSTOMER_ID" NUMBER(19) NOT NULL,
    "STATUS" VARCHAR2(750 CHAR) DEFAULT 'pending' NOT NULL,
    "TOTAL" NUMBER(10,2) NOT NULL,
    "ITEMS" NUMBER(10) DEFAULT 1 NOT NULL,
    "ORDERED_AT" TIMESTAMP(0) NOT NULL,
    "SHIPPED_AT" TIMESTAMP(0),
    "NOTE" VARCHAR2(4000 CHAR),
    "RECEIPT" BLOB,
    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,
DATE '2023-01-15',
TIMESTAMP '2023-01-15 10:24:00'
);
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,
DATE '2023-02-03',
TIMESTAMP '2023-02-03 08:11:42'
);
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,
DATE '2023-03-21',
TIMESTAMP '2023-03-21 19:05:17'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "CUSTOMERS" (
"ID",
"NAME",
"EMAIL",
"COUNTRY",
"IS_ACTIVE",
"SIGNED_UP",
"CREATED_AT"
) VALUES (
4,
'李雷',
'lilei@example.cn',
'CN',
1,
DATE '2023-05-09',
TIMESTAMP '2023-05-09 02:40:00'
);
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'
);
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,
DATE '2024-01-02',
TIMESTAMP '2024-01-02 09:30:00'
);
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,
DATE '2024-02-29',
TIMESTAMP '2024-02-29 23:59:59'
);
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,
DATE '2024-04-12',
TIMESTAMP '2024-04-12 12:12:12'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
1,
1,
'shipped',
129.9,
3,
TIMESTAMP '2024-03-01 10:00:00',
TIMESTAMP '2024-03-02 16:30:00',
NULL,
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
2,
2,
'paid',
54,
1,
TIMESTAMP '2024-03-02 11:15:00',
NULL,
'Gift wrap 🎁',
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
3,
1,
'cancelled',
12.5,
1,
TIMESTAMP '2024-03-03 09:45:00',
NULL,
'Customer changed their mind',
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
4,
4,
'shipped',
980,
12,
TIMESTAMP '2024-03-05 02:10:00',
TIMESTAMP '2024-03-07 08:00:00',
'请小心轻放',
HEXTORAW('25504446')
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
5,
5,
'pending',
45.75,
2,
TIMESTAMP '2024-03-08 17:20:00',
NULL,
'Leave at the door;'
|| CHR(10)
|| 'ring twice',
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
6,
6,
'shipped',
310.4,
5,
TIMESTAMP '2024-03-10 13:00:00',
TIMESTAMP '2024-03-11 09:00:00',
'Fragile: "glass"',
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
7,
8,
'paid',
76.2,
2,
TIMESTAMP '2024-03-11 18:45:00',
NULL,
NULL,
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
8,
2,
'paid',
19.99,
1,
TIMESTAMP '2024-03-12 08:00:00',
NULL,
'Paid at the counter',
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
9,
3,
'shipped',
64,
2,
TIMESTAMP '2024-03-14 15:30:00',
NULL,
'Shipping date never recorded',
NULL
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"RECEIPT"
) VALUES (
10,
7,
'paid',
1499,
1,
TIMESTAMP '2024-03-15 21:05:00',
NULL,
'C:\Users\ravi\invoice.pdf',
NULL
);
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_EMAIL" UNIQUE ("EMAIL");
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 "FK_ORDERS" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "CUSTOMERS" ("ID") ON DELETE CASCADE ENABLE NOVALIDATE;
BEGIN
    EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" ENABLE VALIDATE CONSTRAINT "FK_ORDERS"';
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('Foreign key ' || '"FK_ORDERS"' || ' 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 < 9 THEN
        next_id := 9;
    END IF;
    EXECUTE IMMEDIATE 'ALTER TABLE "CUSTOMERS" MODIFY ("ID" GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH ' || next_id || '))';
END;
/
DECLARE
    next_id NUMBER;
BEGIN
    SELECT NVL(MAX("ID"), 0) + 1 INTO next_id FROM "ORDERS";
    IF next_id < 11 THEN
        next_id := 11;
    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é.

À vérifier

  • 1 colonne de texte compare sans tenir compte de la casse dans la source ; Oracle compare exactement, donc les clés uniques et les recherches peuvent se comporter autrement. Utilisez une collation ou un type de colonne insensible à la casse sur les colonnes qui en ont besoin.
  • 2 objets non convertis (vues, déclencheurs, routines ou événements) ; le rapport les liste un par un. Recréez-les à la main dans Oracle.

Votre fichier est converti sur cet ordinateur et n'est jamais envoyé.

Autres exemples :

Ce qui change de SQLite à Oracle

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.

  • declared types (any text: VARCHAR(255), DATETIME, BOOLEAN, JSON or none)

    le type auquel chaque valeur de la colonne correspond

    SQLite accepte n'importe quelle valeur dans n'importe quelle colonne, donc le type déclaré est une indication : chaque colonne reçoit le type auquel toutes ses valeurs correspondent, et une colonne aux valeurs mélangées garde leur texte.

  • BOOLEAN, BOOL

    NUMBER(1) avec un CHECK de 0 et 1

    Quand chaque valeur vaut 0 ou 1 ; une colonne qui contient aussi d'autres valeurs les garde en nombres ou en texte.

  • TEXT, VARCHAR(n), CHAR(n), CLOB

    VARCHAR2(n CHAR) si chaque valeur y tient, sinon CLOB

    SQLite n'impose jamais de longueur ; une longueur déclarée n'est gardée que si chaque valeur y tient.

  • TEXT and VARCHAR(n) longer than 4000 bytes

    VARCHAR2(4000 CHAR) si chaque valeur tient en 4000 octets (750 caractères dans une clé), 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

  • DECIMAL(p,s), NUMERIC

    le type exact si chaque valeur y tient, sinon un double

    SQLite les stocke en entiers ou en doubles ; une précision déclarée n'est gardée que si les valeurs y tiennent.

  • BLOB, and columns holding bytes

    BLOB

    Les octets restent des octets ; le texte et les nombres de la même colonne sont gardés sous forme d'octets.

  • DATE, DATETIME, TIMESTAMP holding ISO 8601 text

    DATE ou TIMESTAMP(p), selon ce que contiennent les valeurs

    Quand chaque valeur est une date ou une date et une heure ; les nombres epoch et les autres textes gardent leurs valeurs telles quelles.

  • JSON holding JSON text

    CLOB

    Quand chaque valeur est un objet ou un tableau JSON.

  • Infinity in REAL columns

    gardé en BINARY_DOUBLE_INFINITY

    Les doubles d'Oracle acceptent l'infini.

  • INTEGER PRIMARY KEY, AUTOINCREMENT

    GENERATED BY DEFAULT ON NULL AS IDENTITY, qui reprend après l'identifiant le plus élevé ou celui de sqlite_sequence

    Seule une colonne déclarée exactement INTEGER PRIMARY KEY est le rowid ; chaque ligne garde son identifiant, et le compteur reprend après le plus grand identifiant jamais attribué.

  • COLLATE NOCASE

    comparaison exacte

    Oracle compare le texte exactement, sauf indication contraire ; les colonnes NOCASE ne sont plus insensibles à la casse.

    Ligne du rapport: case_insensitive_collation

  • generated columns

    colonnes virtuelles

    Oracle ne calcule les colonnes générées qu'à la lecture ; les colonnes STORED deviennent virtuelles avec les mêmes valeurs.

    Ligne du rapport: stored_as_virtual

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

    une colonne simple

    Une formule qui ne peut pas être écrite laisse une colonne simple et une ligne dans le rapport ; le dump ne contient aucune valeur pour les colonnes générées.

    Ligne du rapport: generated_not_translated

  • defaults with functions IntoSQL doesn't write (strftime, randomblob)

    aucune valeur par défaut

    Une valeur par défaut qui ne peut pas être écrite est omise et signalée ; CURRENT_TIMESTAMP et datetime('now') sont écrits.

    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

  • partial and expression indexes

    non créée

    IntoSQL écrit des index sur des colonnes entières ; recréez les autres après le chargement.

    Ligne du rapport: index_skipped

  • foreign keys (unenforced unless PRAGMA foreign_keys=ON)

    après les données ENABLE NOVALIDATE, puis validées

    SQLite ne vérifie les clés étrangères que si on le lui demande, donc les lignes sans parent sont courantes : elles se chargent, et la clé reste non vérifiée avec un avertissement au lieu d'arrêter le chargement.

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

    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

  • empty strings and empty blobs

    NULL

    Oracle stocke une chaîne vide comme NULL, donc une valeur qui valait ' se relit comme NULL. Le rapport les compte par colonne.

    Ligne du rapport: empty_string_null

  • foreign keys to tables the dump doesn't create

    non créée

    Une clé ne peut pas désigner une table absente.

    Ligne du rapport: foreign_key_skipped

  • primary keys holding NULL, and NOT NULL columns with values that become NULL

    NOT NULL retiré

    SQLite permet à une clé primaire autre que le rowid de contenir NULL ; la colonne ne peut pas être NOT NULL dans la cible, sinon le chargement s'arrêterait.

    Ligne du rapport: not_null_relaxed

  • views, triggers and virtual tables (FTS, R*Tree)

    listés dans le rapport

    Leur code est écrit dans le langage propre à SQLite, et les tables virtuelles ont besoin des modules de SQLite ; ils sont listés pour que vous les recréiez. Leurs tables internes ne sont pas copiées.

    Ligne du rapport: not_converted_objects

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

    types déduits des valeurs

    Un dump de données seules ne contient que des lignes, donc les types viennent des valeurs et les colonnes sont numérotées.

    Ligne du rapport: no_schema

  • expressions in INSERT values other than the text functions dumps write

    NULL

    unistr(), replace(), char() et || sont évalués tels que le shell les écrit ; les autres expressions ne peuvent pas l'être sans base de données.

    Ligne du rapport: expression_value

  • NUL characters in text

    conservé

    Le shell sqlite3 et Python coupent le texte à un caractère NUL quand ils le dumpent ; seul ce qui le précède est donc dans le dump.

  • text that isn't valid UTF-8

    les octets invalides deviennent le caractère de remplacement

    Les dumps écrivent ce texte en octets bruts ; le script est en UTF-8.

    Ligne du rapport: invalid_utf8_replaced

  • text decoded twice (ñ)

    copié tel quel

    Le dump contient exactement ces caractères, ils sont donc copiés ; le rapport les signale.

    Ligne du rapport: mojibake_suspected

Dans SQLiteDans OracleLigne du rapport
declared types (any text: VARCHAR(255), DATETIME, BOOLEAN, JSON or none)le type auquel chaque valeur de la colonne correspondSQLite accepte n'importe quelle valeur dans n'importe quelle colonne, donc le type déclaré est une indication : chaque colonne reçoit le type auquel toutes ses valeurs correspondent, et une colonne aux valeurs mélangées garde leur texte.
BOOLEAN, BOOLNUMBER(1) avec un CHECK de 0 et 1Quand chaque valeur vaut 0 ou 1 ; une colonne qui contient aussi d'autres valeurs les garde en nombres ou en texte.
TEXT, VARCHAR(n), CHAR(n), CLOBVARCHAR2(n CHAR) si chaque valeur y tient, sinon CLOBSQLite n'impose jamais de longueur ; une longueur déclarée n'est gardée que si chaque valeur y tient.
TEXT and VARCHAR(n) longer than 4000 bytesVARCHAR2(4000 CHAR) si chaque valeur tient en 4000 octets (750 caractères dans une clé), 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
DECIMAL(p,s), NUMERICle type exact si chaque valeur y tient, sinon un doubleSQLite les stocke en entiers ou en doubles ; une précision déclarée n'est gardée que si les valeurs y tiennent.
BLOB, and columns holding bytesBLOBLes octets restent des octets ; le texte et les nombres de la même colonne sont gardés sous forme d'octets.
DATE, DATETIME, TIMESTAMP holding ISO 8601 textDATE ou TIMESTAMP(p), selon ce que contiennent les valeursQuand chaque valeur est une date ou une date et une heure ; les nombres epoch et les autres textes gardent leurs valeurs telles quelles.
JSON holding JSON textCLOBQuand chaque valeur est un objet ou un tableau JSON.
Infinity in REAL columnsgardé en BINARY_DOUBLE_INFINITYLes doubles d'Oracle acceptent l'infini.
INTEGER PRIMARY KEY, AUTOINCREMENTGENERATED BY DEFAULT ON NULL AS IDENTITY, qui reprend après l'identifiant le plus élevé ou celui de sqlite_sequenceSeule une colonne déclarée exactement INTEGER PRIMARY KEY est le rowid ; chaque ligne garde son identifiant, et le compteur reprend après le plus grand identifiant jamais attribué.
COLLATE NOCASEcomparaison exacteOracle compare le texte exactement, sauf indication contraire ; les colonnes NOCASE ne sont plus insensibles à la casse.case_insensitive_collation
generated columnscolonnes virtuellesOracle ne calcule les colonnes générées qu'à la lecture ; les colonnes STORED deviennent virtuelles avec les mêmes valeurs.stored_as_virtual
generated columns with functions IntoSQL doesn't write, and the || operatorune colonne simpleUne formule qui ne peut pas être écrite laisse une colonne simple et une ligne dans le rapport ; le dump ne contient aucune valeur pour les colonnes générées.generated_not_translated
defaults with functions IntoSQL doesn't write (strftime, randomblob)aucune valeur par défautUne valeur par défaut qui ne peut pas être écrite est omise et signalée ; CURRENT_TIMESTAMP et datetime('now') sont écrits.default_not_translated
CHECK constraintstraduitesLes mêmes contraintes CHECK, vérifiées au chargement de chaque ligne.
CHECK constraints with functions IntoSQL doesn't writenon crééeUne contrainte CHECK qui ne peut pas être écrite est omise et signalée.check_skipped
partial and expression indexesnon crééeIntoSQL écrit des index sur des colonnes entières ; recréez les autres après le chargement.index_skipped
foreign keys (unenforced unless PRAGMA foreign_keys=ON)après les données ENABLE NOVALIDATE, puis validéesSQLite ne vérifie les clés étrangères que si on le lui demande, donc les lignes sans parent sont courantes : elles se chargent, et la clé reste non vérifiée avec un avertissement au lieu d'arrêter le chargement.
ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULTsuppriméLes clés étrangères d'Oracle n'agissent qu'à la suppression, avec CASCADE ou SET NULL.foreign_key_action_unsupported
empty strings and empty blobsNULLOracle stocke une chaîne vide comme NULL, donc une valeur qui valait ' se relit comme NULL. Le rapport les compte par colonne.empty_string_null
foreign keys to tables the dump doesn't createnon crééeUne clé ne peut pas désigner une table absente.foreign_key_skipped
primary keys holding NULL, and NOT NULL columns with values that become NULLNOT NULL retiréSQLite permet à une clé primaire autre que le rowid de contenir NULL ; la colonne ne peut pas être NOT NULL dans la cible, sinon le chargement s'arrêterait.not_null_relaxed
views, triggers and virtual tables (FTS, R*Tree)listés dans le rapportLeur code est écrit dans le langage propre à SQLite, et les tables virtuelles ont besoin des modules de SQLite ; ils sont listés pour que vous les recréiez. Leurs tables internes ne sont pas copiées.not_converted_objects
dumps without CREATE TABLE (--data-only)types déduits des valeursUn dump de données seules ne contient que des lignes, donc les types viennent des valeurs et les colonnes sont numérotées.no_schema
expressions in INSERT values other than the text functions dumps writeNULLunistr(), replace(), char() et || sont évalués tels que le shell les écrit ; les autres expressions ne peuvent pas l'être sans base de données.expression_value
NUL characters in textconservéLe shell sqlite3 et Python coupent le texte à un caractère NUL quand ils le dumpent ; seul ce qui le précède est donc dans le dump.
text that isn't valid UTF-8les octets invalides deviennent le caractère de remplacementLes dumps écrivent ce texte en octets bruts ; le script est en UTF-8.invalid_utf8_replaced
text decoded twice (ñ)copié tel quelLe dump 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 @sqlite.oracle.sql

Les 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 SQLite pour un meilleur résultat

Le convertisseur lit ce que contient le dump. Ces options y gardent davantage de vos données :

  • Le fichier de base de données lui-même se convertit tel quel, lu page par page dans votre navigateur. Fermez d'abord l'application qui y écrit, pour qu'aucun changement ne reste dans son fichier -wal.
  • sqlite3 app.db .dump > app.sql écrit la même base de données en SQL, qui se convertit aussi, en .sql ou .sql.gz.
  • DB Browser for SQLite écrit ce SQL avec File, Export, Database to SQL file, tout comme iterdump() de Python.

Ce qui n'est pas converti

Les vues et les déclencheurs sont écrits dans le langage propre à SQLite. Ils sont listés par nom dans le rapport, jamais supprimés en silence, pour que vous puissiez les réécrire pour Oracle. Les tables virtuelles, comme FTS5 et R*Tree, sont listées aussi, et leurs tables internes sont omises.

Questions sur SQLite vers Oracle

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 le fichier .db lui-même ?

Oui. Déposez le fichier .db, .sqlite ou .sqlite3 : il est lu dans votre navigateur et jamais envoyé. Le texte avec des caractères NUL et chaque chiffre d'un double arrivent tels qu'ils sont stockés, ce qu'un .dump peut tronquer.

De quelles versions de SQLite le dump peut-il venir ?

Les fichiers de base de données de SQLite 3.0 et après, en UTF-8 ou UTF-16, et les dumps du .dump du shell sqlite3 ou de iterdump() de Python. Chaque fichier et dump de test vient de sqlite3 3.31 à 3.54, tables STRICT et WITHOUT ROWID comprises, et est comparé à sa source cellule par cellule.

Comment les types de colonnes sont-ils décidés quand SQLite ne les impose pas ?

Le type déclaré est une indication et les valeurs décident : une colonne devient NUMBER, BINARY_DOUBLE, DATE, TIMESTAMP, BLOB, VARCHAR2 ou CLOB quand chaque valeur y correspond. Les chaînes vides deviennent NULL, comme Oracle les stocke, et le rapport les compte.

INTEGER PRIMARY KEY et AUTOINCREMENT sont-ils conservés ?

Oui. Un INTEGER PRIMARY KEY devient une colonne d'identité, chaque ligne garde son identifiant, et le prochain identifiant reprend après le plus élevé, ou après la valeur de sqlite_sequence avec AUTOINCREMENT.

Et les vues et les déclencheurs ?

Ils sont listés par nom dans le rapport et ne sont pas convertis, car chaque base de données les écrit dans son propre langage.

Sur quelles versions de Oracle le script se charge-t-il ?

Oracle 19c et versions ultérieures. Chaque dump de test se charge sur 21c et 23ai, et s'arrête à la première erreur en cas de problème.