Konwertuj SQL Server do Oracle
Upuść skrypt, który Generate Scripts w SSMS zapisuje ze schematem i danymi, jako .sql lub .sql.gz, w UTF-16 lub UTF-8, i pobierz skrypt Oracle z tymi samymi tabelami, kluczami, indeksami i danymi. Każda wartość, której Oracle nie może przechować bez zmian, i każdy obiekt, którego nie przenosi, są wymienione w raporcie.
18 wierszy przekonwertowanych, 2 poprawki, brak odrzuconych
Tabele w pliku shop_2024_sqlserver.sqlZrzut SQL Server · zapisany przez SQL Server Management Objects · utf-8
orderszapisana jako ORDERS10 wierszy1
11 kolumn 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) customerszapisana jako CUSTOMERS8 wierszy1
8 kolumn 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)
Nieprzekonwertowane
- Widok paid_orders
- Wyzwalacz orders_no_negative
Każda baza danych zapisuje je we własnym języku. Przepisz je dla 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;
Poprawki
- "total_with_tax" w tabeli orders jest w źródle przechowywana; Oracle oblicza ją przy odczycie.
- "row_version" w tabeli customers to wersja wiersza, którą SQL Server ustawia sam; zrzut nie ma dla niej wartości, więc ma typ RAW(8) i jest pusta.
Do sprawdzenia
- W źródle 6 kolumn tekstowych 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.
- Ograniczenia CHECK check1 w tabeli orders nie da się zapisać dla Oracle (function isjson), więc go nie utworzono. Zapisz ograniczenie CHECK ręcznie, jeśli jest ważne.
- Indeks idx_orders_pending w tabeli orders używa wyrażenia, którego nie da się zapisać dla Oracle (filtered index), więc go nie utworzono. Utwórz indeks ręcznie, jeśli zapytania go potrzebują.
- Wartości domyślnej "order_ref" w tabeli orders nie da się zapisać dla Oracle (function uuid), więc kolumna nie ma wartości domyślnej. Dodaj wartość domyślną ręcznie, jeśli nowe wiersze jej potrzebują.
Plik jest konwertowany na tym komputerze i nigdy nie jest wysyłany.
Inne przykłady:
Co zmienia się między SQL Server 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.
bit
NUMBER(1) z CHECK 0 i 1
Oracle 21c nie ma typu kolumny logicznej; 1 i 0 zachowują wartości w każdej wersji.
char(n), varchar(n), nchar(n), nvarchar(n)
VARCHAR2(n CHAR), liczony w znakach
Długości liczą znaki, tak jak nvarchar w SQL Server.
varchar(max), nvarchar(max), text, ntext
VARCHAR2(4000 CHAR), gdy każda wartość mieści się w 4000 bajtach, 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
empty strings and empty binary values
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
decimal(p,s), money, smallmoney
NUMBER(p,s); money jako NUMBER(19,4)
NUMBER mieści 38 cyfr, tak jak decimal, więc każda wartość jest dokładna.
datetime, datetime2, smalldatetime
TIMESTAMP(p)
datetime to wskazanie zegara, jak TIMESTAMP w Oracle, który zachowuje do dziewięciu cyfr ułamka sekundy. date staje się DATE, który zawiera też godzinę, ustawioną na północ.
datetimeoffset
TIMESTAMP WITH TIME ZONE z przesunięciem każdej wartości
Oracle przechowuje przesunięcia od -12:00 do +14:00; wartość z przesunięciem poza -12:00 jest zapisywana w UTC, ten sam moment.
time
INTERVAL DAY TO SECOND od północy
Oracle nie ma typu godziny dnia; interwał od północy mieści każdą wartość.
dates that aren't valid
NULL
Wartość, która nie jest datą, staje się NULL, a raport ją liczy.
Wpis w raporcie: date_out_of_range
json (SQL Server 2025)
CLOB
Te same wartości JSON, które odczytują funkcje JSON w Oracle.
uniqueidentifier
VARCHAR2(36)
Te same identyfikatory, zapisane małymi literami.
binary, varbinary, image
RAW(n) i BLOB
Bajty pozostają bajtami.
geometry, geography
BLOB z własnymi bajtami SQL Server
SSMS zapisuje wartości przestrzenne w serializacji SQL Server, zachowywanej bajt po bajcie.
Wpis w raporcie: spatial_as_native
rowversion, timestamp
BLOB, pusty
SQL Server sam ustawia wersję wiersza, a SSMS nie zapisuje dla niej wartości.
Wpis w raporcie: rowversion_empty
xml, sql_variant, hierarchyid, vector
VARCHAR2 lub CLOB z tekstem każdej wartości
Oracle nie ma odpowiedniego typu; xml i sql_variant zachowują tekst każdej wartości, a hierarchyid swoją ścieżkę, np. /1/2/.
Wpis w raporcie: type_replaced
collations that ignore case (_CI_)
dokładne porównanie
Oracle porównuje tekst dokładnie, chyba że ustawisz inaczej, więc kolumny, które w SQL Server ignorowały wielkość liter, teraz odróżniają Ana od ana.
Wpis w raporcie: case_insensitive_collation
IDENTITY
GENERATED BY DEFAULT ON NULL AS IDENTITY, kontynuowane po najwyższym id
Skopiowane id ładują się bez zmian, a licznik idzie dalej po najwyższym.
CREATE SEQUENCE
CREATE SEQUENCE z tymi samymi opcjami
Sekwencje w Oracle działają tak samo. SSMS nie zapisuje, dokąd doszła sekwencja, więc zaczyna ona od wartości, od której została utworzona.
computed columns
kolumny wirtualne
Oracle oblicza kolumny generowane tylko przy odczycie; kolumny PERSISTED stają się wirtualne z tymi samymi wartościami.
Wpis w raporcie: stored_as_virtual
computed columns with functions Oracle lacks
zwykła kolumna
Formuła, której nie da się zapisać, zostawia zwykłą kolumnę i wpis w raporcie; SSMS nie zapisuje wartości kolumn obliczanych.
Wpis w raporcie: generated_not_translated
defaults with functions Oracle lacks, and NEXT VALUE FOR
brak wartości domyślnej
Wartość domyślna, której nie da się zapisać, jest pomijana i zgłaszana w raporcie.
Wpis w raporcie: default_not_translated
CHECK constraints
przetłumaczone
Te same ograniczenia CHECK, sprawdzane przy ładowaniu każdego wiersza.
CHECK constraints with functions Oracle lacks
nie jest tworzone
Ograniczenie CHECK, którego nie da się zapisać, jest pomijane i zgłaszane w raporcie.
Wpis w raporcie: check_skipped
CHECK constraints added WITH NOCHECK or disabled
nie jest tworzone
SQL Server nie stosuje tych ograniczeń CHECK, więc wiersze mogą je łamać.
Wpis w raporcie: check_not_enforced
filtered and columnstore indexes, and indexes on CLOB columns
nie jest tworzone
IntoSQL zapisuje indeksy b-tree na całych kolumnach; pozostałe utwórz ponownie po załadowaniu.
Wpis w raporcie: index_skipped
foreign keys
po danych z ENABLE NOVALIDATE, potem walidowany z ostrzeżeniem o osieroconych wierszach
Klucz od razu sprawdza nowe wiersze i jest walidowany na końcu; wiersze bez rodzica zostawiają go niezwalidowanym 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
names over 128 bytes
skrócone
Nazwy w Oracle 12.2 i nowszym mają do 128 bajtów; w SQL Server do 128 znaków.
Wpis w raporcie: name_shortened
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
tables on a partition scheme
jedna tabela z wierszami wszystkich partycji
Wiersze są te same; jeśli trzeba, podziel tabelę na partycje ponownie w Oracle.
Wpis w raporcie: partitions_dropped
temporal tables (SYSTEM_VERSIONING)
dwie tabele: bieżące wiersze i historia
Tabela i jej tabela historii są kopiowane jako zwykłe tabele; Oracle nie przechowuje historii sam.
Wpis w raporcie: system_versioning_dropped
schemas
jeden schemat, nazwa każdej tabeli zaczyna się od nazwy jej schematu
Skrypt ładuje się do schematu użytkownika, który go uruchamia, więc nazwy tabel z różnych schematów zaczynają się od nazwy schematu; tabele z dbo zachowują nazwy.
Wpis w raporcie: schemas_merged
NOT NULL columns with values that become NULL
NOT NULL usunięte
Kolumna, której wartości musiały stać się NULL, nie może zachować NOT NULL, bo ładowanie by się zatrzymało.
Wpis w raporcie: not_null_relaxed
views, functions, procedures, triggers, synonyms, types and partition functions
wymienione w raporcie
Ich kod jest napisany w T-SQL, więc trafiają na listę do ręcznego odtworzenia.
Wpis w raporcie: not_converted_objects
scripts without CREATE TABLE (data only)
typy odczytane z wartości
Skrypt samych danych zawiera tylko wiersze, więc typy pochodzą z wartości.
Wpis w raporcie: no_schema
expressions in INSERT values
NULL
Konwerter, który nie uruchamia bazy danych, nie może ich obliczyć.
Wpis w raporcie: expression_value
types IntoSQL doesn't know
CLOB
Tekst mieści każdą wartość; zmień typ po załadowaniu.
Wpis w raporcie: unknown_type
NUL characters in text
zachowane
VARCHAR2 i CLOB mogą zawierać znak NUL, więc wartość jest kopiowana bez zmian.
text that isn't valid in its encoding
błędne bajty jako znak zastępczy
Skrypt jest w UTF-8 i każda wartość musi być poprawnym tekstem.
Wpis w raporcie: invalid_utf8_replaced
text decoded twice (ñ)
skopiowane bez zmian
Skrypt zawiera dokładnie te znaki, więc są kopiowane; raport je wskazuje.
Wpis w raporcie: mojibake_suspected
| W SQL Server | W Oracle | Wpis w raporcie |
|---|---|---|
| bit | NUMBER(1) z CHECK 0 i 1Oracle 21c nie ma typu kolumny logicznej; 1 i 0 zachowują wartości w każdej wersji. | |
| char(n), varchar(n), nchar(n), nvarchar(n) | VARCHAR2(n CHAR), liczony w znakachDługości liczą znaki, tak jak nvarchar w SQL Server. | |
| varchar(max), nvarchar(max), text, ntext | VARCHAR2(4000 CHAR), gdy każda wartość mieści się w 4000 bajtach, 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 |
| empty strings and empty binary values | NULLOracle zapisuje pusty ciąg jako NULL, więc wartość ' jest odczytywana jako NULL. Raport liczy je w każdej kolumnie. | empty_string_null |
| decimal(p,s), money, smallmoney | NUMBER(p,s); money jako NUMBER(19,4)NUMBER mieści 38 cyfr, tak jak decimal, więc każda wartość jest dokładna. | |
| datetime, datetime2, smalldatetime | TIMESTAMP(p)datetime to wskazanie zegara, jak TIMESTAMP w Oracle, który zachowuje do dziewięciu cyfr ułamka sekundy. date staje się DATE, który zawiera też godzinę, ustawioną na północ. | |
| datetimeoffset | TIMESTAMP WITH TIME ZONE z przesunięciem każdej wartościOracle przechowuje przesunięcia od -12:00 do +14:00; wartość z przesunięciem poza -12:00 jest zapisywana w UTC, ten sam moment. | |
| time | INTERVAL DAY TO SECOND od północyOracle nie ma typu godziny dnia; interwał od północy mieści każdą wartość. | |
| dates that aren't valid | NULLWartość, która nie jest datą, staje się NULL, a raport ją liczy. | date_out_of_range |
| json (SQL Server 2025) | CLOBTe same wartości JSON, które odczytują funkcje JSON w Oracle. | |
| uniqueidentifier | VARCHAR2(36)Te same identyfikatory, zapisane małymi literami. | |
| binary, varbinary, image | RAW(n) i BLOBBajty pozostają bajtami. | |
| geometry, geography | BLOB z własnymi bajtami SQL ServerSSMS zapisuje wartości przestrzenne w serializacji SQL Server, zachowywanej bajt po bajcie. | spatial_as_native |
| rowversion, timestamp | BLOB, pustySQL Server sam ustawia wersję wiersza, a SSMS nie zapisuje dla niej wartości. | rowversion_empty |
| xml, sql_variant, hierarchyid, vector | VARCHAR2 lub CLOB z tekstem każdej wartościOracle nie ma odpowiedniego typu; xml i sql_variant zachowują tekst każdej wartości, a hierarchyid swoją ścieżkę, np. /1/2/. | type_replaced |
| collations that ignore case (_CI_) | dokładne porównanieOracle porównuje tekst dokładnie, chyba że ustawisz inaczej, więc kolumny, które w SQL Server ignorowały wielkość liter, teraz odróżniają Ana od ana. | case_insensitive_collation |
| IDENTITY | GENERATED BY DEFAULT ON NULL AS IDENTITY, kontynuowane po najwyższym idSkopiowane id ładują się bez zmian, a licznik idzie dalej po najwyższym. | |
| CREATE SEQUENCE | CREATE SEQUENCE z tymi samymi opcjamiSekwencje w Oracle działają tak samo. SSMS nie zapisuje, dokąd doszła sekwencja, więc zaczyna ona od wartości, od której została utworzona. | |
| computed columns | kolumny wirtualneOracle oblicza kolumny generowane tylko przy odczycie; kolumny PERSISTED stają się wirtualne z tymi samymi wartościami. | stored_as_virtual |
| computed columns with functions Oracle lacks | zwykła kolumnaFormuła, której nie da się zapisać, zostawia zwykłą kolumnę i wpis w raporcie; SSMS nie zapisuje wartości kolumn obliczanych. | generated_not_translated |
| defaults with functions Oracle lacks, and NEXT VALUE FOR | brak wartości domyślnejWartość domyślna, której nie da się zapisać, jest pomijana i zgłaszana w raporcie. | default_not_translated |
| CHECK constraints | przetłumaczoneTe same ograniczenia CHECK, sprawdzane przy ładowaniu każdego wiersza. | |
| CHECK constraints with functions Oracle lacks | nie jest tworzoneOgraniczenie CHECK, którego nie da się zapisać, jest pomijane i zgłaszane w raporcie. | check_skipped |
| CHECK constraints added WITH NOCHECK or disabled | nie jest tworzoneSQL Server nie stosuje tych ograniczeń CHECK, więc wiersze mogą je łamać. | check_not_enforced |
| filtered and columnstore indexes, and indexes on CLOB columns | nie jest tworzoneIntoSQL zapisuje indeksy b-tree na całych kolumnach; pozostałe utwórz ponownie po załadowaniu. | index_skipped |
| foreign keys | po danych z ENABLE NOVALIDATE, potem walidowany z ostrzeżeniem o osieroconych wierszachKlucz od razu sprawdza nowe wiersze i jest walidowany na końcu; wiersze bez rodzica zostawiają go niezwalidowanym z ostrzeżeniem, zamiast zatrzymać ładowanie. | |
| ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT | usunięteKlucze obce w Oracle działają tylko przy usuwaniu, z CASCADE lub SET NULL. | foreign_key_action_unsupported |
| names over 128 bytes | skróconeNazwy w Oracle 12.2 i nowszym mają do 128 bajtów; w SQL Server do 128 znaków. | name_shortened |
| foreign keys to tables the dump doesn't create | nie jest tworzoneKlucz nie może wskazywać tabeli, której nie ma. | foreign_key_skipped |
| tables on a partition scheme | jedna tabela z wierszami wszystkich partycjiWiersze są te same; jeśli trzeba, podziel tabelę na partycje ponownie w Oracle. | partitions_dropped |
| temporal tables (SYSTEM_VERSIONING) | dwie tabele: bieżące wiersze i historiaTabela i jej tabela historii są kopiowane jako zwykłe tabele; Oracle nie przechowuje historii sam. | system_versioning_dropped |
| schemas | jeden schemat, nazwa każdej tabeli zaczyna się od nazwy jej schematuSkrypt ładuje się do schematu użytkownika, który go uruchamia, więc nazwy tabel z różnych schematów zaczynają się od nazwy schematu; tabele z dbo zachowują nazwy. | schemas_merged |
| NOT NULL columns with values that become NULL | NOT NULL usunięteKolumna, której wartości musiały stać się NULL, nie może zachować NOT NULL, bo ładowanie by się zatrzymało. | not_null_relaxed |
| views, functions, procedures, triggers, synonyms, types and partition functions | wymienione w raporcieIch kod jest napisany w T-SQL, więc trafiają na listę do ręcznego odtworzenia. | not_converted_objects |
| scripts without CREATE TABLE (data only) | typy odczytane z wartościSkrypt samych danych zawiera tylko wiersze, więc typy pochodzą z wartości. | no_schema |
| expressions in INSERT values | NULLKonwerter, który nie uruchamia bazy danych, nie może ich obliczyć. | expression_value |
| types IntoSQL doesn't know | CLOBTekst mieści każdą wartość; zmień typ po załadowaniu. | unknown_type |
| NUL characters in text | zachowaneVARCHAR2 i CLOB mogą zawierać znak NUL, więc wartość jest kopiowana bez zmian. | |
| text that isn't valid in its encoding | błędne bajty jako znak zastępczySkrypt jest w UTF-8 i każda wartość musi być poprawnym tekstem. | invalid_utf8_replaced |
| text decoded twice (ñ) | skopiowane bez zmianSkrypt 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 @sql_server.oracle.sqlKlucze 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 SQL Server dla najlepszego wyniku
Konwerter odczytuje to, co zawiera zrzut. Te opcje zachowują w nim więcej twoich danych:
- W SSMS kliknij prawym przyciskiem bazę danych, Tasks, Generate Scripts i wybierz tabele. dbatools, mssql-scripter i inne narzędzia oparte na tej samej bibliotece zapisują taki sam skrypt.
- W sekcji Advanced ustaw Types of data to script na Schema and data. Skrypt samego schematu ma tabele bez wierszy.
- Zapisz go jako Unicode, domyślnie w SSMS, lub jako UTF-8: oba są czytane tak samo, a gzip też działa.
Co nie jest konwertowane
Widoki, funkcje, procedury, wyzwalacze, synonimy, reguły i polityki bezpieczeństwa są pisane w T-SQL. Raport wymienia je z nazwy i nigdy nie pomija ich po cichu, więc możesz je przepisać dla Oracle.
Pytania o konwersję SQL Server 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 odczytuje plik UTF-16 zapisany przez SSMS?
Tak. SSMS domyślnie zapisuje skrypty jako UTF-16, a konwerter czyta UTF-16 i UTF-8 tak samo, spakowane gzip lub nie, z GO między partiami.
Z jakich wersji SQL Server może pochodzić skrypt?
Skrypty zapisane przez SSMS, dbatools lub mssql-scripter z SQL Server od wersji 2017. Każdy testowy skrypt pochodzi z SQL Server 2017, 2022 i 2025 i jest porównywany ze źródłem komórka po komórce.
Czy wartości IDENTITY są zachowywane?
Tak. Kolumny IDENTITY stają się kolumnami identity, każdy wiersz zachowuje swoje id, a kolejne id idzie po najwyższym. Sekwencje są tworzone z tymi samymi opcjami.
Co dzieje się z money, datetimeoffset i innymi typami SQL Server?
bit staje się NUMBER(1), datetime2 TIMESTAMP ze wszystkimi cyframi, datetimeoffset TIMESTAMP WITH TIME ZONE z przesunięciem, a nvarchar(max) CLOB, gdy wartości nie mieszczą się w VARCHAR2. Puste ciągi stają się NULL, bo tak przechowuje je Oracle, a raport je liczy.
A procedury, wyzwalacze i widoki?
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 skrypt ładuje się na 21c i 23ai i zatrzymuje przy pierwszym błędzie, jeśli coś pójdzie nie tak.