Converta MySQL para Oracle
Solte um dump do mysqldump, mariadb-dump, mysqlpump, phpMyAdmin ou Adminer, em .sql ou .sql.gz, e baixe um script do Oracle com as mesmas tabelas, chaves, índices e dados. Cada valor que o Oracle não aceita como está, e cada objeto que ele não traz, aparece no relatório.
18 linhas convertidas, 4 correções, nenhuma rejeitada
Tabelas em shop_2024.sqlDump do MySQL 8.0.46 · gerado por mysqldump · utf8mb4
customersescrita como CUSTOMERS8 linhas2
7 colunas ID NUMBER(10) not null NAME VARCHAR2(100 CHAR) not null EMAIL VARCHAR2(150 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 ordersescrita como ORDERS10 linhas2
9 colunas ID NUMBER(10) not null CUSTOMER_ID NUMBER(10) not null STATUS VARCHAR2(9 CHAR) TOTAL NUMBER(10,2) not null ITEMS NUMBER(5) not null ORDERED_AT TIMESTAMP(0) not null SHIPPED_AT TIMESTAMP(0) NOTE VARCHAR2(255 CHAR) UPDATED_AT TIMESTAMP(0) WITH TIME ZONE not null
-- Written by IntoSQL from a MySQL 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(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1001),
"NAME" VARCHAR2(100 CHAR) NOT NULL,
"EMAIL" VARCHAR2(150 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,
CONSTRAINT "CK_CUSTOMERS_ID" CHECK ("ID" >= 0),
CONSTRAINT "CK_CUSTOMERS_IS_ACTIVE" CHECK ("IS_ACTIVE" IN (0, 1))
);
CREATE TABLE "ORDERS" (
"ID" NUMBER(10) GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 5001),
"CUSTOMER_ID" NUMBER(10) NOT NULL,
"STATUS" VARCHAR2(9 CHAR) DEFAULT 'pending',
"TOTAL" NUMBER(10,2) NOT NULL,
"ITEMS" NUMBER(5) DEFAULT 1 NOT NULL,
"ORDERED_AT" TIMESTAMP(0) NOT NULL,
"SHIPPED_AT" TIMESTAMP(0),
"NOTE" VARCHAR2(255 CHAR),
"UPDATED_AT" TIMESTAMP(0) WITH TIME ZONE DEFAULT SYSTIMESTAMP NOT NULL,
CONSTRAINT "CK_ORDERS_ID" CHECK ("ID" >= 0),
CONSTRAINT "CK_ORDERS_CUSTOMER_ID" CHECK ("CUSTOMER_ID" >= 0),
CONSTRAINT "CK_ORDERS_STATUS" CHECK ("STATUS" IN ('pending', 'paid', 'shipped', 'cancelled')),
CONSTRAINT "CK_ORDERS_ITEMS" CHECK ("ITEMS" >= 0)
);
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 +00:00'
);
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 +00:00'
);
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 +00:00'
);
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 +00:00'
);
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 +00:00'
);
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 +00:00'
);
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 +00:00'
);
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 +00:00'
);
COMMIT;
END;
/
BEGIN
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
1,
1,
'shipped',
129.90,
3,
TIMESTAMP '2024-03-01 10:00:00',
TIMESTAMP '2024-03-02 16:30:00',
NULL,
TIMESTAMP '2024-03-02 16:30:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
2,
2,
'paid',
54.00,
1,
TIMESTAMP '2024-03-02 11:15:00',
NULL,
'Gift wrap 🎁',
TIMESTAMP '2024-03-02 11:20:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
3,
1,
'cancelled',
12.50,
1,
TIMESTAMP '2024-03-03 09:45:00',
NULL,
'Customer changed their mind',
TIMESTAMP '2024-03-03 10:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
4,
4,
'shipped',
980.00,
12,
TIMESTAMP '2024-03-05 02:10:00',
TIMESTAMP '2024-03-07 08:00:00',
'请小心轻放',
TIMESTAMP '2024-03-07 08:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
5,
5,
'pending',
45.75,
2,
TIMESTAMP '2024-03-08 17:20:00',
NULL,
'Leave at the door; ring twice',
TIMESTAMP '2024-03-08 17:20:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
6,
6,
'shipped',
310.40,
5,
TIMESTAMP '2024-03-10 13:00:00',
TIMESTAMP '2024-03-11 09:00:00',
'Fragile: "glass"',
TIMESTAMP '2024-03-11 09:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
7,
8,
'paid',
76.20,
2,
TIMESTAMP '2024-03-11 18:45:00',
NULL,
NULL,
TIMESTAMP '2024-03-11 18:46:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
8,
2,
NULL,
19.99,
1,
TIMESTAMP '2024-03-12 08:00:00',
NULL,
'Status lost in an old import',
TIMESTAMP '2024-03-12 08:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
9,
3,
'shipped',
64.00,
2,
TIMESTAMP '2024-03-14 15:30:00',
NULL,
'Shipping date never recorded',
TIMESTAMP '2024-03-15 10:00:00 +00:00'
);
INSERT INTO "ORDERS" (
"ID",
"CUSTOMER_ID",
"STATUS",
"TOTAL",
"ITEMS",
"ORDERED_AT",
"SHIPPED_AT",
"NOTE",
"UPDATED_AT"
) VALUES (
10,
7,
'paid',
1499.00,
1,
TIMESTAMP '2024-03-15 21:05:00',
NULL,
'C:\Users\ravi\invoice.pdf',
TIMESTAMP '2024-03-15 21:05:00 +00:00'
);
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_UQ_EMAIL" UNIQUE ("EMAIL");
ALTER TABLE "ORDERS" ADD CONSTRAINT "PK_ORDERS" PRIMARY KEY ("ID");
CREATE INDEX "IX_ORDERS_IDX_CUSTOMER" ON "ORDERS" ("CUSTOMER_ID");
CREATE INDEX "IX_ORDERS_IDX_STATUS_DATE" ON "ORDERS" ("STATUS", "ORDERED_AT");
ALTER TABLE "ORDERS" ADD CONSTRAINT "FK_ORDERS_CUSTOMER" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "CUSTOMERS" ("ID") ENABLE NOVALIDATE;
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" ENABLE VALIDATE CONSTRAINT "FK_ORDERS_CUSTOMER"';
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Foreign key ' || '"FK_ORDERS_CUSTOMER"' || ' 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 < 1001 THEN
next_id := 1001;
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 < 5001 THEN
next_id := 5001;
END IF;
EXECUTE IMMEDIATE 'ALTER TABLE "ORDERS" MODIFY ("ID" GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH ' || next_id || '))';
END;
/
CREATE OR REPLACE TRIGGER "TR_ORDERS_UPDATED_AT" BEFORE UPDATE ON "ORDERS" FOR EACH ROW
BEGIN
IF NOT UPDATING('UPDATED_AT') THEN
:NEW."UPDATED_AT" := SYSTIMESTAMP;
END IF;
END;
/
DROP FUNCTION "INTOSQL_CLOB";
DROP FUNCTION "INTOSQL_BLOB";
COMMIT;
EXIT;
Correções
- "signed_up" de customers agora aceita NULL: alguns dos seus valores não puderam ser guardados e são NULL.
- O valor padrão de "signed_up" em customers, 0000‑00‑00, não é uma data que o Oracle aceite, então a coluna fica sem valor padrão.
- "status" de orders agora aceita NULL: alguns dos seus valores não puderam ser guardados e são NULL.
- "updated_at" de orders muda para a hora atual a cada atualização; no Oracle, um gatilho faz isso.
Para revisar
- 1 valor em "signed_up" de customers é uma data zero ou impossível, como 0000‑00‑00, que o Oracle não consegue guardar, então ficou NULL. Se essas datas têm significado, troque-as na origem por datas reais antes do dump.
- 1 valor em "shipped_at" de orders é uma data zero ou impossível, como 0000‑00‑00 00:00:00, que o Oracle não consegue guardar, então ficou NULL. Se essas datas têm significado, troque-as na origem por datas reais antes do dump.
- Em "status" de orders, 1 valor vazio virou NULL; o Oracle guarda string vazia como NULL. Onde as consultas comparam esta coluna com ', compare com IS NULL.
Seu arquivo é convertido neste computador e nunca é enviado.
Outros exemplos:
O que muda do MySQL para o Oracle
Cada linha é uma regra que o conversor aplica, com a linha do relatório que ele escreve quando a regra muda algo nos seus dados.
TINYINT(1), BOOL
NUMBER(1) com um CHECK de 0 e 1 quando todo valor é 0 ou 1, senão NUMBER(3)
O BOOL do MySQL é um TINYINT(1) que aceita qualquer número de -128 a 127. O Oracle antes do 23ai não tem coluna booleana, então uma coluna de 0 e 1 vira NUMBER(1) com um CHECK; uma que contém 2 ou -1 mantém seus números.
Linha do relatório: bool_kept_numeric
UNSIGNED integers
NUMBER largo o bastante para o intervalo, com um CHECK de que não é negativo
O NUMBER do Oracle comporta qualquer inteiro das larguras que o MySQL tem; o CHECK impede valores negativos, como o MySQL fazia.
ZEROFILL and display widths
descartado
O preenchimento com zeros é uma forma de exibir um número, não parte dele. Os números são mantidos; formate-os na leitura se o preenchimento for importante.
Linha do relatório: zerofill_dropped
FLOAT(M,D)
BINARY_FLOAT ou BINARY_DOUBLE, sem a escala
Os floats binários do Oracle não têm escala fixa. Os valores guardados são copiados como estão.
Linha do relatório: float_scale_dropped
DECIMAL(p,s)
NUMBER(p,s) até 38 dígitos; VARCHAR2 acima disso
O NUMBER do Oracle comporta 38 dígitos. Decimais mais largos ficam como texto, para que cada dígito continue exato.
Linha do relatório: decimal_as_text
BIT(1), BIT(n)
NUMBER(1), NUMBER(19) até 63 bits, NUMBER(20) para BIT(64)
Os campos de bits são guardados como o número que seus bits formam.
zero, partial or impossible dates (0000-00-00, 2024-02-30)
NULL
O Oracle só guarda datas reais do calendário. O MySQL mantém datas zero e impossíveis quando o modo SQL permite; elas viram NULL e o relatório as conta.
Linha do relatório: invalid_date_null
NOT NULL columns with values that become NULL
NOT NULL removido
Uma coluna cujos valores tiveram de virar NULL, incluindo strings vazias, não pode manter NOT NULL, senão a carga pararia.
Linha do relatório: not_null_relaxed
empty strings and empty binary values
NULL
O Oracle guarda uma string vazia como NULL, então um valor que era ' é lido como NULL. O relatório as conta por coluna.
Linha do relatório: empty_string_null
DEFAULT '0000-00-00'
sem valor padrão
Um valor padrão que o Oracle não consegue guardar fica de fora em vez de ser trocado por uma data inventada.
Linha do relatório: zero_date_default
TIME
INTERVAL DAY TO SECOND, que comporta durações
O Oracle não tem tipo de hora do dia, e o TIME do MySQL é uma duração de -838:59:59 a 838:59:59; um intervalo comporta todo valor.
YEAR
NUMBER(4) com um CHECK do intervalo
O Oracle não tem tipo de ano; o CHECK mantém os mesmos valores que o MySQL permite.
CHAR(n), VARCHAR(n)
VARCHAR2(n CHAR), contando caracteres
Os tamanhos contam caracteres como os do MySQL, e o MySQL retorna valores CHAR sem espaços finais, como o VARCHAR2 os mantém.
VARCHAR(n) and TEXT longer than 4000 bytes
CLOB
Um VARCHAR2 comporta 4000 bytes por padrão, então um texto mais longo vira CLOB; uma coluna cujos valores cabem todos continua VARCHAR2.
Linha do relatório: text_as_lob
DATETIME
TIMESTAMP
Um DATETIME é a leitura de um relógio de parede sem fuso horário, como o TIMESTAMP. DATE vira o DATE do Oracle, que também guarda uma hora do dia, que fica em meia-noite.
TIMESTAMP
TIMESTAMP WITH TIME ZONE no fuso que o dump informa, UTC quando ele não informa nenhum
Um TIMESTAMP é um instante. Os dumps informam o fuso em que foram escritos (o mysqldump escreve em UTC); sem isso, os valores são lidos como UTC e o relatório avisa.
Linha do relatório: timestamp_zone_assumed
ENUM
VARCHAR2 com um CHECK dos valores
Texto com CHECK mantém os mesmos valores.
ENUM holding '' (MySQL's error value)
NULL
O MySQL guarda uma string vazia quando um valor inválido entra em um ENUM em um modo SQL permissivo. O Oracle a guarda como NULL, que o CHECK permite, e o relatório a conta com os outros valores vazios.
ENUM holding values outside its list
sem CHECK
Valores que a lista não nomeia falhariam no CHECK, então o CHECK não é criado.
Linha do relatório: enum_check_skipped
SET
VARCHAR2 como o MySQL escreve ('a,b')
O Oracle não tem tipo de conjunto; o texto é o que o MySQL retorna.
JSON
CLOB
As funções JSON do Oracle leem JSON a partir de texto em todas as versões, e um CLOB guarda valores de qualquer tamanho.
NUL bytes in text
mantido
VARCHAR2 e CLOB aceitam o caractere NUL, então o valor é copiado como está.
text that isn't valid in its character set
os bytes inválidos como o caractere de substituição
O texto precisa ser lido como caracteres para ser escrito como VARCHAR2.
Linha do relatório: invalid_utf8_replaced
text decoded twice (ñ)
copiado como está
O dump contém exatamente esses caracteres, então eles são copiados; o relatório os aponta.
Linha do relatório: mojibake_suspected
AUTO_INCREMENT
GENERATED BY DEFAULT ON NULL AS IDENTITY, reiniciado depois dos ids copiados
Os ids copiados carregam como estão, e o contador continua depois do maior deles ou do AUTO_INCREMENT do dump, o que for maior.
MyISAM AUTO_INCREMENT on the second column of a key
um contador para a tabela
O MyISAM conta por grupo da primeira coluna da chave; o Oracle tem um contador por tabela.
Linha do relatório: myisam_group_autoincrement
ON UPDATE CURRENT_TIMESTAMP
um gatilho BEFORE UPDATE
O gatilho define a coluna com a hora atual quando uma atualização não a define.
Linha do relatório: on_update_trigger
generated columns
colunas virtuais
O Oracle só calcula colunas geradas na leitura; colunas STORED viram virtuais com os mesmos valores.
Linha do relatório: stored_as_virtual
generated columns with functions Oracle lacks
uma coluna simples
Uma fórmula que não pode ser escrita para o Oracle deixa uma coluna simples e uma linha no relatório.
Linha do relatório: generated_not_translated
INVISIBLE columns
colunas INVISIBLE
O Oracle esconde colunas invisíveis do SELECT *, como o MySQL faz.
CHECK constraints
traduzido, dentro do CREATE TABLE
Os CHECKs são testados à medida que cada linha carrega.
CHECK constraints with functions Oracle lacks
não criado
Um CHECK que não pode ser escrito para o Oracle fica de fora e é informado no relatório.
Linha do relatório: check_skipped
CHECK ... NOT ENFORCED
não criado
O MySQL mantém esses CHECKs sem aplicá-los, então as linhas podem violá-los.
Linha do relatório: check_not_enforced
defaults with functions Oracle lacks
sem valor padrão
Um valor padrão que não pode ser escrito para o Oracle fica de fora e é informado no relatório.
Linha do relatório: default_not_translated
keys and indexes on a prefix, c(20)
um índice sobre SUBSTR da coluna
Um índice de função sobre o mesmo início da coluna mantém as mesmas linhas distintas e indexa colunas CLOB que o Oracle não indexa inteiras.
Linha do relatório: prefix_unique
FULLTEXT indexes
não criado
O Oracle Text faz busca de texto completo com seu próprio tipo de índice e consultas.
Linha do relatório: fulltext_not_created
SPATIAL indexes
não criado
As geometrias são guardadas como bytes WKB, que um índice espacial não consegue ler.
Linha do relatório: spatial_index_not_created
functional indexes, and indexes on whole CLOB or BLOB columns
não criado
O Oracle não indexa um objeto grande inteiro, e algumas funções do MySQL não têm equivalente no Oracle.
Linha do relatório: index_skipped
foreign keys
depois dos dados ENABLE NOVALIDATE, e então validada com um aviso sobre órfãos
Os dumps são carregados com FOREIGN_KEY_CHECKS=0 e o MyISAM nunca verifica, então linhas sem pai são comuns. A chave verifica as linhas novas na hora e é validada por último; órfãos a deixam sem validação com um aviso, em vez de parar a carga.
ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT
descartado
As chaves estrangeiras do Oracle só agem na exclusão, com CASCADE ou SET NULL.
Linha do relatório: foreign_key_action_unsupported
foreign keys to columns without a unique key
não criada
O Oracle exige uma chave primária ou uma restrição única nas colunas referenciadas; o InnoDB não.
Linha do relatório: foreign_key_skipped
table and column names
em maiúsculas quando são nomes simples, senão como escritos
O Oracle guarda em maiúsculas os nomes escritos sem aspas, então nomes simples viram maiúsculas e as consultas podem omitir as aspas; os outros nomes mantêm suas maiúsculas e minúsculas e precisam de aspas.
Linha do relatório: identifier_renamed
names over 128 bytes
encurtado
Os nomes do Oracle 12.2 e posteriores têm até 128 bytes.
Linha do relatório: name_shortened
GEOMETRY, POINT, POLYGON...
BLOB com WKB
WKB é o formato padrão que toda biblioteca espacial lê; SDO_GEOMETRY precisa dos metadados do Oracle Spatial.
Linha do relatório: geometry_as_blob
INET4, INET6, UUID (MariaDB)
VARCHAR2(39), VARCHAR2(36)
O Oracle não tem nenhum dos dois tipos; o texto é o que o MariaDB retorna.
BINARY, VARBINARY, BLOB
RAW até 2000 bytes, senão BLOB
Bytes continuam sendo bytes.
PARTITION BY
uma tabela
As linhas são as mesmas; particione a tabela de novo no Oracle se precisar.
Linha do relatório: partitions_dropped
WITH SYSTEM VERSIONING (MariaDB)
uma tabela com as linhas atuais
Um dump contém só as linhas atuais.
Linha do relatório: system_versioning_dropped
MyISAM, MEMORY and other engines
uma tabela comum
O Oracle tem um único mecanismo de tabelas.
Linha do relatório: engine_dropped
views, triggers, procedures, functions and events
listados no relatório
O código deles é escrito na linguagem do MySQL, então eles são listados para você recriá-los.
Linha do relatório: not_converted_objects
dumps without CREATE TABLE
tipos deduzidos dos valores
Um dump feito com --no-create-info só tem linhas, então os tipos vêm dos valores.
Linha do relatório: no_schema
geometries in a dump without CREATE TABLE
BLOB com WKB
O formato de geometria do MySQL é reconhecido pelos valores e guardado como WKB padrão.
Linha do relatório: geometry_inferred
_ci collations
comparação exata
O Oracle compara texto de forma exata, a menos que se indique o contrário.
Linha do relatório: case_insensitive_collation
SET NAMES utf8 from utf8mb4 tables
convertido, com um aviso
O mysqldump do MySQL 5.x escreve utf8 de 3 bytes por padrão e troca cada emoji por um ponto de interrogação antes que qualquer conversor veja o arquivo.
Linha do relatório: dump_lost_four_byte_chars
dumps without SET NAMES whose text isn't UTF-8
lido como Latin-1 (Windows-1252)
O latin1 do MySQL é o Windows-1252, a codificação comum desses dumps.
Linha do relatório: charset_guessed
sjis, cp932, gbk, big5 dumps
lido como UTF-8, com um aviso
Essas codificações ainda não são decodificadas.
Linha do relatório: unsupported_charset
UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows
avaliadas
Algumas ferramentas de dump escrevem valores como essas chamadas; elas são lidas como os valores que produzem, com o WKT geográfico convertido para longitude primeiro.
other expressions in rows
NULL
Um conversor que não executa um banco de dados não consegue avaliá-las.
Linha do relatório: expression_value
DEFAULT in VALUES
o valor padrão da coluna
Um valor padrão literal é copiado para a linha.
Linha do relatório: default_keyword_filled
DEFAULT in VALUES without a literal default
NULL
Não há valor para copiar.
Linha do relatório: default_keyword_null
REPLACE and INSERT IGNORE
linhas simples
Um dump tem uma linha por chave, então as linhas são as mesmas.
Linha do relatório: replace_as_insert
types IntoSQL doesn't know
CLOB
O tipo text aceita qualquer valor; mude o tipo depois da carga.
Linha do relatório: unknown_type
values that don't fit their column
NULL
Um dump danificado ou escrito à mão pode conter valores que a coluna não aceita; eles viram NULL para que o resto carregue.
Linha do relatório: invalid_value_null
unreadable geometries
NULL
Bytes que não são uma geometria não podem ser guardados como uma.
Linha do relatório: bad_geometry
dumps of several databases
um schema, cada tabela com o nome do seu banco na frente
O script carrega no schema do usuário que o executa, então as tabelas de bancos diferentes recebem o nome do seu banco na frente.
Linha do relatório: databases_merged
CREATE SEQUENCE (MariaDB)
CREATE SEQUENCE, no valor que ela tinha alcançado
As sequências do Oracle funcionam do mesmo jeito.
VECTOR(n) (MariaDB 11.7+)
CLOB com os floats como array JSON
Só o Oracle 23ai tem tipo vector; um array JSON mantém cada float em qualquer versão.
Linha do relatório: type_replaced
| No MySQL | No Oracle | Linha do relatório |
|---|---|---|
| TINYINT(1), BOOL | NUMBER(1) com um CHECK de 0 e 1 quando todo valor é 0 ou 1, senão NUMBER(3)O BOOL do MySQL é um TINYINT(1) que aceita qualquer número de -128 a 127. O Oracle antes do 23ai não tem coluna booleana, então uma coluna de 0 e 1 vira NUMBER(1) com um CHECK; uma que contém 2 ou -1 mantém seus números. | bool_kept_numeric |
| UNSIGNED integers | NUMBER largo o bastante para o intervalo, com um CHECK de que não é negativoO NUMBER do Oracle comporta qualquer inteiro das larguras que o MySQL tem; o CHECK impede valores negativos, como o MySQL fazia. | |
| ZEROFILL and display widths | descartadoO preenchimento com zeros é uma forma de exibir um número, não parte dele. Os números são mantidos; formate-os na leitura se o preenchimento for importante. | zerofill_dropped |
| FLOAT(M,D) | BINARY_FLOAT ou BINARY_DOUBLE, sem a escalaOs floats binários do Oracle não têm escala fixa. Os valores guardados são copiados como estão. | float_scale_dropped |
| DECIMAL(p,s) | NUMBER(p,s) até 38 dígitos; VARCHAR2 acima dissoO NUMBER do Oracle comporta 38 dígitos. Decimais mais largos ficam como texto, para que cada dígito continue exato. | decimal_as_text |
| BIT(1), BIT(n) | NUMBER(1), NUMBER(19) até 63 bits, NUMBER(20) para BIT(64)Os campos de bits são guardados como o número que seus bits formam. | |
| zero, partial or impossible dates (0000-00-00, 2024-02-30) | NULLO Oracle só guarda datas reais do calendário. O MySQL mantém datas zero e impossíveis quando o modo SQL permite; elas viram NULL e o relatório as conta. | invalid_date_null |
| NOT NULL columns with values that become NULL | NOT NULL removidoUma coluna cujos valores tiveram de virar NULL, incluindo strings vazias, não pode manter NOT NULL, senão a carga pararia. | not_null_relaxed |
| empty strings and empty binary values | NULLO Oracle guarda uma string vazia como NULL, então um valor que era ' é lido como NULL. O relatório as conta por coluna. | empty_string_null |
| DEFAULT '0000-00-00' | sem valor padrãoUm valor padrão que o Oracle não consegue guardar fica de fora em vez de ser trocado por uma data inventada. | zero_date_default |
| TIME | INTERVAL DAY TO SECOND, que comporta duraçõesO Oracle não tem tipo de hora do dia, e o TIME do MySQL é uma duração de -838:59:59 a 838:59:59; um intervalo comporta todo valor. | |
| YEAR | NUMBER(4) com um CHECK do intervaloO Oracle não tem tipo de ano; o CHECK mantém os mesmos valores que o MySQL permite. | |
| CHAR(n), VARCHAR(n) | VARCHAR2(n CHAR), contando caracteresOs tamanhos contam caracteres como os do MySQL, e o MySQL retorna valores CHAR sem espaços finais, como o VARCHAR2 os mantém. | |
| VARCHAR(n) and TEXT longer than 4000 bytes | CLOBUm VARCHAR2 comporta 4000 bytes por padrão, então um texto mais longo vira CLOB; uma coluna cujos valores cabem todos continua VARCHAR2. | text_as_lob |
| DATETIME | TIMESTAMPUm DATETIME é a leitura de um relógio de parede sem fuso horário, como o TIMESTAMP. DATE vira o DATE do Oracle, que também guarda uma hora do dia, que fica em meia-noite. | |
| TIMESTAMP | TIMESTAMP WITH TIME ZONE no fuso que o dump informa, UTC quando ele não informa nenhumUm TIMESTAMP é um instante. Os dumps informam o fuso em que foram escritos (o mysqldump escreve em UTC); sem isso, os valores são lidos como UTC e o relatório avisa. | timestamp_zone_assumed |
| ENUM | VARCHAR2 com um CHECK dos valoresTexto com CHECK mantém os mesmos valores. | |
| ENUM holding '' (MySQL's error value) | NULLO MySQL guarda uma string vazia quando um valor inválido entra em um ENUM em um modo SQL permissivo. O Oracle a guarda como NULL, que o CHECK permite, e o relatório a conta com os outros valores vazios. | |
| ENUM holding values outside its list | sem CHECKValores que a lista não nomeia falhariam no CHECK, então o CHECK não é criado. | enum_check_skipped |
| SET | VARCHAR2 como o MySQL escreve ('a,b')O Oracle não tem tipo de conjunto; o texto é o que o MySQL retorna. | |
| JSON | CLOBAs funções JSON do Oracle leem JSON a partir de texto em todas as versões, e um CLOB guarda valores de qualquer tamanho. | |
| NUL bytes in text | mantidoVARCHAR2 e CLOB aceitam o caractere NUL, então o valor é copiado como está. | |
| text that isn't valid in its character set | os bytes inválidos como o caractere de substituiçãoO texto precisa ser lido como caracteres para ser escrito como VARCHAR2. | invalid_utf8_replaced |
| text decoded twice (ñ) | copiado como estáO dump contém exatamente esses caracteres, então eles são copiados; o relatório os aponta. | mojibake_suspected |
| AUTO_INCREMENT | GENERATED BY DEFAULT ON NULL AS IDENTITY, reiniciado depois dos ids copiadosOs ids copiados carregam como estão, e o contador continua depois do maior deles ou do AUTO_INCREMENT do dump, o que for maior. | |
| MyISAM AUTO_INCREMENT on the second column of a key | um contador para a tabelaO MyISAM conta por grupo da primeira coluna da chave; o Oracle tem um contador por tabela. | myisam_group_autoincrement |
| ON UPDATE CURRENT_TIMESTAMP | um gatilho BEFORE UPDATEO gatilho define a coluna com a hora atual quando uma atualização não a define. | on_update_trigger |
| generated columns | colunas virtuaisO Oracle só calcula colunas geradas na leitura; colunas STORED viram virtuais com os mesmos valores. | stored_as_virtual |
| generated columns with functions Oracle lacks | uma coluna simplesUma fórmula que não pode ser escrita para o Oracle deixa uma coluna simples e uma linha no relatório. | generated_not_translated |
| INVISIBLE columns | colunas INVISIBLEO Oracle esconde colunas invisíveis do SELECT *, como o MySQL faz. | |
| CHECK constraints | traduzido, dentro do CREATE TABLEOs CHECKs são testados à medida que cada linha carrega. | |
| CHECK constraints with functions Oracle lacks | não criadoUm CHECK que não pode ser escrito para o Oracle fica de fora e é informado no relatório. | check_skipped |
| CHECK ... NOT ENFORCED | não criadoO MySQL mantém esses CHECKs sem aplicá-los, então as linhas podem violá-los. | check_not_enforced |
| defaults with functions Oracle lacks | sem valor padrãoUm valor padrão que não pode ser escrito para o Oracle fica de fora e é informado no relatório. | default_not_translated |
| keys and indexes on a prefix, c(20) | um índice sobre SUBSTR da colunaUm índice de função sobre o mesmo início da coluna mantém as mesmas linhas distintas e indexa colunas CLOB que o Oracle não indexa inteiras. | prefix_unique |
| FULLTEXT indexes | não criadoO Oracle Text faz busca de texto completo com seu próprio tipo de índice e consultas. | fulltext_not_created |
| SPATIAL indexes | não criadoAs geometrias são guardadas como bytes WKB, que um índice espacial não consegue ler. | spatial_index_not_created |
| functional indexes, and indexes on whole CLOB or BLOB columns | não criadoO Oracle não indexa um objeto grande inteiro, e algumas funções do MySQL não têm equivalente no Oracle. | index_skipped |
| foreign keys | depois dos dados ENABLE NOVALIDATE, e então validada com um aviso sobre órfãosOs dumps são carregados com FOREIGN_KEY_CHECKS=0 e o MyISAM nunca verifica, então linhas sem pai são comuns. A chave verifica as linhas novas na hora e é validada por último; órfãos a deixam sem validação com um aviso, em vez de parar a carga. | |
| ON UPDATE CASCADE, SET NULL or SET DEFAULT; ON DELETE SET DEFAULT | descartadoAs chaves estrangeiras do Oracle só agem na exclusão, com CASCADE ou SET NULL. | foreign_key_action_unsupported |
| foreign keys to columns without a unique key | não criadaO Oracle exige uma chave primária ou uma restrição única nas colunas referenciadas; o InnoDB não. | foreign_key_skipped |
| table and column names | em maiúsculas quando são nomes simples, senão como escritosO Oracle guarda em maiúsculas os nomes escritos sem aspas, então nomes simples viram maiúsculas e as consultas podem omitir as aspas; os outros nomes mantêm suas maiúsculas e minúsculas e precisam de aspas. | identifier_renamed |
| names over 128 bytes | encurtadoOs nomes do Oracle 12.2 e posteriores têm até 128 bytes. | name_shortened |
| GEOMETRY, POINT, POLYGON... | BLOB com WKBWKB é o formato padrão que toda biblioteca espacial lê; SDO_GEOMETRY precisa dos metadados do Oracle Spatial. | geometry_as_blob |
| INET4, INET6, UUID (MariaDB) | VARCHAR2(39), VARCHAR2(36)O Oracle não tem nenhum dos dois tipos; o texto é o que o MariaDB retorna. | |
| BINARY, VARBINARY, BLOB | RAW até 2000 bytes, senão BLOBBytes continuam sendo bytes. | |
| PARTITION BY | uma tabelaAs linhas são as mesmas; particione a tabela de novo no Oracle se precisar. | partitions_dropped |
| WITH SYSTEM VERSIONING (MariaDB) | uma tabela com as linhas atuaisUm dump contém só as linhas atuais. | system_versioning_dropped |
| MyISAM, MEMORY and other engines | uma tabela comumO Oracle tem um único mecanismo de tabelas. | engine_dropped |
| views, triggers, procedures, functions and events | listados no relatórioO código deles é escrito na linguagem do MySQL, então eles são listados para você recriá-los. | not_converted_objects |
| dumps without CREATE TABLE | tipos deduzidos dos valoresUm dump feito com --no-create-info só tem linhas, então os tipos vêm dos valores. | no_schema |
| geometries in a dump without CREATE TABLE | BLOB com WKBO formato de geometria do MySQL é reconhecido pelos valores e guardado como WKB padrão. | geometry_inferred |
| _ci collations | comparação exataO Oracle compara texto de forma exata, a menos que se indique o contrário. | case_insensitive_collation |
| SET NAMES utf8 from utf8mb4 tables | convertido, com um avisoO mysqldump do MySQL 5.x escreve utf8 de 3 bytes por padrão e troca cada emoji por um ponto de interrogação antes que qualquer conversor veja o arquivo. | dump_lost_four_byte_chars |
| dumps without SET NAMES whose text isn't UTF-8 | lido como Latin-1 (Windows-1252)O latin1 do MySQL é o Windows-1252, a codificação comum desses dumps. | charset_guessed |
| sjis, cp932, gbk, big5 dumps | lido como UTF-8, com um avisoEssas codificações ainda não são decodificadas. | unsupported_charset |
| UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows | avaliadasAlgumas ferramentas de dump escrevem valores como essas chamadas; elas são lidas como os valores que produzem, com o WKT geográfico convertido para longitude primeiro. | |
| other expressions in rows | NULLUm conversor que não executa um banco de dados não consegue avaliá-las. | expression_value |
| DEFAULT in VALUES | o valor padrão da colunaUm valor padrão literal é copiado para a linha. | default_keyword_filled |
| DEFAULT in VALUES without a literal default | NULLNão há valor para copiar. | default_keyword_null |
| REPLACE and INSERT IGNORE | linhas simplesUm dump tem uma linha por chave, então as linhas são as mesmas. | replace_as_insert |
| types IntoSQL doesn't know | CLOBO tipo text aceita qualquer valor; mude o tipo depois da carga. | unknown_type |
| values that don't fit their column | NULLUm dump danificado ou escrito à mão pode conter valores que a coluna não aceita; eles viram NULL para que o resto carregue. | invalid_value_null |
| unreadable geometries | NULLBytes que não são uma geometria não podem ser guardados como uma. | bad_geometry |
| dumps of several databases | um schema, cada tabela com o nome do seu banco na frenteO script carrega no schema do usuário que o executa, então as tabelas de bancos diferentes recebem o nome do seu banco na frente. | databases_merged |
| CREATE SEQUENCE (MariaDB) | CREATE SEQUENCE, no valor que ela tinha alcançadoAs sequências do Oracle funcionam do mesmo jeito. | |
| VECTOR(n) (MariaDB 11.7+) | CLOB com os floats como array JSONSó o Oracle 23ai tem tipo vector; um array JSON mantém cada float em qualquer versão. | type_replaced |
Carregue o script no Oracle
O script cria as tabelas, copia as linhas e depois adiciona chaves, índices e chaves estrangeiras, então carrega rápido e para no primeiro erro.
NLS_LANG=.AL32UTF8 sqlplus -S -L user@//localhost/mydb @mysql.oracle.sqlAs chaves estrangeiras são adicionadas ENABLE NOVALIDATE, então as linhas novas são verificadas na hora, e depois validadas. Se uma linha antiga aponta para uma linha que não existe, o script informa qual restrição e a deixa sem validação, em vez de falhar no meio do caminho.
Para um dump grande, execute o SQL*Plus na mesma máquina do banco de dados. O script faz commit a cada 100 linhas. O usuário que o executa precisa de CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER e CREATE PROCEDURE, e de cota no seu tablespace.
Gere o dump do MySQL para o melhor resultado
O conversor lê o que o dump contém. Estas opções mantêm mais dos seus dados nele:
- --default-character-set=utf8mb4 mantém emoji e outros caracteres de 4 bytes, que um dump em utf8 perde antes de o conversor vê-lo.
- --hex-blob escreve as colunas binárias em hexadecimal, o que sobrevive à cópia entre sistemas.
- --routines --triggers --events adicionam esses objetos ao dump, para que o relatório possa listá-los.
O que não é convertido
Visões, gatilhos, procedimentos armazenados, funções e eventos são escritos na linguagem própria de cada banco de dados. Eles aparecem no relatório pelo nome, nunca são descartados em silêncio, para que você possa reescrevê-los para o Oracle.
Perguntas sobre MySQL para Oracle
Não encontrou a resposta? Escreva para nós pela página de contato e uma pessoa responde. Página de contato
Meu dump é enviado?
Não. O conversor roda no seu navegador e lê o dump do seu disco em partes, então ele nunca sai do seu computador. O app para desktop e a linha de comando também convertem no seu computador.
Qual o tamanho máximo do dump?
O conversor nunca guarda o dump inteiro na memória: ele lê o arquivo duas vezes, por intervalos, e escreve o script à medida que avança. Dumps de vários gigabytes são convertidos no navegador, no app para desktop e com a linha de comando.
Ele lê dumps do MariaDB?
Sim. Dumps do mariadb-dump e do MariaDB 10.3 ao 12 são convertidos da mesma forma, incluindo as colunas INET6, INET4 e UUID do MariaDB.
O que acontece com datas 0000-00-00?
O Oracle não tem data zero, então elas viram NULL e a coluna passa a aceitar NULL. O relatório diz quantas havia em cada coluna. Strings vazias também viram NULL, pois é assim que o Oracle as guarda.
Os valores de AUTO_INCREMENT são mantidos?
Sim. Cada coluna AUTO_INCREMENT vira uma coluna identity, cada linha mantém seu id, e o próximo id continua depois do maior, ou depois do AUTO_INCREMENT da tabela, se ele for maior.
TINYINT(1) vira boolean?
O Oracle antes do 23ai não tem coluna booleana. Uma coluna cujos valores são todos 0 ou 1 vira NUMBER(1) com um CHECK que a mantém assim; uma que contém outros números os mantém, e o relatório explica o motivo.
E os procedimentos armazenados e gatilhos?
Eles aparecem no relatório pelo nome e não são convertidos, porque cada banco de dados os escreve na sua própria linguagem. ON UPDATE CURRENT_TIMESTAMP é a exceção: vira um gatilho do Oracle.
Em quais versões do Oracle o script carrega?
Oracle 19c e posteriores. Cada dump de teste carrega no 21c e no 23ai e para no primeiro erro se algo der errado.