Перейти к содержимому
Главная страница IntoSQL

Конвертация SQLite в Oracle

Перетащите файл базы данных SQLite (.db, .sqlite, .sqlite3) или SQL, который пишет .dump в sqlite3, и скачайте скрипт Oracle с теми же таблицами, ключами, индексами и данными. Каждый столбец получает тип, в который помещаются его значения, а каждое значение, которое Oracle не может хранить как есть, указано в отчете.

Ваш файл
sqlshop_2024_sqlite.sqlПример файла, 3,4 кБ
Ваша база данных

18 строк конвертировано, без исправлений, ни одна не отклонена

Показать

Таблицы в shop_2024_sqlite.sqlДамп SQLite · создан программой sqlite3 · utf-8

  • customersзаписана как CUSTOMERS8 строк
    7 столбцов
    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записана как ORDERS10 строк
    9 столбцов
    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

Не конвертировано

  • Представление order_totals
  • Триггер orders_shipped

Каждая база данных пишет их на своем языке. Перепишите их для 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;

Исправления

Исправлять ничего не пришлось.

Требует проверки

  • 1 текстовый столбец сравнивает значения без учета регистра в источнике; Oracle сравнивает точно, поэтому уникальные ключи и поиск могут работать иначе. Используйте сопоставление или тип столбца без учета регистра для столбцов, которым это нужно.
  • Не конвертированы представления, триггеры, процедуры и события (2 объекта); отчет перечисляет каждый. Создайте их заново вручную в Oracle.

Файл конвертируется на этом компьютере и никуда не загружается.

Другие примеры:

Что меняется при переходе с SQLite на Oracle

Каждая строка - это правило, которое применяет конвертер, и строка отчета, которую он пишет, когда правило что-то меняет в ваших данных.

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

    тип, в который помещается каждое значение столбца

    SQLite хранит любое значение в любом столбце, поэтому объявленный тип - лишь подсказка: каждый столбец получает тип, в который помещаются все его значения, а столбец со смешанными значениями сохраняет их текст.

  • BOOLEAN, BOOL

    NUMBER(1) с CHECK на 0 и 1

    Если каждое значение равно 0 или 1; столбец, где есть и другие значения, сохраняет их как числа или текст.

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

    VARCHAR2(n CHAR), если каждое значение помещается, иначе CLOB

    SQLite никогда не ограничивает длину; объявленная длина сохраняется, только если в нее помещается каждое значение.

  • TEXT and VARCHAR(n) longer than 4000 bytes

    VARCHAR2(4000 CHAR), если каждое значение укладывается в 4000 байт (750 символов в ключе), иначе CLOB

    VARCHAR2 по умолчанию вмещает 4000 байт, а Oracle не может индексировать CLOB, поэтому text остается VARCHAR2, если значения помещаются, и становится CLOB, если нет.

    Строка отчета: text_as_lob

  • DECIMAL(p,s), NUMERIC

    точный тип, если в него помещается каждое значение, иначе double

    SQLite хранит их как целые числа или double; объявленная точность сохраняется, только если значения в нее помещаются.

  • BLOB, and columns holding bytes

    BLOB

    Байты остаются байтами; текст и числа в том же столбце сохраняются как их байты.

  • DATE, DATETIME, TIMESTAMP holding ISO 8601 text

    DATE или TIMESTAMP(p), в зависимости от значений

    Если каждое значение - дата или дата со временем; числа epoch и другой текст сохраняют свои значения как есть.

  • JSON holding JSON text

    CLOB

    Если каждое значение - объект или массив JSON.

  • Infinity in REAL columns

    сохраняется как BINARY_DOUBLE_INFINITY

    double в Oracle вмещает бесконечность.

  • INTEGER PRIMARY KEY, AUTOINCREMENT

    GENERATED BY DEFAULT ON NULL AS IDENTITY, продолжается после наибольшего id или значения sqlite_sequence

    Только столбец, объявленный ровно как INTEGER PRIMARY KEY, является rowid; каждая строка сохраняет свой id, а счетчик начинается после наибольшего когда-либо выданного id.

  • COLLATE NOCASE

    точное сравнение

    Oracle сравнивает текст точно, если не указано иное; столбцы NOCASE перестают игнорировать регистр.

    Строка отчета: case_insensitive_collation

  • generated columns

    виртуальные столбцы

    Oracle вычисляет генерируемые столбцы только при чтении; столбцы STORED становятся виртуальными с теми же значениями.

    Строка отчета: stored_as_virtual

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

    обычный столбец

    Формула, которую нельзя записать, оставляет обычный столбец и строку в отчете; в дампе нет значений для генерируемых столбцов.

    Строка отчета: generated_not_translated

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

    без значения по умолчанию

    Значение по умолчанию, которое нельзя записать, опускается и попадает в отчет; CURRENT_TIMESTAMP и datetime('now') записываются.

    Строка отчета: default_not_translated

  • CHECK constraints

    переводится

    Те же проверки, применяемые при загрузке каждой строки.

  • CHECK constraints with functions IntoSQL doesn't write

    не создается

    Проверка, которую нельзя записать, опускается и попадает в отчет.

    Строка отчета: check_skipped

  • partial and expression indexes

    не создается

    IntoSQL создает индексы по целым столбцам; остальные создайте заново после загрузки.

    Строка отчета: index_skipped

  • foreign keys (unenforced unless PRAGMA foreign_keys=ON)

    после данных ENABLE NOVALIDATE, затем валидация

    SQLite проверяет внешние ключи, только если это включено, поэтому строки без родителя встречаются часто: они загружаются, а ключ остается непроверенным с предупреждением, вместо того чтобы остановить загрузку.

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

    удаляется

    Внешние ключи в Oracle действуют только при удалении, с CASCADE или SET NULL.

    Строка отчета: foreign_key_action_unsupported

  • empty strings and empty blobs

    NULL

    Oracle хранит пустую строку как NULL, поэтому значение ' читается обратно как NULL. Отчет подсчитывает их по столбцам.

    Строка отчета: empty_string_null

  • foreign keys to tables the dump doesn't create

    не создается

    Ключ не может ссылаться на таблицу, которой нет.

    Строка отчета: foreign_key_skipped

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

    NOT NULL снимается

    SQLite разрешает первичному ключу, кроме rowid, содержать NULL; в целевой базе столбец не может быть NOT NULL, иначе загрузка остановится.

    Строка отчета: not_null_relaxed

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

    перечисляются в отчете

    Их код написан на собственном языке SQLite, а виртуальным таблицам нужны модули SQLite; они перечислены, чтобы вы могли создать их заново. Их внутренние таблицы не копируются.

    Строка отчета: not_converted_objects

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

    типы определяются по значениям

    Дамп только с данными содержит лишь строки, поэтому типы берутся из значений, а столбцы нумеруются.

    Строка отчета: no_schema

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

    NULL

    unistr(), replace(), char() и || вычисляются в том виде, в каком их пишет оболочка; другие выражения нельзя вычислить без базы данных.

    Строка отчета: expression_value

  • NUL characters in text

    сохраняется

    Оболочка sqlite3 и Python обрезают текст на символе NUL при создании дампа, поэтому в дампе есть только то, что стоит перед ним.

  • text that isn't valid UTF-8

    неверные байты заменяются символом замены

    Дампы записывают такой текст как сырые байты; скрипт в UTF-8.

    Строка отчета: invalid_utf8_replaced

  • text decoded twice (ñ)

    копируется как есть

    Дамп содержит именно эти символы, поэтому они копируются; отчет на них указывает.

    Строка отчета: mojibake_suspected

В SQLiteВ OracleСтрока отчета
declared types (any text: VARCHAR(255), DATETIME, BOOLEAN, JSON or none)тип, в который помещается каждое значение столбцаSQLite хранит любое значение в любом столбце, поэтому объявленный тип - лишь подсказка: каждый столбец получает тип, в который помещаются все его значения, а столбец со смешанными значениями сохраняет их текст.
BOOLEAN, BOOLNUMBER(1) с CHECK на 0 и 1Если каждое значение равно 0 или 1; столбец, где есть и другие значения, сохраняет их как числа или текст.
TEXT, VARCHAR(n), CHAR(n), CLOBVARCHAR2(n CHAR), если каждое значение помещается, иначе CLOBSQLite никогда не ограничивает длину; объявленная длина сохраняется, только если в нее помещается каждое значение.
TEXT and VARCHAR(n) longer than 4000 bytesVARCHAR2(4000 CHAR), если каждое значение укладывается в 4000 байт (750 символов в ключе), иначе CLOBVARCHAR2 по умолчанию вмещает 4000 байт, а Oracle не может индексировать CLOB, поэтому text остается VARCHAR2, если значения помещаются, и становится CLOB, если нет.text_as_lob
DECIMAL(p,s), NUMERICточный тип, если в него помещается каждое значение, иначе doubleSQLite хранит их как целые числа или double; объявленная точность сохраняется, только если значения в нее помещаются.
BLOB, and columns holding bytesBLOBБайты остаются байтами; текст и числа в том же столбце сохраняются как их байты.
DATE, DATETIME, TIMESTAMP holding ISO 8601 textDATE или TIMESTAMP(p), в зависимости от значенийЕсли каждое значение - дата или дата со временем; числа epoch и другой текст сохраняют свои значения как есть.
JSON holding JSON textCLOBЕсли каждое значение - объект или массив JSON.
Infinity in REAL columnsсохраняется как BINARY_DOUBLE_INFINITYdouble в Oracle вмещает бесконечность.
INTEGER PRIMARY KEY, AUTOINCREMENTGENERATED BY DEFAULT ON NULL AS IDENTITY, продолжается после наибольшего id или значения sqlite_sequenceТолько столбец, объявленный ровно как INTEGER PRIMARY KEY, является rowid; каждая строка сохраняет свой id, а счетчик начинается после наибольшего когда-либо выданного id.
COLLATE NOCASEточное сравнениеOracle сравнивает текст точно, если не указано иное; столбцы NOCASE перестают игнорировать регистр.case_insensitive_collation
generated columnsвиртуальные столбцыOracle вычисляет генерируемые столбцы только при чтении; столбцы STORED становятся виртуальными с теми же значениями.stored_as_virtual
generated columns with functions IntoSQL doesn't write, and the || operatorобычный столбецФормула, которую нельзя записать, оставляет обычный столбец и строку в отчете; в дампе нет значений для генерируемых столбцов.generated_not_translated
defaults with functions IntoSQL doesn't write (strftime, randomblob)без значения по умолчаниюЗначение по умолчанию, которое нельзя записать, опускается и попадает в отчет; CURRENT_TIMESTAMP и datetime('now') записываются.default_not_translated
CHECK constraintsпереводитсяТе же проверки, применяемые при загрузке каждой строки.
CHECK constraints with functions IntoSQL doesn't writeне создаетсяПроверка, которую нельзя записать, опускается и попадает в отчет.check_skipped
partial and expression indexesне создаетсяIntoSQL создает индексы по целым столбцам; остальные создайте заново после загрузки.index_skipped
foreign keys (unenforced unless PRAGMA foreign_keys=ON)после данных ENABLE NOVALIDATE, затем валидацияSQLite проверяет внешние ключи, только если это включено, поэтому строки без родителя встречаются часто: они загружаются, а ключ остается непроверенным с предупреждением, вместо того чтобы остановить загрузку.
ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULTудаляетсяВнешние ключи в Oracle действуют только при удалении, с CASCADE или SET NULL.foreign_key_action_unsupported
empty strings and empty blobsNULLOracle хранит пустую строку как NULL, поэтому значение ' читается обратно как NULL. Отчет подсчитывает их по столбцам.empty_string_null
foreign keys to tables the dump doesn't createне создаетсяКлюч не может ссылаться на таблицу, которой нет.foreign_key_skipped
primary keys holding NULL, and NOT NULL columns with values that become NULLNOT NULL снимаетсяSQLite разрешает первичному ключу, кроме rowid, содержать NULL; в целевой базе столбец не может быть NOT NULL, иначе загрузка остановится.not_null_relaxed
views, triggers and virtual tables (FTS, R*Tree)перечисляются в отчетеИх код написан на собственном языке SQLite, а виртуальным таблицам нужны модули SQLite; они перечислены, чтобы вы могли создать их заново. Их внутренние таблицы не копируются.not_converted_objects
dumps without CREATE TABLE (--data-only)типы определяются по значениямДамп только с данными содержит лишь строки, поэтому типы берутся из значений, а столбцы нумеруются.no_schema
expressions in INSERT values other than the text functions dumps writeNULLunistr(), replace(), char() и || вычисляются в том виде, в каком их пишет оболочка; другие выражения нельзя вычислить без базы данных.expression_value
NUL characters in textсохраняетсяОболочка sqlite3 и Python обрезают текст на символе NUL при создании дампа, поэтому в дампе есть только то, что стоит перед ним.
text that isn't valid UTF-8неверные байты заменяются символом заменыДампы записывают такой текст как сырые байты; скрипт в UTF-8.invalid_utf8_replaced
text decoded twice (ñ)копируется как естьДамп содержит именно эти символы, поэтому они копируются; отчет на них указывает.mojibake_suspected

Загрузите скрипт в Oracle

Скрипт создает таблицы, копирует строки, затем добавляет ключи, индексы и внешние ключи, поэтому загрузка идет быстро и останавливается на первой ошибке.

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

Внешние ключи добавляются ENABLE NOVALIDATE, поэтому новые строки проверяются сразу, а затем выполняется валидация. Если старая строка ссылается на несуществующую строку, скрипт сообщает, какое это ограничение, и оставляет его без валидации, а не прерывается на полпути.

Для большого дампа запускайте SQL*Plus на той же машине, где работает база данных. Скрипт фиксирует каждые 100 строк. Пользователю, который его запускает, нужны CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER и CREATE PROCEDURE, а также квота в его табличном пространстве.

Как создать дамп SQLite для лучшего результата

Конвертер читает то, что есть в дампе. Эти параметры сохраняют в нем больше ваших данных:

  • Сам файл базы данных конвертируется как есть и читается в браузере страница за страницей. Сначала закройте приложение, которое в него пишет, чтобы ни одно изменение не осталось в его файле -wal.
  • sqlite3 app.db .dump > app.sql записывает ту же базу данных в SQL, который тоже конвертируется, в формате .sql или .sql.gz.
  • DB Browser for SQLite пишет этот SQL через File, Export, Database to SQL file, как и iterdump() в Python.

Что не конвертируется

Представления и триггеры написаны на собственном языке SQLite. Они перечислены в отчете по имени и никогда не удаляются молча, чтобы вы могли переписать их для Oracle. Виртуальные таблицы, такие как FTS5 и R*Tree, тоже перечислены, а их служебные таблицы пропускаются.

Вопросы о SQLite в Oracle

Нет ответа на ваш вопрос? Напишите нам через страницу контактов, и вам ответит человек. Страница контактов

Мой дамп загружается на сервер?

Нет. Конвертер работает в вашем браузере и читает дамп с диска по частям, поэтому он никогда не покидает ваш компьютер. Приложение для компьютера и командная строка тоже конвертируют на вашем компьютере.

Насколько большим может быть дамп?

Конвертер никогда не держит весь дамп в памяти: он читает файл дважды, по диапазонам, и пишет скрипт по ходу чтения. Дампы в несколько гигабайт конвертируются в браузере, в приложении для компьютера и в командной строке.

Можно ли конвертировать сам файл .db?

Да. Перетащите файл .db, .sqlite или .sqlite3: он читается в браузере и никуда не загружается. Текст с символами NUL и все цифры значения double приходят такими, как хранятся, а .dump может их обрезать.

Из каких версий SQLite может быть дамп?

Файлы баз данных SQLite начиная с 3.0, в UTF-8 или UTF-16, и дампы из .dump оболочки sqlite3 или из iterdump() в Python. Каждый тестовый файл и дамп создан в sqlite3 с 3.31 по 3.54, включая таблицы STRICT и WITHOUT ROWID, и сверен с источником ячейка за ячейкой.

Как определяются типы столбцов, если SQLite их не соблюдает?

Объявленный тип - лишь подсказка, а решают значения: столбец становится NUMBER, BINARY_DOUBLE, DATE, TIMESTAMP, BLOB, VARCHAR2 или CLOB, если в него помещается каждое значение. Пустые строки становятся NULL, как их хранит Oracle, а отчет их подсчитывает.

Сохраняются ли INTEGER PRIMARY KEY и AUTOINCREMENT?

Да. INTEGER PRIMARY KEY становится столбцом identity, каждая строка сохраняет свой id, а следующий id идет после наибольшего или, при AUTOINCREMENT, после значения sqlite_sequence.

А представления и триггеры?

Они перечислены в отчете по имени и не конвертируются, потому что каждая база данных пишет их на своем языке.

На каких версиях Oracle загружается скрипт?

Oracle 19c и новее. Каждый тестовый дамп загружается на 21c и 23ai и останавливается на первой ошибке, если что-то пойдет не так.