Перенесите экспорт Oracle на более старую или новую версию Oracle
Перетащите файл .sql, который пишет Database Export в SQL Developer или SQLcl, с таблицами и командами Insert, и скачайте скрипт, который загружается на Oracle 19c и новее. NUMBER, DATE, TIMESTAMP, LOB, identity и последовательности остаются как есть, XMLTYPE и JSON хранят свой текст в CLOB, и каждое изменение указано в отчете.
18 строк конвертировано, без исправлений, ни одна не отклонена
Таблицы в shop_2024_oracle.sqlДамп Oracle · создан программой SQL Developer · utf-8
customersзаписана как CUSTOMERS8 строк
7 столбцов 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записана как ORDERS10 строк
9 столбцов 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;
Исправления
Исправлять ничего не пришлось.
Файл конвертируется на этом компьютере и никуда не загружается.
Другие примеры:
Что меняется между файлом и скриптом
Каждая строка - это правило, которое применяет конвертер, и строка отчета, которую он пишет, когда правило что-то меняет в ваших данных.
BOOLEAN (23ai)
BOOLEAN в 23ai, иначе NUMBER(1) с CHECK на 0 и 1
TRUE и FALSE остаются true и false.
VARCHAR2(n BYTE|CHAR), NVARCHAR2(n), CHAR(n), NCHAR(n), CLOB, NCLOB, LONG
те же типы с длинами в BYTE или CHAR
Те же текстовые типы; LONG становится CLOB, который предпочитают все версии начиная с 8.
VARCHAR2 and NVARCHAR2 past what the target's own types hold
VARCHAR2(4000 CHAR), если каждое значение укладывается в 4000 байт, иначе CLOB
VARCHAR2 по умолчанию вмещает 4000 байт, а Oracle не может индексировать CLOB, поэтому text остается VARCHAR2, если значения помещаются, и становится CLOB, если нет.
Строка отчета: text_as_lob
NUMBER, NUMBER(p,s), FLOAT(b)
те же типы NUMBER
Те же типы NUMBER и FLOAT со всеми цифрами.
INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND
те же типы INTERVAL
Те же интервалы.
DATE, TIMESTAMP(p)
DATE и TIMESTAMP(p), как объявлено
Те же типы, поэтому каждая дата сохраняет время с точностью до секунды.
TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE
те же типы
Oracle хранит смещения от -12:00 до +14:00; значение со смещением за пределами -12:00 записывается в UTC, тот же момент.
JSON (21c), and CLOB holding JSON
JSON в 21c и новее, иначе CLOB
Те же значения JSON; SQL NULL, который экспорт записал как 'null', остается NULL.
BLOB, RAW(n), LONG RAW
те же типы; LONG RAW как BLOB
Байты остаются байтами.
ROWID, UROWID, XMLTYPE, SDO_GEOMETRY
CLOB с их текстом
XMLTYPE, ROWID и UROWID сохраняют свой текст в CLOB, поэтому скрипт загружается на любой версии начиная с 19c.
Строка отчета: type_replaced
collations that ignore case (BINARY_CI)
точное сравнение
Сортировки столбцов не записываются, поэтому столбец, который не учитывал регистр (BINARY_CI), теперь различает Ana и ana.
Строка отчета: case_insensitive_collation
identity columns, and a sequence a BEFORE INSERT trigger assigns
GENERATED BY DEFAULT ON NULL AS IDENTITY, продолжается после наибольшего id
Скопированные id загружаются как есть, а счетчик продолжается после наибольшего. Столбец, который триггер заполняет из последовательности (способ до 12c), тоже становится столбцом identity.
identity columns the target can't count
обычное целое
Oracle нумерует один столбец identity на таблицу; любой другой сохраняет свои значения без счетчика.
Строка отчета: counter_dropped
CREATE SEQUENCE
CREATE SEQUENCE с теми же параметрами
Экспорт записывает, до какого значения дошла последовательность, как ее START WITH, поэтому она продолжается оттуда.
virtual columns (GENERATED ALWAYS AS ... VIRTUAL)
виртуальные столбцы
Те же виртуальные столбцы.
Строка отчета: stored_as_virtual
virtual columns with functions IntoSQL doesn't write, and the || operator
обычный столбец
Формула, которую нельзя записать для Oracle, оставляет обычный столбец и строку в отчете; значения, которые экспорт записал для виртуальных столбцов, опускаются, и Oracle не может их вычислить.
Строка отчета: generated_not_translated
defaults with functions IntoSQL doesn't write (SYS_GUID(), ||)
без значения по умолчанию
Значение по умолчанию, которое нельзя записать, опускается и попадает в отчет.
Строка отчета: default_not_translated
CHECK constraints
переводится
Те же проверки, применяемые при загрузке каждой строки.
CHECK constraints with functions IntoSQL doesn't write
не создается
Проверка, которую нельзя записать, опускается и попадает в отчет.
Строка отчета: check_skipped
CHECK constraints that are DISABLE or ENABLE NOVALIDATE
не создается
Oracle не применяет эти проверки к уже существующим строкам, поэтому строки могут их нарушать.
Строка отчета: check_not_enforced
function-based, bitmap and domain indexes
не создается
IntoSQL создает индексы b-tree по целым столбцам; остальные создайте заново после загрузки.
Строка отчета: index_skipped
foreign keys
после данных ENABLE NOVALIDATE, затем валидация с предупреждением о строках без родителя
Ключ сразу проверяет новые строки, а валидация идет последней; при строках без родителя он остается невалидированным с предупреждением, и загрузка не останавливается.
ON DELETE CASCADE that cascades in a cycle or along a second path
удаляется
Внешние ключи в Oracle действуют только при удалении, с CASCADE или SET NULL.
Строка отчета: foreign_key_action_unsupported
foreign keys to tables the export doesn't create, and DISABLE or NOVALIDATE ones
не создается
Ключ не может ссылаться на таблицу, которой нет, а у ключа, который Oracle не проверяет, могут быть строки без родителя.
Строка отчета: foreign_key_skipped
names longer than Oracle 12.1 allows
сокращается
Имена в Oracle с версии 12.2 вмещают 128 байт; более длинное имя сокращается.
Строка отчета: name_shortened
partitioned tables
одна таблица со строками всех секций
Строки те же; при необходимости секционируйте таблицу заново в Oracle.
Строка отчета: partitions_dropped
several schemas in one export
одна схема, имя таблицы начинается с имени ее схемы
Скрипт загружается в схему пользователя, который его запускает, поэтому таблицы из разных схем получают в начале имя своей схемы; экспорт одной схемы сохраняет имена своих таблиц.
Строка отчета: schemas_merged
NOT NULL columns with values that become NULL
NOT NULL снимается
Столбец, значения которого пришлось заменить на NULL, не может сохранить NOT NULL, иначе загрузка остановится.
Строка отчета: not_null_relaxed
views, synonyms, types, packages, procedures, functions and other triggers
перечисляются в отчете
Их код написан на PL/SQL, поэтому они перечислены, чтобы вы создали их заново.
Строка отчета: not_converted_objects
exports without CREATE TABLE (data only)
типы определяются по значениям
Экспорт только с данными содержит лишь строки, поэтому типы берутся из значений.
Строка отчета: no_schema
expressions in INSERT values other than the ones exports write
NULL
Конвертер, который не запускает базу данных, не может их вычислить; to_date, to_timestamp, TO_CLOB, HEXTORAW и другие функции, которые пишут экспорты, читаются.
Строка отчета: expression_value
types IntoSQL doesn't know, and object types
CLOB
Тип text вмещает любое значение; измените тип после загрузки.
Строка отчета: unknown_type
dates before year 1 and time zones given as region names
NULL
Значение, которое не является датой, становится NULL, и отчет его подсчитывает.
Строка отчета: date_out_of_range
NaN and Infinity in BINARY_FLOAT and BINARY_DOUBLE
NaN и Infinity сохраняются
Типы с плавающей точкой в Oracle хранят NaN и бесконечность.
NUL characters in text
сохраняется
VARCHAR2 и CLOB могут содержать символ NUL, поэтому значение копируется как есть.
text that isn't valid in its encoding
неверные байты заменяются символом замены
Скрипт в UTF-8, и каждое значение должно быть корректным текстом.
Строка отчета: invalid_utf8_replaced
text decoded twice (ñ)
копируется как есть
Скрипт содержит именно эти символы, поэтому они копируются; отчет на них указывает.
Строка отчета: mojibake_suspected
| В файле | В скрипте | Строка отчета |
|---|---|---|
| BOOLEAN (23ai) | BOOLEAN в 23ai, иначе NUMBER(1) с CHECK на 0 и 1TRUE и FALSE остаются true и false. | |
| VARCHAR2(n BYTE|CHAR), NVARCHAR2(n), CHAR(n), NCHAR(n), CLOB, NCLOB, LONG | те же типы с длинами в BYTE или CHARТе же текстовые типы; LONG становится CLOB, который предпочитают все версии начиная с 8. | |
| VARCHAR2 and NVARCHAR2 past what the target's own types hold | VARCHAR2(4000 CHAR), если каждое значение укладывается в 4000 байт, иначе CLOBVARCHAR2 по умолчанию вмещает 4000 байт, а Oracle не может индексировать CLOB, поэтому text остается VARCHAR2, если значения помещаются, и становится CLOB, если нет. | text_as_lob |
| NUMBER, NUMBER(p,s), FLOAT(b) | те же типы NUMBERТе же типы NUMBER и FLOAT со всеми цифрами. | |
| INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND | те же типы INTERVALТе же интервалы. | |
| DATE, TIMESTAMP(p) | DATE и TIMESTAMP(p), как объявленоТе же типы, поэтому каждая дата сохраняет время с точностью до секунды. | |
| TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE | те же типыOracle хранит смещения от -12:00 до +14:00; значение со смещением за пределами -12:00 записывается в UTC, тот же момент. | |
| JSON (21c), and CLOB holding JSON | JSON в 21c и новее, иначе CLOBТе же значения JSON; SQL NULL, который экспорт записал как 'null', остается NULL. | |
| BLOB, RAW(n), LONG RAW | те же типы; LONG RAW как BLOBБайты остаются байтами. | |
| ROWID, UROWID, XMLTYPE, SDO_GEOMETRY | CLOB с их текстомXMLTYPE, ROWID и UROWID сохраняют свой текст в CLOB, поэтому скрипт загружается на любой версии начиная с 19c. | type_replaced |
| collations that ignore case (BINARY_CI) | точное сравнениеСортировки столбцов не записываются, поэтому столбец, который не учитывал регистр (BINARY_CI), теперь различает Ana и ana. | case_insensitive_collation |
| identity columns, and a sequence a BEFORE INSERT trigger assigns | GENERATED BY DEFAULT ON NULL AS IDENTITY, продолжается после наибольшего idСкопированные id загружаются как есть, а счетчик продолжается после наибольшего. Столбец, который триггер заполняет из последовательности (способ до 12c), тоже становится столбцом identity. | |
| identity columns the target can't count | обычное целоеOracle нумерует один столбец identity на таблицу; любой другой сохраняет свои значения без счетчика. | counter_dropped |
| CREATE SEQUENCE | CREATE SEQUENCE с теми же параметрамиЭкспорт записывает, до какого значения дошла последовательность, как ее START WITH, поэтому она продолжается оттуда. | |
| virtual columns (GENERATED ALWAYS AS ... VIRTUAL) | виртуальные столбцыТе же виртуальные столбцы. | stored_as_virtual |
| virtual columns with functions IntoSQL doesn't write, and the || operator | обычный столбецФормула, которую нельзя записать для Oracle, оставляет обычный столбец и строку в отчете; значения, которые экспорт записал для виртуальных столбцов, опускаются, и Oracle не может их вычислить. | generated_not_translated |
| defaults with functions IntoSQL doesn't write (SYS_GUID(), ||) | без значения по умолчаниюЗначение по умолчанию, которое нельзя записать, опускается и попадает в отчет. | default_not_translated |
| CHECK constraints | переводитсяТе же проверки, применяемые при загрузке каждой строки. | |
| CHECK constraints with functions IntoSQL doesn't write | не создаетсяПроверка, которую нельзя записать, опускается и попадает в отчет. | check_skipped |
| CHECK constraints that are DISABLE or ENABLE NOVALIDATE | не создаетсяOracle не применяет эти проверки к уже существующим строкам, поэтому строки могут их нарушать. | check_not_enforced |
| function-based, bitmap and domain indexes | не создаетсяIntoSQL создает индексы b-tree по целым столбцам; остальные создайте заново после загрузки. | index_skipped |
| foreign keys | после данных ENABLE NOVALIDATE, затем валидация с предупреждением о строках без родителяКлюч сразу проверяет новые строки, а валидация идет последней; при строках без родителя он остается невалидированным с предупреждением, и загрузка не останавливается. | |
| ON DELETE CASCADE that cascades in a cycle or along a second path | удаляетсяВнешние ключи в Oracle действуют только при удалении, с CASCADE или SET NULL. | foreign_key_action_unsupported |
| foreign keys to tables the export doesn't create, and DISABLE or NOVALIDATE ones | не создаетсяКлюч не может ссылаться на таблицу, которой нет, а у ключа, который Oracle не проверяет, могут быть строки без родителя. | foreign_key_skipped |
| names longer than Oracle 12.1 allows | сокращаетсяИмена в Oracle с версии 12.2 вмещают 128 байт; более длинное имя сокращается. | name_shortened |
| partitioned tables | одна таблица со строками всех секцийСтроки те же; при необходимости секционируйте таблицу заново в Oracle. | partitions_dropped |
| several schemas in one export | одна схема, имя таблицы начинается с имени ее схемыСкрипт загружается в схему пользователя, который его запускает, поэтому таблицы из разных схем получают в начале имя своей схемы; экспорт одной схемы сохраняет имена своих таблиц. | schemas_merged |
| NOT NULL columns with values that become NULL | NOT NULL снимаетсяСтолбец, значения которого пришлось заменить на NULL, не может сохранить NOT NULL, иначе загрузка остановится. | not_null_relaxed |
| views, synonyms, types, packages, procedures, functions and other triggers | перечисляются в отчетеИх код написан на PL/SQL, поэтому они перечислены, чтобы вы создали их заново. | not_converted_objects |
| exports without CREATE TABLE (data only) | типы определяются по значениямЭкспорт только с данными содержит лишь строки, поэтому типы берутся из значений. | no_schema |
| expressions in INSERT values other than the ones exports write | NULLКонвертер, который не запускает базу данных, не может их вычислить; to_date, to_timestamp, TO_CLOB, HEXTORAW и другие функции, которые пишут экспорты, читаются. | expression_value |
| types IntoSQL doesn't know, and object types | CLOBТип text вмещает любое значение; измените тип после загрузки. | unknown_type |
| dates before year 1 and time zones given as region names | NULLЗначение, которое не является датой, становится NULL, и отчет его подсчитывает. | date_out_of_range |
| NaN and Infinity in BINARY_FLOAT and BINARY_DOUBLE | NaN и Infinity сохраняютсяТипы с плавающей точкой в Oracle хранят NaN и бесконечность. | |
| NUL characters in text | сохраняетсяVARCHAR2 и CLOB могут содержать символ NUL, поэтому значение копируется как есть. | |
| text that isn't valid in its encoding | неверные байты заменяются символом заменыСкрипт в UTF-8, и каждое значение должно быть корректным текстом. | invalid_utf8_replaced |
| text decoded twice (ñ) | копируется как естьСкрипт содержит именно эти символы, поэтому они копируются; отчет на них указывает. | mojibake_suspected |
Загрузите скрипт в Oracle
Скрипт создает таблицы, копирует строки, затем добавляет ключи, индексы и внешние ключи, поэтому загрузка идет быстро и останавливается на первой ошибке.
NLS_LANG=.AL32UTF8 sqlplus -S -L user@//localhost/mydb @oracle.oracle.sqlВнешние ключи добавляются ENABLE NOVALIDATE, поэтому новые строки проверяются сразу, а затем выполняется валидация. Если старая строка ссылается на несуществующую строку, скрипт сообщает, какое это ограничение, и оставляет его без валидации, а не прерывается на полпути.
Для большого дампа запускайте SQL*Plus на той же машине, где работает база данных. Скрипт фиксирует каждые 100 строк. Пользователю, который его запускает, нужны CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER и CREATE PROCEDURE, а также квота в его табличном пространстве.
Как создать дамп Oracle для лучшего результата
Конвертер читает то, что есть в дампе. Эти параметры сохраняют в нем больше ваших данных:
- В SQL Developer выберите Tools, Database Export, с DDL и форматом данных Insert. SQLcl записывает то же самое с SET SQLFORMAT INSERT.
- Выполните ALTER SESSION SET NLS_DATE_FORMAT = 'SYYYY-MM-DD HH24:MI:SS' перед экспортом: формат по умолчанию записывает даты без времени и века.
- Файл .dmp из exp или expdp двоичный: импортируйте его в базу Oracle, например в Oracle Database Free в Docker, и экспортируйте через SQL Developer.
Что не конвертируется
Представления, триггеры, процедуры, функции и другие объекты, написанные на собственном языке Oracle, перечислены в отчете по имени и никогда не удаляются молча, чтобы вы могли проверить каждый на той версии Oracle, в которую загружаете, прежде чем создать его заново.
Вопросы о переносе Oracle между версиями
Нет ответа на ваш вопрос? Напишите нам через страницу контактов, и вам ответит человек. Страница контактов
Мой дамп загружается на сервер?
Нет. Конвертер работает в вашем браузере и читает дамп с диска по частям, поэтому он никогда не покидает ваш компьютер. Приложение для компьютера и командная строка тоже конвертируют на вашем компьютере.
Насколько большим может быть дамп?
Конвертер никогда не держит весь дамп в памяти: он читает файл дважды, по диапазонам, и пишет скрипт по ходу чтения. Дампы в несколько гигабайт конвертируются в браузере, в приложении для компьютера и в командной строке.
Можно ли конвертировать файл .dmp из exp или expdp?
Не напрямую: Data Pump и исходный Export пишут двоичный формат, который читает только Oracle. Импортируйте его в любую базу Oracle (Oracle Database Free работает в Docker) и экспортируйте через Database Export в SQL Developer или SQLcl. Конвертер сообщает об этом, когда получает файл .dmp.
Из каких версий Oracle может быть экспорт?
Экспорты из SQL Developer и SQLcl с определениями таблиц из DBMS_METADATA, из Oracle 11g и новее. Каждый тестовый экспорт создан в Oracle 21c и 23ai, в американском, немецком и ISO-сеансах, и сверен с источником ячейка за ячейкой.
Что происходит с NUMBER, DATE и другими типами Oracle?
Они остаются как есть: NUMBER со своей точностью, DATE, TIMESTAMP, интервалы, CHAR и VARCHAR2 со своими длинами, RAW и LOB. XMLTYPE и JSON сохраняют свой текст в CLOB, поэтому скрипт загружается на 19c.
Сохраняются ли столбцы identity и последовательности?
Да. Столбцы identity и последовательности остаются как есть и продолжаются с того значения, до которого, по данным экспорта, они дошли.
А пакеты, процедуры и триггеры PL/SQL?
Они перечислены в отчете по имени и не конвертируются, чтобы вы могли создать их заново, когда таблицы будут загружены.
На каких версиях Oracle загружается скрипт?
Oracle 19c и новее. Каждый тестовый экспорт загружается на 21c и 23ai и останавливается на первой ошибке, если что-то пойдет не так.