Конвертация SQL Server в Oracle
Перетащите скрипт, который Generate Scripts в SSMS записывает со схемой и данными, в формате .sql или .sql.gz, в UTF-16 или UTF-8, и скачайте скрипт Oracle с теми же таблицами, ключами, индексами и данными. Каждое значение, которое Oracle не может хранить как есть, и каждый объект, который он не переносит, указаны в отчете.
18 строк конвертировано, 2 исправления, ни одна не отклонена
Таблицы в shop_2024_sqlserver.sqlДамп SQL Server · создан программой SQL Server Management Objects · utf-8
ordersзаписана как ORDERS10 строк1
11 столбцов ID NUMBER(10) not null CUSTOMER_ID NUMBER(10) not null STATUS VARCHAR2(10 CHAR) not null TOTAL NUMBER(19,4) not null ITEMS NUMBER(3) not null ORDERED_AT TIMESTAMP(0) not null SHIPPED_AT TIMESTAMP(7) NOTE CLOB DETAILS CLOB ORDER_REF VARCHAR2(36 CHAR) not null TOTAL_WITH_TAX NUMBER(12,2) customersзаписана как CUSTOMERS8 строк1
8 столбцов ID NUMBER(10) not null NAME VARCHAR2(100 CHAR) not null EMAIL VARCHAR2(200 CHAR) not null COUNTRY VARCHAR2(2 CHAR) not null IS_ACTIVE NUMBER(1) not null SIGNED_UP DATE CREATED_AT TIMESTAMP(0) WITH TIME ZONE not null ROW_VERSION RAW(8)
Не конвертировано
- Представление paid_orders
- Триггер orders_no_negative
Каждая база данных пишет их на своем языке. Перепишите их для Oracle.
-- Written by IntoSQL from a SQL Server 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 "ORDERS" (
"ID" NUMBER(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1),
"CUSTOMER_ID" NUMBER(10) NOT NULL,
"STATUS" VARCHAR2(10 CHAR) DEFAULT 'pending' NOT NULL,
"TOTAL" NUMBER(19,4) NOT NULL,
"ITEMS" NUMBER(3) DEFAULT 1 NOT NULL,
"ORDERED_AT" TIMESTAMP(0) NOT NULL,
"SHIPPED_AT" TIMESTAMP(7),
"NOTE" CLOB,
"DETAILS" CLOB,
"ORDER_REF" VARCHAR2(36 CHAR) NOT NULL,
"TOTAL_WITH_TAX" NUMBER(12,2) GENERATED ALWAYS AS (CAST(CAST("TOTAL" * (1.16) AS NUMBER(12,2)) AS NUMBER(12,2))) VIRTUAL,
CONSTRAINT "CK_ORDERS_ITEMS" CHECK ("ITEMS" >= 0),
CONSTRAINT "CHECK2" CHECK ("STATUS" = 'cancelled' OR "STATUS" = 'shipped' OR "STATUS" = 'paid' OR "STATUS" = 'pending'),
CONSTRAINT "CHECK3" CHECK ("TOTAL" >= (0))
);
CREATE TABLE "CUSTOMERS" (
"ID" NUMBER(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1),
"NAME" VARCHAR2(100 CHAR) NOT NULL,
"EMAIL" VARCHAR2(200 CHAR) NOT NULL,
"COUNTRY" VARCHAR2(2 CHAR) DEFAULT 'US' NOT NULL,
"IS_ACTIVE" NUMBER(1) DEFAULT 1 NOT NULL,
"SIGNED_UP" DATE,
"CREATED_AT" TIMESTAMP(0) WITH TIME ZONE DEFAULT SYSTIMESTAMP NOT NULL,
"ROW_VERSION" RAW(8),
CONSTRAINT "CK_CUSTOMERS_IS_ACTIVE" CHECK ("IS_ACTIVE" IN (0, 1))
);
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 04:24:00.0000000 -06: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 09:11:42.0000000 +01:00'
);
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 20:05:17.0000000 +01:00'
);
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 10:40:00.0000000 +08: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 15:00:00.0000000 +01: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 10:30:00.0000000 +01: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-03-01 05:29:59.0000000 +05:30'
);
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 14:12:12.0000000 +02:00'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
1,
1,
'shipped',
129.9000,
3,
TIMESTAMP '2024-03-01 10:00:00.0000000',
TIMESTAMP '2024-03-02 16:30:00.1234567',
NULL,
'{"gift": false}',
'0b7a4c2e-3f1d-4e8a-9c55-1a2b3c4d5e6f'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
2,
2,
'paid',
54.0000,
1,
TIMESTAMP '2024-03-02 11:15:00.0000000',
NULL,
'Gift wrap 🎁',
'{"gift": true, "wrap": "red"}',
'1c8b5d3f-4a2e-4f9b-8d66-2b3c4d5e6f70'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
3,
1,
'cancelled',
12.5000,
1,
TIMESTAMP '2024-03-03 09:45:00.0000000',
NULL,
'Customer changed their mind',
NULL,
'2d9c6e4a-5b3f-4a0c-9e77-3c4d5e6f7081'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
4,
4,
'shipped',
980.0000,
12,
TIMESTAMP '2024-03-05 02:10:00.0000000',
TIMESTAMP '2024-03-07 08:00:00.0000000',
'请小心轻放',
'{"fragile": true}',
'3e0d7f5b-6c4a-4b1d-8f88-4d5e6f708192'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
5,
5,
'pending',
45.7500,
2,
TIMESTAMP '2024-03-08 17:20:00.0000000',
NULL,
'Leave at the door; ring twice',
NULL,
'4f1e806c-7d5b-4c2e-9a99-5e6f708192a3'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
6,
6,
'shipped',
310.4000,
5,
TIMESTAMP '2024-03-10 13:00:00.0000000',
TIMESTAMP '2024-03-11 09:00:00.0000000',
'Fragile: "glass"',
'{"fragile": true}',
'50f2917d-8e6c-4d3f-8baa-6f708192a3b4'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
7,
8,
'paid',
76.2000,
2,
TIMESTAMP '2024-03-11 18:45:00.0000000',
NULL,
NULL,
NULL,
'6103a28e-9f7d-4e40-9cbb-708192a3b4c5'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
8,
2,
'shipped',
19.9900,
1,
TIMESTAMP '2024-03-12 08:00:00.0000000',
TIMESTAMP '9999-12-31 23:59:59.9999999',
'Shipped date set to the maximum by an old import',
NULL,
'7214b39f-a08e-4f51-8dcc-8192a3b4c5d6'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
9,
3,
'shipped',
64.0000,
2,
TIMESTAMP '2024-03-14 15:30:00.0000000',
TIMESTAMP '2024-03-15 10:00:00.0000000',
'Two parcels',
'{"parcels": [1, 2]}',
'8325c4a0-b19f-4062-9edd-92a3b4c5d6e7'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"DETAILS",
"ORDER_REF"
) VALUES (
10,
7,
'paid',
1499.0000,
1,
TIMESTAMP '2024-03-15 21:05:00.0000000',
NULL,
'C:\Users\ravi\invoice.pdf',
NULL,
'9436d5b1-c2a0-4173-8fee-a3b4c5d6e7f8'
);
COMMIT;
END;
/
-- Keys, indexes, foreign keys, counters and triggers, after the rows.
ALTER TABLE "ORDERS" ADD CONSTRAINT "PK_ORDERS" PRIMARY KEY ("ID");
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "PK_CUSTOMERS" PRIMARY KEY ("ID");
ALTER TABLE "CUSTOMERS" ADD CONSTRAINT "UQ_CUSTOMERS_EMAIL" UNIQUE ("EMAIL");
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") 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 "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;
/
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';
DROP FUNCTION "INTOSQL_CLOB";
DROP FUNCTION "INTOSQL_BLOB";
COMMIT;
EXIT;
Исправления
- "total_with_tax" таблицы orders хранится в источнике; Oracle вычисляет его при чтении.
- "row_version" таблицы customers - это версия строки, которую SQL Server задает сам; в дампе нет ее значений, поэтому это RAW(8), и столбец пуст.
Требует проверки
- 6 текстовых столбцов сравнивают значения без учета регистра в источнике; Oracle сравнивает точно, поэтому уникальные ключи и поиск могут работать иначе. Используйте сопоставление или тип столбца без учета регистра для столбцов, которым это нужно.
- Не конвертированы представления, триггеры, процедуры и события (2 объекта); отчет перечисляет каждый. Создайте их заново вручную в Oracle.
- Проверку check1 таблицы orders нельзя записать для Oracle (function isjson), поэтому она не создана. Запишите проверку вручную, если она важна.
- Индекс idx_orders_pending таблицы orders использует выражение, которое нельзя записать для Oracle (filtered index), поэтому он не создан. Создайте индекс вручную, если он нужен запросам.
- Значение по умолчанию столбца "order_ref" таблицы orders нельзя записать для Oracle (function uuid), поэтому у столбца его нет. Добавьте значение по умолчанию вручную, если оно нужно новым строкам.
Файл конвертируется на этом компьютере и никуда не загружается.
Другие примеры:
Что меняется при переходе с SQL Server на Oracle
Каждая строка - это правило, которое применяет конвертер, и строка отчета, которую он пишет, когда правило что-то меняет в ваших данных.
bit
NUMBER(1) с CHECK на 0 и 1
В Oracle 21c нет логического типа столбца; 1 и 0 сохраняют значения во всех версиях.
char(n), varchar(n), nchar(n), nvarchar(n)
VARCHAR2(n CHAR), длина в символах
Длина считается в символах, как у nvarchar в SQL Server.
varchar(max), nvarchar(max), text, ntext
VARCHAR2(4000 CHAR), если каждое значение укладывается в 4000 байт, иначе CLOB
VARCHAR2 по умолчанию вмещает 4000 байт, а Oracle не может индексировать CLOB, поэтому text остается VARCHAR2, если значения помещаются, и становится CLOB, если нет.
Строка отчета: text_as_lob
empty strings and empty binary values
NULL
Oracle хранит пустую строку как NULL, поэтому значение ' читается обратно как NULL. Отчет подсчитывает их по столбцам.
Строка отчета: empty_string_null
decimal(p,s), money, smallmoney
NUMBER(p,s); money как NUMBER(19,4)
NUMBER вмещает 38 цифр, как и decimal, поэтому каждое значение точное.
datetime, datetime2, smalldatetime
TIMESTAMP(p)
datetime - это показание часов, как TIMESTAMP в Oracle, который хранит до девяти цифр долей секунды. date становится DATE, который хранит и время суток, оно остается полночью.
datetimeoffset
TIMESTAMP WITH TIME ZONE со смещением каждого значения
Oracle хранит смещения от -12:00 до +14:00; значение со смещением за пределами -12:00 записывается в UTC, тот же момент.
time
INTERVAL DAY TO SECOND от полуночи
В Oracle нет типа для времени суток; интервал от полуночи вмещает любое значение.
dates that aren't valid
NULL
Значение, которое не является датой, становится NULL, и отчет его подсчитывает.
Строка отчета: date_out_of_range
json (SQL Server 2025)
CLOB
Те же значения JSON, которые читают функции JSON в Oracle.
uniqueidentifier
VARCHAR2(36)
Те же идентификаторы, записанные строчными буквами.
binary, varbinary, image
RAW(n) и BLOB
Байты остаются байтами.
geometry, geography
BLOB с собственными байтами SQL Server
SSMS записывает пространственные значения в сериализации SQL Server, которая сохраняется байт в байт.
Строка отчета: spatial_as_native
rowversion, timestamp
BLOB, пустой
SQL Server сам задает версию строки, и SSMS не записывает для нее значений.
Строка отчета: rowversion_empty
xml, sql_variant, hierarchyid, vector
VARCHAR2 или CLOB с текстом каждого значения
В Oracle нет равнозначного типа; xml и sql_variant сохраняют текст каждого значения, а hierarchyid - свой путь, например /1/2/.
Строка отчета: type_replaced
collations that ignore case (_CI_)
точное сравнение
Oracle сравнивает текст точно, если не указано иное, поэтому столбцы, которые в SQL Server не учитывали регистр, теперь различают Ana и ana.
Строка отчета: case_insensitive_collation
IDENTITY
GENERATED BY DEFAULT ON NULL AS IDENTITY, продолжается после наибольшего id
Скопированные id загружаются как есть, а счетчик продолжается после наибольшего.
CREATE SEQUENCE
CREATE SEQUENCE с теми же параметрами
Последовательности в Oracle работают так же. SSMS не записывает, до какого значения дошла последовательность, поэтому она начинается с того, с чего была создана.
computed columns
виртуальные столбцы
Oracle вычисляет генерируемые столбцы только при чтении; столбцы PERSISTED становятся виртуальными с теми же значениями.
Строка отчета: stored_as_virtual
computed columns with functions Oracle lacks
обычный столбец
Формула, которую нельзя записать, оставляет обычный столбец и строку в отчете; SSMS не записывает значения вычисляемых столбцов.
Строка отчета: generated_not_translated
defaults with functions Oracle lacks, and NEXT VALUE FOR
без значения по умолчанию
Значение по умолчанию, которое нельзя записать, опускается и попадает в отчет.
Строка отчета: default_not_translated
CHECK constraints
переводится
Те же проверки, применяемые при загрузке каждой строки.
CHECK constraints with functions Oracle lacks
не создается
Проверка, которую нельзя записать, опускается и попадает в отчет.
Строка отчета: check_skipped
CHECK constraints added WITH NOCHECK or disabled
не создается
SQL Server не применяет эти проверки, поэтому строки могут их нарушать.
Строка отчета: check_not_enforced
filtered and columnstore indexes, and indexes on CLOB columns
не создается
IntoSQL создает индексы b-tree по целым столбцам; остальные создайте заново после загрузки.
Строка отчета: index_skipped
foreign keys
после данных ENABLE NOVALIDATE, затем валидация с предупреждением о строках без родителя
Ключ сразу проверяет новые строки, а валидация идет последней; при строках без родителя он остается невалидированным с предупреждением, и загрузка не останавливается.
ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT
удаляется
Внешние ключи в Oracle действуют только при удалении, с CASCADE или SET NULL.
Строка отчета: foreign_key_action_unsupported
names over 128 bytes
сокращается
Имена в Oracle 12.2 и новее вмещают 128 байт, а в SQL Server - 128 символов.
Строка отчета: name_shortened
foreign keys to tables the dump doesn't create
не создается
Ключ не может ссылаться на таблицу, которой нет.
Строка отчета: foreign_key_skipped
tables on a partition scheme
одна таблица со строками всех секций
Строки те же; при необходимости секционируйте таблицу заново в Oracle.
Строка отчета: partitions_dropped
temporal tables (SYSTEM_VERSIONING)
две таблицы: текущие строки и история
Таблица и ее таблица истории копируются как обычные таблицы; Oracle не ведет историю сам.
Строка отчета: system_versioning_dropped
schemas
одна схема, имя таблицы начинается с имени ее схемы
Скрипт загружается в схему пользователя, который его запускает, поэтому имена таблиц из разных схем начинаются с имени схемы; таблицы из dbo сохраняют свои имена.
Строка отчета: schemas_merged
NOT NULL columns with values that become NULL
NOT NULL снимается
Столбец, значения которого пришлось заменить на NULL, не может сохранить NOT NULL, иначе загрузка остановится.
Строка отчета: not_null_relaxed
views, functions, procedures, triggers, synonyms, types and partition functions
перечисляются в отчете
Их код написан на T-SQL, поэтому они перечислены, чтобы вы создали их заново.
Строка отчета: not_converted_objects
scripts without CREATE TABLE (data only)
типы определяются по значениям
Скрипт только с данными содержит лишь строки, поэтому типы берутся из значений.
Строка отчета: no_schema
expressions in INSERT values
NULL
Конвертер, который не запускает базу данных, не может их вычислить.
Строка отчета: expression_value
types IntoSQL doesn't know
CLOB
Тип text вмещает любое значение; измените тип после загрузки.
Строка отчета: unknown_type
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
| В SQL Server | В Oracle | Строка отчета |
|---|---|---|
| bit | NUMBER(1) с CHECK на 0 и 1В Oracle 21c нет логического типа столбца; 1 и 0 сохраняют значения во всех версиях. | |
| char(n), varchar(n), nchar(n), nvarchar(n) | VARCHAR2(n CHAR), длина в символахДлина считается в символах, как у nvarchar в SQL Server. | |
| varchar(max), nvarchar(max), text, ntext | VARCHAR2(4000 CHAR), если каждое значение укладывается в 4000 байт, иначе CLOBVARCHAR2 по умолчанию вмещает 4000 байт, а Oracle не может индексировать CLOB, поэтому text остается VARCHAR2, если значения помещаются, и становится CLOB, если нет. | text_as_lob |
| empty strings and empty binary values | NULLOracle хранит пустую строку как NULL, поэтому значение ' читается обратно как NULL. Отчет подсчитывает их по столбцам. | empty_string_null |
| decimal(p,s), money, smallmoney | NUMBER(p,s); money как NUMBER(19,4)NUMBER вмещает 38 цифр, как и decimal, поэтому каждое значение точное. | |
| datetime, datetime2, smalldatetime | TIMESTAMP(p)datetime - это показание часов, как TIMESTAMP в Oracle, который хранит до девяти цифр долей секунды. date становится DATE, который хранит и время суток, оно остается полночью. | |
| datetimeoffset | TIMESTAMP WITH TIME ZONE со смещением каждого значенияOracle хранит смещения от -12:00 до +14:00; значение со смещением за пределами -12:00 записывается в UTC, тот же момент. | |
| time | INTERVAL DAY TO SECOND от полуночиВ Oracle нет типа для времени суток; интервал от полуночи вмещает любое значение. | |
| dates that aren't valid | NULLЗначение, которое не является датой, становится NULL, и отчет его подсчитывает. | date_out_of_range |
| json (SQL Server 2025) | CLOBТе же значения JSON, которые читают функции JSON в Oracle. | |
| uniqueidentifier | VARCHAR2(36)Те же идентификаторы, записанные строчными буквами. | |
| binary, varbinary, image | RAW(n) и BLOBБайты остаются байтами. | |
| geometry, geography | BLOB с собственными байтами SQL ServerSSMS записывает пространственные значения в сериализации SQL Server, которая сохраняется байт в байт. | spatial_as_native |
| rowversion, timestamp | BLOB, пустойSQL Server сам задает версию строки, и SSMS не записывает для нее значений. | rowversion_empty |
| xml, sql_variant, hierarchyid, vector | VARCHAR2 или CLOB с текстом каждого значенияВ Oracle нет равнозначного типа; xml и sql_variant сохраняют текст каждого значения, а hierarchyid - свой путь, например /1/2/. | type_replaced |
| collations that ignore case (_CI_) | точное сравнениеOracle сравнивает текст точно, если не указано иное, поэтому столбцы, которые в SQL Server не учитывали регистр, теперь различают Ana и ana. | case_insensitive_collation |
| IDENTITY | GENERATED BY DEFAULT ON NULL AS IDENTITY, продолжается после наибольшего idСкопированные id загружаются как есть, а счетчик продолжается после наибольшего. | |
| CREATE SEQUENCE | CREATE SEQUENCE с теми же параметрамиПоследовательности в Oracle работают так же. SSMS не записывает, до какого значения дошла последовательность, поэтому она начинается с того, с чего была создана. | |
| computed columns | виртуальные столбцыOracle вычисляет генерируемые столбцы только при чтении; столбцы PERSISTED становятся виртуальными с теми же значениями. | stored_as_virtual |
| computed columns with functions Oracle lacks | обычный столбецФормула, которую нельзя записать, оставляет обычный столбец и строку в отчете; SSMS не записывает значения вычисляемых столбцов. | generated_not_translated |
| defaults with functions Oracle lacks, and NEXT VALUE FOR | без значения по умолчаниюЗначение по умолчанию, которое нельзя записать, опускается и попадает в отчет. | default_not_translated |
| CHECK constraints | переводитсяТе же проверки, применяемые при загрузке каждой строки. | |
| CHECK constraints with functions Oracle lacks | не создаетсяПроверка, которую нельзя записать, опускается и попадает в отчет. | check_skipped |
| CHECK constraints added WITH NOCHECK or disabled | не создаетсяSQL Server не применяет эти проверки, поэтому строки могут их нарушать. | check_not_enforced |
| filtered and columnstore indexes, and indexes on CLOB columns | не создаетсяIntoSQL создает индексы b-tree по целым столбцам; остальные создайте заново после загрузки. | index_skipped |
| foreign keys | после данных ENABLE NOVALIDATE, затем валидация с предупреждением о строках без родителяКлюч сразу проверяет новые строки, а валидация идет последней; при строках без родителя он остается невалидированным с предупреждением, и загрузка не останавливается. | |
| ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT | удаляетсяВнешние ключи в Oracle действуют только при удалении, с CASCADE или SET NULL. | foreign_key_action_unsupported |
| names over 128 bytes | сокращаетсяИмена в Oracle 12.2 и новее вмещают 128 байт, а в SQL Server - 128 символов. | name_shortened |
| foreign keys to tables the dump doesn't create | не создаетсяКлюч не может ссылаться на таблицу, которой нет. | foreign_key_skipped |
| tables on a partition scheme | одна таблица со строками всех секцийСтроки те же; при необходимости секционируйте таблицу заново в Oracle. | partitions_dropped |
| temporal tables (SYSTEM_VERSIONING) | две таблицы: текущие строки и историяТаблица и ее таблица истории копируются как обычные таблицы; Oracle не ведет историю сам. | system_versioning_dropped |
| schemas | одна схема, имя таблицы начинается с имени ее схемыСкрипт загружается в схему пользователя, который его запускает, поэтому имена таблиц из разных схем начинаются с имени схемы; таблицы из dbo сохраняют свои имена. | schemas_merged |
| NOT NULL columns with values that become NULL | NOT NULL снимаетсяСтолбец, значения которого пришлось заменить на NULL, не может сохранить NOT NULL, иначе загрузка остановится. | not_null_relaxed |
| views, functions, procedures, triggers, synonyms, types and partition functions | перечисляются в отчетеИх код написан на T-SQL, поэтому они перечислены, чтобы вы создали их заново. | not_converted_objects |
| scripts without CREATE TABLE (data only) | типы определяются по значениямСкрипт только с данными содержит лишь строки, поэтому типы берутся из значений. | no_schema |
| expressions in INSERT values | NULLКонвертер, который не запускает базу данных, не может их вычислить. | expression_value |
| types IntoSQL doesn't know | CLOBТип text вмещает любое значение; измените тип после загрузки. | unknown_type |
| 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 @sql_server.oracle.sqlВнешние ключи добавляются ENABLE NOVALIDATE, поэтому новые строки проверяются сразу, а затем выполняется валидация. Если старая строка ссылается на несуществующую строку, скрипт сообщает, какое это ограничение, и оставляет его без валидации, а не прерывается на полпути.
Для большого дампа запускайте SQL*Plus на той же машине, где работает база данных. Скрипт фиксирует каждые 100 строк. Пользователю, который его запускает, нужны CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER и CREATE PROCEDURE, а также квота в его табличном пространстве.
Как создать дамп SQL Server для лучшего результата
Конвертер читает то, что есть в дампе. Эти параметры сохраняют в нем больше ваших данных:
- В SSMS щелкните базу данных правой кнопкой, выберите Tasks, Generate Scripts и отметьте таблицы. dbatools, mssql-scripter и другие инструменты на той же библиотеке пишут такой же скрипт.
- В разделе Advanced задайте для Types of data to script значение Schema and data. Скрипт только со схемой содержит таблицы без строк.
- Сохраните его в Unicode, как по умолчанию в SSMS, или в UTF-8: оба читаются одинаково, gzip тоже подходит.
Что не конвертируется
Представления, функции, процедуры, триггеры, синонимы, правила и политики безопасности написаны на T-SQL. Они перечислены в отчете по имени и никогда не удаляются молча, чтобы вы могли переписать их для Oracle.
Вопросы о SQL Server в Oracle
Нет ответа на ваш вопрос? Напишите нам через страницу контактов, и вам ответит человек. Страница контактов
Мой дамп загружается на сервер?
Нет. Конвертер работает в вашем браузере и читает дамп с диска по частям, поэтому он никогда не покидает ваш компьютер. Приложение для компьютера и командная строка тоже конвертируют на вашем компьютере.
Насколько большим может быть дамп?
Конвертер никогда не держит весь дамп в памяти: он читает файл дважды, по диапазонам, и пишет скрипт по ходу чтения. Дампы в несколько гигабайт конвертируются в браузере, в приложении для компьютера и в командной строке.
Читает ли он файл UTF-16, который сохраняет SSMS?
Да. SSMS по умолчанию сохраняет скрипты в UTF-16, а конвертер одинаково читает UTF-16 и UTF-8, сжатые gzip или нет, с GO между пакетами.
Из каких версий SQL Server может быть скрипт?
Скрипты, которые SSMS, dbatools или mssql-scripter пишут из SQL Server 2017 и новее. Каждый тестовый скрипт создан в SQL Server 2017, 2022 и 2025 и сверен с источником ячейка за ячейкой.
Сохраняются ли значения IDENTITY?
Да. Столбцы IDENTITY становятся столбцами identity, каждая строка сохраняет свой id, а следующий id идет после наибольшего. Последовательности создаются с теми же параметрами.
Что происходит с money, datetimeoffset и другими типами SQL Server?
bit становится NUMBER(1), datetime2 - TIMESTAMP со всеми цифрами, datetimeoffset - TIMESTAMP WITH TIME ZONE со своим смещением, а nvarchar(max) - CLOB, если значения не помещаются в VARCHAR2. Пустые строки становятся NULL, как их хранит Oracle, и отчет их подсчитывает.
А процедуры, триггеры и представления?
Они перечислены в отчете по имени и не конвертируются, потому что каждая база данных пишет их на своем языке.
На каких версиях Oracle загружается скрипт?
Oracle 19c и новее. Каждый тестовый скрипт загружается на 21c и 23ai и останавливается на первой ошибке, если что-то пойдет не так.