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

Konwertuj SQLite do Oracle

Upuść plik bazy danych SQLite (.db, .sqlite, .sqlite3) albo SQL zapisany przez .dump z sqlite3 i pobierz skrypt Oracle z tymi samymi tabelami, kluczami, indeksami i danymi. Każda kolumna dostaje typ, w którym mieszczą się jej wartości, a każda wartość, której Oracle nie może przechować bez zmian, jest wymieniona w raporcie.

Twój plik
sqlshop_2024_sqlite.sqlPlik przykładowy, 3,4 kB
Twoja baza danych

18 wierszy przekonwertowanych, bez poprawek, brak odrzuconych

Pokaż

Tabele w pliku shop_2024_sqlite.sqlZrzut SQLite · zapisany przez sqlite3 · utf-8

  • customerszapisana jako CUSTOMERS8 wierszy
    7 kolumn
    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
  • orderszapisana jako ORDERS10 wierszy
    9 kolumn
    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

Nieprzekonwertowane

  • Widok order_totals
  • Wyzwalacz orders_shipped

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

Poprawki

Nic nie wymagało poprawek.

Do sprawdzenia

  • W źródle 1 kolumna tekstowa ignoruje wielkość liter przy porównaniu; Oracle porównuje dokładnie, więc klucze unikalne i wyszukiwanie mogą działać inaczej. Użyj collation lub typu kolumny ignorującego wielkość liter w kolumnach, które tego potrzebują.
  • Widoki, wyzwalacze, procedury i zdarzenia nie są konwertowane: 2 obiekty, każdy wymieniony w raporcie. Utwórz je ręcznie w Oracle.

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

Inne przykłady:

Co zmienia się między SQLite 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.

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

    typ, w którym mieści się każda wartość kolumny

    SQLite przechowuje dowolną wartość w dowolnej kolumnie, więc zadeklarowany typ jest tylko wskazówką: każda kolumna dostaje typ, w którym mieszczą się wszystkie jej wartości, a kolumna z mieszanymi wartościami zachowuje ich tekst.

  • BOOLEAN, BOOL

    NUMBER(1) z CHECK 0 i 1

    Gdy każda wartość to 0 lub 1; kolumna, która zawiera też inne wartości, zachowuje je jako liczby lub tekst.

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

    VARCHAR2(n CHAR), gdy każda wartość się mieści, w przeciwnym razie CLOB

    SQLite nigdy nie wymusza długości; zadeklarowana długość obowiązuje tylko wtedy, gdy mieści się w niej każda wartość.

  • TEXT and VARCHAR(n) longer than 4000 bytes

    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

  • DECIMAL(p,s), NUMERIC

    dokładny typ, gdy mieści się w nim każda wartość, w przeciwnym razie double

    SQLite przechowuje je jako liczby całkowite lub double; zadeklarowana precyzja obowiązuje tylko wtedy, gdy wartości się w niej mieszczą.

  • BLOB, and columns holding bytes

    BLOB

    Bajty pozostają bajtami; tekst i liczby w tej samej kolumnie są zachowywane jako ich bajty.

  • DATE, DATETIME, TIMESTAMP holding ISO 8601 text

    DATE lub TIMESTAMP(p), zależnie od tego, co zawierają wartości

    Gdy każda wartość to data lub data z godziną; liczby epoch i inny tekst zachowują swoje wartości bez zmian.

  • JSON holding JSON text

    CLOB

    Gdy każda wartość to obiekt lub tablica JSON.

  • Infinity in REAL columns

    zachowane jako BINARY_DOUBLE_INFINITY

    Typ double w Oracle przechowuje nieskończoność.

  • INTEGER PRIMARY KEY, AUTOINCREMENT

    GENERATED BY DEFAULT ON NULL AS IDENTITY, kontynuowane po najwyższym id lub wartości z sqlite_sequence

    Tylko kolumna zadeklarowana dokładnie jako INTEGER PRIMARY KEY jest rowid; każdy wiersz zachowuje swoje id, a licznik zaczyna po najwyższym kiedykolwiek wydanym id.

  • COLLATE NOCASE

    dokładne porównanie

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

    Wpis w raporcie: case_insensitive_collation

  • 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 IntoSQL doesn't write, and the || operator

    zwykła kolumna

    Formuła, której nie da się zapisać, zostawia zwykłą kolumnę i wpis w raporcie; zrzut nie zawiera wartości kolumn generowanych.

    Wpis w raporcie: generated_not_translated

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

    brak wartości domyślnej

    Wartość domyślna, której nie da się zapisać, jest pomijana i zgłaszana w raporcie; CURRENT_TIMESTAMP i datetime('now') są zapisywane.

    Wpis w raporcie: default_not_translated

  • CHECK constraints

    przetłumaczone

    Te same ograniczenia CHECK, sprawdzane przy ładowaniu każdego wiersza.

  • CHECK constraints with functions IntoSQL doesn't write

    nie jest tworzone

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

    Wpis w raporcie: check_skipped

  • partial and expression indexes

    nie jest tworzone

    IntoSQL zapisuje indeksy na całych kolumnach; pozostałe utwórz ponownie po załadowaniu.

    Wpis w raporcie: index_skipped

  • foreign keys (unenforced unless PRAGMA foreign_keys=ON)

    po danych z ENABLE NOVALIDATE, potem walidowany

    SQLite sprawdza klucze obce tylko na żądanie, więc wiersze bez rodzica są częste: ładują się, a klucz zostaje niesprawdzony 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

  • empty strings and empty blobs

    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

  • 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

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

    NOT NULL usunięte

    SQLite pozwala, by klucz główny inny niż rowid zawierał NULL; kolumna nie może być NOT NULL w bazie docelowej, bo ładowanie by się zatrzymało.

    Wpis w raporcie: not_null_relaxed

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

    wymienione w raporcie

    Ich kod jest napisany we własnym języku SQLite, a tabele wirtualne wymagają modułów SQLite; trafiają na listę do ręcznego odtworzenia. Ich wewnętrzne tabele nie są kopiowane.

    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, a kolumny są numerowane.

    Wpis w raporcie: no_schema

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

    NULL

    unistr(), replace(), char() i || są obliczane tak, jak zapisuje je powłoka; innych wyrażeń nie da się obliczyć bez bazy danych.

    Wpis w raporcie: expression_value

  • NUL characters in text

    zachowane

    Powłoka sqlite3 i Python obcinają tekst na znaku NUL podczas zrzutu, więc w zrzucie jest tylko to, co go poprzedza.

  • text that isn't valid UTF-8

    błędne bajty jako znak zastępczy

    Zrzuty zapisują taki tekst jako surowe bajty; skrypt jest w UTF-8.

    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 SQLiteW OracleWpis w raporcie
declared types (any text: VARCHAR(255), DATETIME, BOOLEAN, JSON or none)typ, w którym mieści się każda wartość kolumnySQLite przechowuje dowolną wartość w dowolnej kolumnie, więc zadeklarowany typ jest tylko wskazówką: każda kolumna dostaje typ, w którym mieszczą się wszystkie jej wartości, a kolumna z mieszanymi wartościami zachowuje ich tekst.
BOOLEAN, BOOLNUMBER(1) z CHECK 0 i 1Gdy każda wartość to 0 lub 1; kolumna, która zawiera też inne wartości, zachowuje je jako liczby lub tekst.
TEXT, VARCHAR(n), CHAR(n), CLOBVARCHAR2(n CHAR), gdy każda wartość się mieści, w przeciwnym razie CLOBSQLite nigdy nie wymusza długości; zadeklarowana długość obowiązuje tylko wtedy, gdy mieści się w niej każda wartość.
TEXT and VARCHAR(n) longer than 4000 bytesVARCHAR2(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
DECIMAL(p,s), NUMERICdokładny typ, gdy mieści się w nim każda wartość, w przeciwnym razie doubleSQLite przechowuje je jako liczby całkowite lub double; zadeklarowana precyzja obowiązuje tylko wtedy, gdy wartości się w niej mieszczą.
BLOB, and columns holding bytesBLOBBajty pozostają bajtami; tekst i liczby w tej samej kolumnie są zachowywane jako ich bajty.
DATE, DATETIME, TIMESTAMP holding ISO 8601 textDATE lub TIMESTAMP(p), zależnie od tego, co zawierają wartościGdy każda wartość to data lub data z godziną; liczby epoch i inny tekst zachowują swoje wartości bez zmian.
JSON holding JSON textCLOBGdy każda wartość to obiekt lub tablica JSON.
Infinity in REAL columnszachowane jako BINARY_DOUBLE_INFINITYTyp double w Oracle przechowuje nieskończoność.
INTEGER PRIMARY KEY, AUTOINCREMENTGENERATED BY DEFAULT ON NULL AS IDENTITY, kontynuowane po najwyższym id lub wartości z sqlite_sequenceTylko kolumna zadeklarowana dokładnie jako INTEGER PRIMARY KEY jest rowid; każdy wiersz zachowuje swoje id, a licznik zaczyna po najwyższym kiedykolwiek wydanym id.
COLLATE NOCASEdokładne porównanieOracle porównuje tekst dokładnie, chyba że ustawisz inaczej; kolumny NOCASE przestają ignorować wielkość liter.case_insensitive_collation
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 IntoSQL doesn't write, and the || operatorzwykła kolumnaFormuła, której nie da się zapisać, zostawia zwykłą kolumnę i wpis w raporcie; zrzut nie zawiera wartości kolumn generowanych.generated_not_translated
defaults with functions IntoSQL doesn't write (strftime, randomblob)brak wartości domyślnejWartość domyślna, której nie da się zapisać, jest pomijana i zgłaszana w raporcie; CURRENT_TIMESTAMP i datetime('now') są zapisywane.default_not_translated
CHECK constraintsprzetłumaczoneTe same ograniczenia CHECK, sprawdzane przy ładowaniu każdego wiersza.
CHECK constraints with functions IntoSQL doesn't writenie jest tworzoneOgraniczenie CHECK, którego nie da się zapisać, jest pomijane i zgłaszane w raporcie.check_skipped
partial and expression indexesnie jest tworzoneIntoSQL zapisuje indeksy na całych kolumnach; pozostałe utwórz ponownie po załadowaniu.index_skipped
foreign keys (unenforced unless PRAGMA foreign_keys=ON)po danych z ENABLE NOVALIDATE, potem walidowanySQLite sprawdza klucze obce tylko na żądanie, więc wiersze bez rodzica są częste: ładują się, a klucz zostaje niesprawdzony 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
empty strings and empty blobsNULLOracle zapisuje pusty ciąg jako NULL, więc wartość ' jest odczytywana jako NULL. Raport liczy je w każdej kolumnie.empty_string_null
foreign keys to tables the dump doesn't createnie jest tworzoneKlucz nie może wskazywać tabeli, której nie ma.foreign_key_skipped
primary keys holding NULL, and NOT NULL columns with values that become NULLNOT NULL usunięteSQLite pozwala, by klucz główny inny niż rowid zawierał NULL; kolumna nie może być NOT NULL w bazie docelowej, bo ładowanie by się zatrzymało.not_null_relaxed
views, triggers and virtual tables (FTS, R*Tree)wymienione w raporcieIch kod jest napisany we własnym języku SQLite, a tabele wirtualne wymagają modułów SQLite; trafiają na listę do ręcznego odtworzenia. Ich wewnętrzne tabele nie są kopiowane.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, a kolumny są numerowane.no_schema
expressions in INSERT values other than the text functions dumps writeNULLunistr(), replace(), char() i || są obliczane tak, jak zapisuje je powłoka; innych wyrażeń nie da się obliczyć bez bazy danych.expression_value
NUL characters in textzachowanePowłoka sqlite3 i Python obcinają tekst na znaku NUL podczas zrzutu, więc w zrzucie jest tylko to, co go poprzedza.
text that isn't valid UTF-8błędne bajty jako znak zastępczyZrzuty zapisują taki tekst jako surowe bajty; skrypt jest w UTF-8.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 @sqlite.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 SQLite dla najlepszego wyniku

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

  • Sam plik bazy danych konwertuje się bez zmian, odczytywany strona po stronie w przeglądarce. Najpierw zamknij aplikację, która do niego zapisuje, żeby żadna zmiana nie została w jego pliku -wal.
  • sqlite3 app.db .dump > app.sql zapisuje tę samą bazę danych jako SQL, który też się konwertuje, jako .sql lub .sql.gz.
  • DB Browser for SQLite zapisuje ten SQL przez File, Export, Database to SQL file, podobnie jak iterdump() w Pythonie.

Co nie jest konwertowane

Widoki i wyzwalacze są pisane we własnym języku SQLite. Raport wymienia je z nazwy i nigdy nie pomija ich po cichu, więc możesz je przepisać dla Oracle. Tabele wirtualne, takie jak FTS5 i R*Tree, też są wymienione, a ich tabele cieni są pomijane.

Pytania o konwersję SQLite 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 mogę przekonwertować sam plik .db?

Tak. Upuść plik .db, .sqlite lub .sqlite3: jest odczytywany w przeglądarce i nigdy nie jest wysyłany. Tekst ze znakami NUL i każda cyfra wartości double docierają tak, jak zostały zapisane, a .dump może je obciąć.

Z jakich wersji SQLite może pochodzić zrzut?

Pliki bazy danych od SQLite 3.0, w UTF-8 lub UTF-16, oraz zrzuty z .dump powłoki sqlite3 lub z iterdump() w Pythonie. Każdy testowy plik i zrzut pochodzi z sqlite3 od 3.31 do 3.54, łącznie z tabelami STRICT i WITHOUT ROWID, i jest porównywany ze źródłem komórka po komórce.

Jak ustalane są typy kolumn, skoro SQLite ich nie wymusza?

Zadeklarowany typ jest wskazówką, a decydują wartości: kolumna staje się NUMBER, BINARY_DOUBLE, DATE, TIMESTAMP, BLOB, VARCHAR2 lub CLOB, gdy mieści się w nim każda wartość. Puste ciągi stają się NULL, bo tak zapisuje je Oracle, a raport je liczy.

Czy INTEGER PRIMARY KEY i AUTOINCREMENT są zachowywane?

Tak. INTEGER PRIMARY KEY staje się kolumną identity, każdy wiersz zachowuje swoje id, a kolejne id idzie po najwyższym albo, przy AUTOINCREMENT, po wartości z sqlite_sequence.

A widoki i wyzwalacze?

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.