Como migrar usuários do Oracle para o Cloud SQL para MySQL: consultas, procedimentos armazenados, funções e gatilhos

Este documento faz parte de uma série que fornece informações importantes e orientações relacionadas a planejamento e execução de migrações de banco de dados Oracle® 11g/12c para o Cloud SQL para MySQL versão 5.7, instâncias de segunda geração. A série inclui as partes a seguir:

Consultas

O Oracle e o Cloud SQL para MySQL são compatíveis com o padrão ANSI SQL. Geralmente, é simples migrar instruções SQL usando apenas elementos de sintaxe básicos (por exemplo, não especificando funções escalares ou qualquer outro recurso estendido do Oracle). Na seção a seguir, discutimos elementos comuns de consulta do Oracle e os equivalentes correspondentes do Cloud SQL para MySQL.

Sintaxe básica de SELECT e FROM

Nome do recurso do Oracle ou nome da sintaxe Visão geral ou implementação do Oracle Compatível com MySQL Solução alternativa ou correspondente do MySQL
Sintaxe básica do SQL para recuperação de dados

SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
Sim

SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
SELECT para impressão de saída

SELECT 1 FROM DUAL
Sim

SELECT 1
OR
SELECT 1 FROM DUAL
Aliases de coluna

SELECT COL1 AS C1
Sim

SELECT COL1 AS C1
OR
SELECT COL1 C1
Diferenciação entre maiúsculas e minúsculas no nome da tabela
Nenhuma diferenciação de maiúsculas e minúsculas
(por exemplo, o nome da tabela pode ser orders e/ou ORDERS).
Não Diferencia maiúsculas de minúsculas de acordo com o nome da tabela definido (por exemplo, o nome da tabela pode ser apenas orders ou ORDERS).

Leia mais detalhes sobre a sintaxe SELECT do MySQL.

  • Visualizações in-line
    • As visualizações in-line (também conhecidas como tabelas derivadas) são instruções SELECT, localizadas na cláusula FROM e usadas como uma subconsulta.
    • As visualizações in-line podem ajudar a simplificar consultas complexas, removendo cálculos compostos ou eliminando operações de junção, ao mesmo tempo em que compilam várias consultas separadas em uma única consulta simplificada.
    • Observação de conversão: as visualizações in-line do Oracle não exigem o uso de aliases, enquanto o MySQL exige aliases específicos para cada visualização in-line.

A tabela a seguir apresenta um exemplo de conversão do Oracle para MySQL, como uma visualização in-line.

Oracle 11g/12c

SQL> SELECT FIRST_NAME,
            DEPARTMENT_ID,
            SALARY,
            DATE_COL
     FROM EMPLOYEES,
          (SELECT SYSDATE AS DATE_COL FROM DUAL);

A resposta será semelhante a:

FIRST_NAME           DEPARTMENT_ID     SALARY DATE_COL
-------------------- ------------- ---------- ---------
Steven                          90      24000 30-JUL-19
Neena                           90      17000 30-JUL-19
Lex                             90      17000 30-JUL-19
Cloud SQL para MySQL 5.7
Sem alias para a visualização in-line:

mysql> SELECT FIRST_NAME,
              DEPARTMENT_ID,
              SALARY,
              DATE_COL
       FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL);

ERROR 1248 (42000): Every derived table must have its own alias

Como adicionar um alias à visualização in-line:

mysql> SELECT FIRST_NAME,
              DEPARTMENT_ID,
              SALARY,
              DATE_COL
       FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL) AS A1;

A resposta será semelhante a:

+-------------+---------------+----------+---------------------+
| FIRST_NAME  | DEPARTMENT_ID | SALARY   | DATE_COL            |
+-------------+---------------+----------+---------------------+
| Steven      |            90 | 23996.00 | 2019-07-30 09:28:00 |
| Neena       |            90 | 22627.00 | 2019-07-30 09:28:00 |
| Lex         |            90 | 22627.00 | 2019-07-30 09:28:00 |

Instruções JOIN

As instruções JOIN do Oracle são compatíveis com as instruções JOIN do MySQL, exceto a cláusula FULL JOIN. Além disso, as instruções JOIN do MySQL aceitam o uso de sintaxe alternativa, como a cláusula USING, a cláusula WHERE em vez da cláusula ON e o uso de SUBQUERY na instrução JOIN.

Na tabela a seguir, veja um exemplo de conversão JOIN.

Tipo JOIN do Oracle Compatível com MySQL Sintaxe de JOIN do MySQL

INNER JOIN
Sim

SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;

CROSS JOIN
Sim

SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E CROSS JOIN DEPARTMENTS D

FULL JOIN
Não Para uma solução alternativa, use UNION com instruções LEFT e RIGHT JOIN.

LEFT JOIN
[ OUTER ]
Sim

SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E LEFT JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;

RIGHT JOIN
[ OUTER ]
Sim

SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E RIGHT JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;

SUBQUERY
Sim

SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E JOIN (SELECT * FROM DEPARTMENTS)D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;

UNION, UNION ALL, INTERSECT e MINUS

O MySQL não é compatível com as funções INTERSECT e MINUS do Oracle, exceto as funções UNION e UNION ALL:

  • UNION: anexa os conjuntos de resultados de duas ou mais instruções SELECT e elimina registros duplicados.
  • UNION ALL: anexa os conjuntos de resultados de duas ou mais instruções SELECT sem eliminar registros duplicados.
  • INTERSECT: retorna a interseção de duas ou mais instruções SELECT somente se houver um registro nos dois conjuntos de dados.
  • MINUS: compara duas ou mais instruções SELECT, retornando apenas linhas distintas da primeira consulta que não são retornadas pelas outras instruções.

Observações sobre a conversão

Ao converter as funções INTERSECT e MINUS do Oracle em MySQL, use as instruções JOIN e IN e EXISTS como uma solução alternativa.

Exemplos

Função Oracle Implementação do Oracle Compatível com MySQL Solução alternativa ou correspondente do MySQL

UNION

SELECT COL1 FROM TBL1
UNION
SELECT COL1 FROM TBL2
Sim

SELECT COL1 FROM TBL1
UNION
SELECT COL1 FROM TBL2

UNION ALL

SELECT COL1 FROM TBL1
UNION ALL
SELECT COL1 FROM TBL2
Sim

SELECT COL1 FROM TBL1
UNION ALL
SELECT COL1 FROM TBL2

INTERSECT

SELECT COL1 FROM TBL1
INTERSECT
SELECT COL1 FROM TBL2
Não

SELECT COL1 FROM TBL1
WHERE COL1 IN
(SELECT COL1 FROM TBL2)

MINUS

SELECT COL1 FROM TBL1
MINUS
SELECT COL1 FROM TBL2
Não

SELECT A.COL1
FROM TBL1 A LEFT JOIN TBL2 B
ON USING(COL1)
WHERE B.COL1 IS NULL

Funções escalares (de linha única) e de grupo

O MySQL fornece uma extensa lista de funções escalares (de linha única) e de agregação. Algumas das funções do MySQL são semelhantes às versões equivalentes do Oracle (por nome e funcionalidade ou com um nome diferente, mas com funcionalidade semelhante). Ainda que as funções do MySQL possam ter nomes idênticos aos equivalentes do Oracle, elas podem exibir funcionalidades diferentes.

As tabelas a seguir descrevem onde o Oracle e o MySQL são equivalentes por nome e funcionalidade (especificados por "Sim") e onde uma conversão é recomendada (todos os casos, exceto "Sim").

Funções de caracteres
Função Oracle Especificação ou implementação da função do Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função do MySQL

CONCAT(str1,str2)
Retorna str1 concatenado com str2:

CONCAT('A', 1) = A1
Sim

CONCAT
Equivalente do Oracle:

CONCAT('A', 1) = A1

LOWER/UPPER
Retorna char, com todas as letras minúsculas ou maiúsculas:

LOWER('SQL') = sql
Sim

LOWER/UPPER
Equivalente do Oracle:

LOWER('SQL') = sql

LPAD/RPAD(expr1,n,expr2)
Retorna expr1, à esquerda ou à direita preenchidos com caracteres n com a sequência de caracteres em expr2:

LPAD('A',3,'*') = **A
Sim

LPAD/RPAD
Equivalente do Oracle:

LPAD('A',3,'*') = **A

SUBSTR(char,p,n)
Retorne uma parte de char, começando na posição do caractere p, com comprimento de substring de n caracteres:

SUBSTR('MySQL', 3, 3)
= SQL
Sim

SUBSTR(char,p,n)
Equivalente do Oracle:

SUBSTR('MySQL', 3, 3)
= SQL

INSTR(index,str)
Retorna a posição (index) da string str:

INSTR('MySQL', 'y')
= 2
Sim

INSTR
Equivalente do Oracle:

INSTR('MySQL', 'y')
= 2

REPLACE(char,str1,str2)
Retorna char com cada ocorrência de uma string de pesquisa substituída por uma string de substituição:

REPLACE('ORADB', 'ORA', 'MySQL')

= MySQLDB
Sim

REPLACE(char,str1,str2)
Equivalente do Oracle:

REPLACE('ORADB', 'ORA', 'MySQL')

= MySQLDB

TRIM(str)
Corte caracteres iniciais ou finais (ou ambos) de uma string:

TRIM(both '-' FROM '-MySQL-')
= MySQL

TRIM(' MySQL ') = MySQL
Sim

TRIM(str)
Equivalente do Oracle:

TRIM(both '-' FROM '-MySQL-')
= MySQL

TRIM(' MySQL ') = MySQL

LTRIM/RTRIM(str)
Remove da extremidade esquerda ou direita da string todos os caracteres que aparecem na pesquisa:

LTRIM('   MySQL', ' ')
= MySQL
Parcialmente

LTRIM/RTRIM(str)
Função R/LTRIM do Oracle, exceto uma substituição para o parâmetro (espaço em branco ou string). O MySQL R/LTRIM só elimina espaços em branco, aceitando apenas a string de entrada:

LTRIM('   MySQL')
= MySQL

ASCII(char)
Retorna a representação decimal no conjunto de caracteres do banco de dados do primeiro caractere de char:

ASCII('A') = 65
Sim

ASCII(char)
Equivalente do Oracle:

ASCII('A') = 65

CHR(char)
Retorna o valor do código ASCII, que é um valor numérico entre 0 e 225, para um caractere:

CHR(65) = A
Parcialmente com nome de função diferente

CHAR(char)
O MySQL usa a função CHAR para a mesma funcionalidade. Portanto, você precisa modificar um nome de função:

CHAR(65) = A

LENGTH(str)
Retorna o comprimento de uma determinada string:


LENGTH ('MySQL') = 5
Sim

LENGTH(str)
Equivalente do Oracle:

LENGTH('MySQL') = 5

REGEXP_REPLACE(str1,expr,str2)
Procure um padrão de expressão regular em uma string:

REGEXP_REPLACE('John', '[hn].', '1') = Jo1
Não N/A Compatível apenas com a versão 8 do MySQL. Como solução alternativa, use a função REPLACE, se possível, ou converta para a camada do aplicativo

REGEXP_SUBSTR(str,expr)
Estende a funcionalidade da função SUBSTR pesquisando um padrão de expressão regular em uma string:

REGEXP_SUBSTR('https://console.cloud.google.com/sql/instances','https://([[:alnum:]]+\.?){3,4}/?')
= https://console.cloud.google.com/
Não N/A Compatível apenas com a versão 8 do MySQL. Para uma solução alternativa, use a função SUBSTR, se possível, ou converta a funcionalidade para a camada do aplicativo.

REGEXP_COUNT(str,expr)
Retorna o número de vezes que um padrão ocorre em uma string de origem. Não N/A Para uma solução alternativa, converta a funcionalidade para a camada do aplicativo.

REGEXP_INSTR(index,expr)
Pesquise uma posição de string (índice) para um padrão de expressão regular. Não N/A Compatível apenas com a versão 8 do MySQL.

REVERSE(str)
Retornar uma string invertida

REVERSE('MySQL')
= LQSyM
Sim

REVERSE
Equivalente do Oracle:

REVERSE('MySQL')
= LQSyM
Funções numéricas
Função Oracle Especificação ou implementação da função do Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função do MySQL

ABS(n)
Valor absoluto de n:

ABS(-4.6) = 4.6
Sim

ABS
Equivalente do Oracle:

ABS(-4.6) = 4.6

CEIL(n)
Retorna o menor número inteiro maior ou igual a n:

CEIL(21.4) = 22
Sim

CEIL
Equivalente do Oracle:

CEIL(21.4) = 22

FLOOR(n)
Retorna o maior inteiro igual ou menor que n:

FLOOR(-23.7) = -24
Sim

FLOOR
Equivalente do Oracle:

FLOOR(-23.7) = -24

MOD(m,n)
Retorna o restante de m dividido por n:

MOD(10, 3) = 1
Sim

MOD(m,n)
Equivalente do Oracle:

MOD(10,3) = 1

ROUND(m,n)
Retorna m arredondado para n casas inteiras à direita do ponto decimal:

ROUND(1.39,1) = 1.4
Sim

ROUND
Equivalente do Oracle:

ROUND(1.39,1) = 1.4

TRUNC(n1, n2)
Retorna n1 truncado para n2 casas decimais:

TRUNC(99.999) = 99
TRUNC(99.999,0) = 99
Parcialmente com nome de função diferente

TRUNCATE(n1, n2)
A função TRUNCATE do MySQL precisa aceitar um número de entrada e um número inteiro para especificar o valor de precisão à direita do ponto decimal:

TRUNCATE(99.999,0) = 99
Funções de data e hora
Função do Oracle Especificação ou implementação da função do Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função do MySQL

SYSDATE
Retorna a data e a hora atuais definidas para o sistema operacional em que o servidor de banco de dados reside:

SELECT SYSDATE
FROM DUAL
= 31-JUL-2019
Parcialmente

SYSDATE()
O SYSDATE() do MySQL precisa incluir parênteses e retornar um formato de data/hora diferente da função SYSDATE do Oracle:

SELECT SYSDATE()
FROM DUAL;
= 2019-01-31 10:01:01.0

A formatação de data/hora pode ser alterada no nível da sessão

SYSTIMESTAMP
Retorna a data do sistema, incluindo segundos fracionários e fuso horário:

SELECT SYSTIMESTAMP FROM DUAL
= 01-JAN-19 07.37.11.622187000 AM +00:00
Parcialmente com nome de função diferente

CURRENT_TIMESTAMP
O MySQL retorna uma formatação de data/hora diferente do Oracle. Uma formatação de data é necessária (ou uma função de data diferente) para corresponder à formatação de data/hora original:

SELECT CURRENT_TIMESTAMP
FROM DUAL
= 2019-01-31 06:55:07

LOCAL_TIMESTAMP
Retorna a data e a hora atuais no fuso horário da sessão em um valor do tipo de dados TIMESTAMP:

SELECT LOCAL_TIMESTAMP
FROM DUAL
= 01-JAN-19 10.01.10.123456 PM
Parcialmente com formatação de data/hora diferente.

LOCAL_TIMESTAMP
O MySQL retorna uma formatação de data/hora diferente do Oracle. A formatação de data/hora é obrigatória (ou uma função de data diferente) para corresponder à formatação de data/hora original:

SELECT LOCAL_TIMESTAMP
FROM DUAL
= 2019-01-01 10:01:01.0

CURRENT_DATE
Retorna a data atual no fuso horário da sessão:

SELECT CURRENT_DATE
FROM DUAL
= 31-JAN-19
Parcialmente com formatação de data/hora diferente

CURRENT_DATE
O MySQL retorna uma formatação de data/hora diferente do Oracle. A formatação de data/hora é obrigatória (ou uma função de data diferente) para corresponder à formatação de data/hora original:

SELECT CURRENT_DATE
FROM DUAL
= 2019-01-31

CURRENT_TIMESTAMP
Retorna a data e a hora atuais no fuso horário da sessão:

SELECT CURRENT_TIMESTAMP
FROM DUAL
= 31-JAN-19 06.54.35.543146 AM +00:00
Parcialmente com formatação de data/hora diferente

CURRENT_TIMESTAMP
O MySQL retorna uma formatação de data/hora diferente do Oracle. A formatação de data/hora é obrigatória (ou uma função de data diferente) para corresponder à formatação de data/hora original:

SELECT CURRENT_TIMESTAMP
FROM DUAL
= 2019-01-31 06:55:07

ADD_MONTHS
Retorna a data mais os meses inteiros:

ADD_MONTHS(SYSDATE, 1)
= 31-JAN-19
Parcialmente com nome de função diferente

ADDDATE
Para conseguir a mesma funcionalidade, o MySQL usa a função ADDDATE:

ADDDATE(SYSDATE(), 1)
= 2019-08-01 06:42:49.0

Por padrão, o MySQL retorna data/hora e intervalo/formato diferentes do Oracle. A formatação de data/hora é obrigatória (ou uma função de data diferente) para corresponder à formatação de data/hora original.
EXTRACT(parte da data) Retorna o valor de um campo de data/hora especificado de uma expressão de data/hora ou intervalo:

EXTRACT(YEAR FROM DATE '2019-01-31')
= 2019
Sim EXTRACT (parte da data) Equivalente do Oracle:

EXTRACT(YEAR FROM DATE '2019-01-31')
= 2019

LAST_DAY
Retorna a data do último dia do mês:

LAST_DAY('01-JAN-2019')
= 31-JAN-19
Parcialmente com formatação de data/hora diferente

LAST_DAY
O MySQL retorna uma formatação de data/hora diferente do Oracle. A formatação de data/hora é obrigatória (ou uma função de data diferente) para corresponder à formatação de data/hora original:

LAST_DAY('2019-01-01')
= 2019-01-31

MONTH_BETWEEN
Retorna o número de meses entre as datas date1 e date2:

MONTHS_BETWEEN(
SYSDATE, SYSDATE-60)
= 1.96
Parcialmente com nome de função diferente

PERIOD_DIFF(date1,date2)
A função PERIOD_DIFF do MySQL retorna a diferença em meses como um número inteiro entre dois pontos (formatados como YYMM ou YYYYMM):

PERIOD_DIFF(
'201903', '201901')
= 2

Para atingir os mesmos valores que a função MONTH_BETWEEN do Oracle, será necessária uma conversão mais específica
TO_CHAR (data/hora) Converte um tipo de dados de data/hora ou carimbo de data/hora em um valor de tipo de dados VARCHAR2 no formato especificado pelo formato de data:

TO_CHAR(
SYSDATE,'DD-MM-YYYY HH24:MI:SS')
= 01-01-2019 10:01:01
Parcialmente com nome de função diferente

DATE_FORMAT
A função DATE_FORMAT do MySQL formata uma data conforme especificado por uma definição de formato de data:

DATE_FORMAT(
SYSDATE(),'%d-%m-%Y %H:%i:%s')
= 01-01-2019 10:01:01
Funções de codificação e decodificação
Função Oracle Especificação ou implementação da função do Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função do MySQL

DECODE
Compara uma expressão com cada valor de pesquisa usando a funcionalidade de uma instrução IF-THEN-ELSE Não

CASE
Use a instrução CASE do MySQL para conseguir uma funcionalidade semelhante.

DUMP
Retorna um valor VARCHAR2 que contém o código do tipo de dados, o comprimento em bytes e a representação interna de uma determinada expressão. Não N/A Incompatível.

ORA_HASH
Calcula um valor de hash para uma determinada expressão. Não

MD5/SHA
Use o MySQL MD5 para soma de verificação de 128 bits ou a função SHA para soma de verificação de 160 bits para gerar valores de hash
Funções de conversão
Função Oracle Especificação ou implementação da função do Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função do MySQL

CAST
Converte um tipo de dados integrado ou um valor tipado por coleção em outro tipo de dados integrado ou valor tipado por coleção:

CAST('1' as int) + 1
= 2
Parcialmente

CAST
A função CAST do MySQL é semelhante à funcionalidade do Oracle, mas em alguns casos ela precisa ser ajustada, dependendo da necessidade de uma conversão explícita ou implícita:

CAST('1' AS SIGNED) + 1
= 2

CONVERT
Converte uma string de caracteres de um conjunto de caracteres em outro:

CONVERT('Ä Ê Í Õ Ø A B C D E ', 'US7ASCII', 'WE8ISO8859P1')
= ?? ?? ?? A B C
Parcialmente

CONVERT
A função CONVERT do MySQL requer alguns ajustes na sintaxe e nos parâmetros para retornar os resultados exatos como Oracle:

CONVERT('Ä Ê Í A B C ' USING utf8)
= Ä Ê Í A B C
TO_CHAR
(string/numérico)
A função converte um número ou uma data em uma string:

TO_CHAR(22.73,'$99.9')
= $22.7
Não

FORMAT
A função FORMAT do MySQL executa o formato "#, ###.##" de um número, arredondando-o para um determinado número de casas decimais e, em seguida, retorna o resultado como uma string, que tem funcionalidade diferente do Oracle:

CONCAT('$',
FORMAT(22.73, 1))
= $22.7

TO_DATE
A função TO_DATE do Oracle converte uma string em uma data pelo formato de data/hora específico da origem:

TO_DATE(
'2019/01/01', 'yyyy-mm-dd')
= 01-JAN-2019
Parcialmente com nome de função e formatação de data/hora diferente

STR_TO_DATE
A função STR_TO_DATE do MySQL usa uma string e retorna uma data especificada pela formatação de data/hora:

STR_TO_DATE(
'2019/01/01', '%Y/%m/%d')
= 2019-01-01

TO_NUMBER
Converte a expressão em um valor de um tipo de dados NUMBER:

TO_NUMBER('01234')
= 1234
Não

CAST
Como alternativa, use a função CAST do MySQL para retornar o mesmo resultado que TO_NUMBER do Oracle:

CAST('01234' as SIGNED)
= 1234
Funções SELECT condicionais
Função Oracle Especificação ou implementação da função do Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função do MySQL

CASE
A instrução CASE escolhe uma sequência de condições e executa uma instrução correspondente com a seguinte sintaxe:

CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Sim

CASE
Além da função CASE, o MySQL também é compatível com o uso condicional IF/ELSE na instrução SELECT:

CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Funções nulas
Função Oracle Especificação ou implementação da função do Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função do MySQL

COALESCE
Retorna a primeira expressão não nula na lista de expressões:

COALESCE(
null, '1', 'a')
= a
Sim

COALESCE
Equivalente do Oracle:

COALESCE(
null, '1', 'a')
= 1

NULLIF
Compare expr1 e expr2m. Se forem iguais, a função retornará nulo. Se eles não forem iguais, a função retornará expr1:

NULLIF('1', '2')
= a
Sim

NULLIF
Equivalente do Oracle:

NULLIF('1', '2')
= a

NVL
Substitua nulo (retornado em branco) por uma string nos resultados de uma consulta:

NVL(null, 'a')
= a
Não

IFNULL
A função equivalente do MySQL seria a função IFNULL , que substitui valores nulos por uma determinada string:

IFNULL(null, 'a')
= a

NVL2
Determine o valor retornado por uma consulta com base no fato de uma expressão especificada ser nula ou não.
Não

CASE
A instrução CASE escolhe uma sequência de condições e executa uma instrução correspondente:


CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Ambiente e funções de identificador
Função Oracle Especificação ou implementação da função do Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função do MySQL

SYS_GUID
Gera e retorna um identificador globalmente exclusivo (valor RAW) composto por 16 bytes:

SELECT SYS_GUID()
FROM DUAL
= 8EFA4A31468B4C6DE05011AC0200009E
Não REPLACE e UUID Para uma solução alternativa, use as funções REPLACE e UUID do MySQL para simular a função SYS_GUID do Oracle:

REPLACE(
UUID(), '-', '')

UID
Retorna um número inteiro que identifica exclusivamente o usuário da sessão (o usuário
que fez login):

SELECT UID FROM DUAL
= 43
Não N/A N/A

USER
Retorna o nome do usuário atual da sessão:

SELECT USER FROM DUAL
= UserName
Parcialmente

USER + INSTR + SUBSTR
A função USER do MySQL retorna o nome de usuário junto com o servidor de conexão (root@IP). Para recuperar apenas o nome de usuário, use outras funções de suporte:

SELECT
SUBSTR(USER(), 1, INSTR(USER(), '@') -1) FROM DUAL
= root

USERENV
Retorna informações sobre a sessão de usuário atual com a configuração de parâmetro atual:

SELECT USERENV('LANGUAGE')
FROM DUAL
= ENGLISH_AMERICA.AL32UTF8
Não

SHOW SESSION
VARIABLES
Use a instrução SHOW SESSION VARIABLES do MySQL para ver as configurações da sessão atual:


SHOW SESSION VARIABLES LIKE '%collation%';
= utf8_general_ci

ROWID
O servidor Oracle atribui a cada linha em cada tabela um ROWID exclusivo para identificar a linha na tabela. O ROWID é o endereço da linha que contém o número do objeto de dados, o bloco de dados da linha, a posição da linha e o arquivo de dados. Não N/A Se possível, tente emular a mesma funcionalidade com outras funções do MySQL.

ROWNUM
Retorna um número que representa a ordem em que uma linha é selecionada pelo Oracle em uma tabela ou em tabelas mescladas. Não N/A Se possível, tente emular a mesma funcionalidade com outras funções do MySQL ou variáveis de sessão.
Funções de agregação (grupo)
Função do Oracle Especificação ou implementação da função do Oracle
Equivalente do MySQL
Função correspondente do MySQL Especificação ou implementação da função do MySQL

AVG
Retorna o valor médio da coluna ou expressão. Sim

AVG
Equivalente do Oracle

COUNT
Retorna o número de linhas retornadas por uma consulta. Sim

COUNT
Equivalente do Oracle

COUNT
(DISTINCT)
Retorna o número de valores exclusivos na coluna ou expressão. Sim

COUNT
(DISTINCT)
Equivalente do Oracle

MAX
Retorna o valor máximo de uma coluna ou expressão. Sim

MAX
Equivalente do Oracle

MIN
Retorna o valor mínimo da coluna ou expressão. Sim

MIN
Equivalente do Oracle

SUM
Retorna a soma do valor da coluna ou expressão. Sim

SUM
Equivalente do Oracle

LISTAGG
Exibe os dados em cada grupo por uma única linha especificada na cláusula ORDER BY, concatenando os valores da coluna de medida:

SELECT LISTAGG(
DEPARTMENT_NAME, ', ')
WITHIN GROUP
(ORDER BY DEPARTMENT_NAME) DEPT
FROM DEPARTMENTS;

-- Single line results
= Accounting, Administration, Benefits, Construction
Não

GROUP_CONCAT
Use a função MySQL GROUP_CONCAT para retornar resultados semelhantes aos do Oracle. São esperadas diferenças de sintaxe com determinados casos:

SELECT GROUP_CONCAT(
DEPARTMENT_NAME ORDER BY DEPARTMENT_NAME SEPARATOR ', ') DEPT
FROM DEPARTMENTS;

-- Single line results
= Accounting, Administration, Benefits, Construction
Busca do Oracle 12c
Função do Oracle Especificação ou implementação da função do Oracle
Equivalente do MySQL
Função correspondente do MySQL Especificação ou implementação da função do MySQL

FETCH
Recupera linhas de dados do conjunto de resultados de uma consulta de várias linhas:

SELECT * FROM
EMPLOYEES
FETCH FIRST 10 ROWS ONLY;
Não LIMIT Use a cláusula LIMIT do MySQL para recuperar apenas um conjunto específico de registros:

SELECT * FROM
EMPLOYEES
LIMIT 10;

Filtragem básica, operadores e subconsultas

Durante a conversão, a filtragem básica, as funções do operador e as subconsultas são relativamente simples, exigindo pouco ou nenhum esforço.

Observações sobre a conversão

Examine e resolva os formatos de data porque os formatos Oracle e MySQL retornam resultados padrão diferentes:

  • A função SYSDATE do Oracle por padrão retorna 01-AUG-19.
  • Por padrão, a função SYSDATE() do MySQL retorna 2019-08-01 12:04:05.
  • Os formatos de data e hora podem ser definidos usando as funções [DATE_FORMAT](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format) ou [STR_TO_DATE](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_str-to-date) do MySQL.
Função ou subconsulta do Oracle Equivalente do MySQL Função ou subconsulta correspondente do MySQL Especificação ou implementação da função do MySQL

EXISTS/NOT EXISTS
Sim

EXISTS/NOT EXISTS

SELECT * FROM DEPARTMENTS D
WHERE EXISTS (SELECT 1
              FROM EMPLOYEES E
              WHERE
              E.DEPARTMENT_ID =
              D.DEPARTMENT_ID);

IN/NOT IN
Sim

IN/NOT IN

SELECT * FROM DEPARTMENTS D
WHERE DEPARTMENT_ID IN
            (SELECT DEPARTMENT_ID
             FROM EMPLOYEES E);

-- OR
SELECT * FROM EMPLOYEES WHERE (EMPLOYEE_ID, DEPARTMENT_ID) IN((100, 90));

LIKE/NOT LIKE
Sim

LIKE/NOT LIKE

SELECT * FROM EMPLOYEES
WHERE FIRST_NAME LIKE '_e_n%';

BETWEEN/NOT BETWEEN
Sim

BETWEEN/NOT BETWEEN

SELECT * FROM EMPLOYEES
WHERE EXTRACT(YEAR FROM HIRE_DATE)
NOT BETWEEN 2001 and 2004;

AND/OR
Sim

AND/OR

SELECT * FROM EMPLOYEES
WHERE DEPARTMENT_ID IN(100, 101)
AND (SALARY >= 1000 OR HIRE_DATE <= '2006-02-05');

SubQuery
Sim

SubQuery
O MySQL é compatível com subconsultas no nível SELECT, para instruções JOIN e para filtragem nas cláusulas WHERE/AND:

-- SELECT SubQuery
SELECT D.DEPARTMENT_NAME,
       (SELECT AVG(SALARY) AS AVG_SAL
        FROM EMPLOYEES E
        WHERE E.DEPARTMENT_ID =
              D.DEPARTMENT_ID) AVG_SAL
FROM DEPARTMENTS D;

-- JOIN SubQuery SELECT FIRST_NAME, LAST_NAME, SALARY FROM EMPLOYEES E JOIN (SELECT * FROM DEPARTMENTS WHERE LOCATION_ID = 2700) D ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
-- Filtering Subquery SELECT FIRST_NAME, LAST_NAME, SALARY FROM EMPLOYEES WHERE SALARY < (SELECT AVG(SALARY) FROM EMPLOYEES);
Operadores Sim Operadores O MySQL é compatível com todos os operadores básicos:

> | >= | < | <= | = | <> | !=

Funções analíticas (ou funções de janela e classificação)

As funções analíticas do Oracle estendem a funcionalidade das funções analíticas SQL padrão fornecendo recursos para calcular valores agregados com base em um grupo de linhas. Essas funções podem ser aplicadas a conjuntos de resultados particionados logicamente no escopo de uma única expressão de consulta. Geralmente, eles são usados em combinação com relatórios e análises de negócios, com o potencial de melhorar o desempenho da consulta como uma alternativa para alcançar o mesmo resultado usando um código SQL não analítico mais complexo.

Notas de conversão

  • O MySQL versão 5.7 não fornece funções analíticas para oferecer compatibilidade com uma conversão de instruções SQL simples. No entanto, essa funcionalidade foi adicionada parcialmente no MySQL versão 8 (em inglês), tornando a conversão de funções analíticas um ponto a ser considerado, provavelmente exigindo esforço manual no processo de migração.
  • Uma solução opcional é reescrever o código para remover o uso de funções analíticas, reverter para soluções de código SQL mais tradicionais ou mover essa lógica para uma camada de aplicativo.

Na tabela a seguir, veja as funções analíticas comuns do Oracle.

Família de funções Funções relacionadas Compatível com o MySQL 5.7
Análise e classificação

RANK
AVERAGE_RANK
DENSE_RANK
RANK ROW_NUMBER
PERCENT_RANK
CUME_DIST
NTILE
FIRST_VALUE
LAST_VALUE
OVER (PARTITION BY...)
Não
Hierárquica

CONNECT BY
HIER_ANCESTOR
HIER_CHILD_COUNT
HIER_DEPTH
HIER_LEVEL
HIER_ORDER
HIER_PARENT
HIER_TOP
Não
Atraso

LAG
LAG_VARIANCE LAG_VARIANCE_PERCENT LEAD
LEAD_VARIANCE LEAD_VARIANCE_PERCENT
Não

Expressão de tabela comum (CTE)

Os CTEs fornecem uma maneira de implementar a lógica do código sequencial para reutilizar o código SQL que pode ser muito complexo ou não eficiente para uso múltiplo. Os CTEs podem ser nomeados e usados várias vezes em diferentes partes de uma instrução SQL usando a cláusula WITH.

Notas de conversão

  • O MySQL versão 5.7 não é compatível com CTEs, mas o MySQL versão 8 (em inglês) sim.
  • Para uma solução alternativa, use tabelas derivadas ou subconsultas ou reescreva a instrução SQL para eliminar a funcionalidade de CTE.

Exemplos

Oracle

WITH DEPT_COUNT
(DEPARTMENT_ID, DEPT_COUNT) AS
(SELECT DEPARTMENT_ID,
        COUNT(*)
 FROM EMPLOYEES
 GROUP BY DEPARTMENT_ID)

SELECT E.FIRST_NAME ||' '|| E.LAST_NAME AS EMP_NAME, D.DEPT_COUNT AS EMP_DEPT_COUNT FROM EMPLOYEES E JOIN DEPT_COUNT D USING (DEPARTMENT_ID) ORDER BY 2 DESC;
MySQL

SELECT * FROM (
SELECT CONCAT(E.FIRST_NAME, ' ', E.LAST_NAME) AS EMP_NAME,
       (SELECT COUNT(*)
        FROM EMPLOYEES D
        WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID
        GROUP BY DEPARTMENT_ID) AS EMP_DEPT_COUNT
FROM EMPLOYEES E
ORDER BY 2 DESC) TBL
WHERE EMP_DEPT_COUNT IS NOT NULL;

Instrução MERGE

A instrução MERGE (ou UPSERT) fornece um meio para especificar instruções SQL que executam condicionalmente operações DML em uma operação MERGE, em vez de uma única operação DML, executada separadamente. Ele seleciona registros da tabela de origem e, em seguida, especificando uma estrutura lógica, executa automaticamente várias operações DML na tabela de destino. Esse recurso ajuda a evitar o uso de várias inserções, atualizações ou exclusões. Observe que MERGE é uma instrução determinística, ou seja, depois que uma linha é processada pela instrução MERGE, ela não pode ser processada novamente usando a mesma instrução MERGE.

Notas de conversão

Ao contrário do Oracle, o MySQL versão 5.7 não é compatível com a funcionalidade MERGE. Para simular parcialmente a funcionalidade MERGE, o MySQL fornece as instruções REPLACE e INSERT… ON DUPLICATE KEY UPDATE (links em inglês):

  • REPLACE: funciona da mesma maneira que uma instrução INSERT, exceto se uma linha antiga na tabela tiver o mesmo valor de uma nova linha para um índice PRIMARY KEY ou UNIQUE. Nesse caso, a linha antiga é excluída antes que a nova linha seja inserida.

  • INSERT… ON DUPLICATE KEY UPDATE: se uma linha inserida causar um valor duplicado em um índice PRIMARY KEY ou UNIQUE, ocorrerá um UPDATE da linha antiga para eliminar a exceção de chave duplicada, por exemplo:

    INSERT INTO tbl (a,b,c) VALUES (1,2,3)
      ON DUPLICATE KEY UPDATE c=c+1;
    
    UPDATE tbl SET c=c+1 WHERE a=1;
    

Outra solução seria converter a funcionalidade MERGE em um procedimento armazenado para gerenciar operações DML, usando os comandos INSERT, UPDATE e DELETE com processamento de exceções e duplicações.

Dicas de instrução SQL

O Oracle fornece uma grande coleção de dicas de consulta SQL que permite que os usuários influenciem o comportamento do otimizador e a tomada de decisão, com o objetivo de produzir planos de execução de consulta mais eficientes. O Oracle é compatível com mais de 60 dicas de banco de dados diferentes. O MySQL fornece um conjunto limitado de dicas de consulta.

Em geral, o MySQL versão 5.7 é compatível com dois tipos de dicas de consulta: OPTIMIZER HINTS e INDEX HINTS. As Dicas do otimizador do MySQL (em inglês) permitem controlar o comportamento do otimizador em instruções SQL individuais, por exemplo:

SELECT /*+ NO_RANGE_OPTIMIZATION(tbl PRIMARY, col1_idx) */ col1 FROM tbl;

Dicas do otimizador MySQL 5.7 disponíveis

Nome da dica Visão geral da dica Escopos aplicáveis

BKA, NO_BKA
Afeta o processamento da junção de acesso à chave em lote Bloco de consulta, tabela

BNL, NO_BNL
Afeta o processamento da junção de loop aninhado Bloco de consulta, tabela

MAX_EXECUTION_TIME
Limita o tempo de execução da instrução Global

MRR, NO_MRR
Afeta a otimização de leitura em vários intervalos Tabela, índice

NO_ICP
Afeta a otimização de pushdown da condição do índice Tabela, índice

NO_RANGE_OPTIMIZATION
Afeta a otimização do intervalo Tabela, índice

QB_NAME
Atribui um nome ao bloco de consulta Bloqueio de consulta

SEMIJOIN, NO_SEMIJOIN
Afeta estratégias de semi-join Bloqueio de consulta

SUBQUERY
Afeta a materialização, estratégias de subconsultas IN-para-EXISTS. Bloqueio de consulta

As Dicas de índice do MySQL (em inglês) fornecem ao otimizador informações sobre como escolher índices durante o processamento da consulta. As palavras-chave USE, FORCE ou IGNORE são usadas para controlar o processo de uso do índice do otimizador, por exemplo:

SELECT * FROM tbl USE INDEX (col1_index, col2_index);
-- OR
SELECT * FROM tbl IGNORE INDEX (col1_index, col2_index);

Observações sobre a conversão

Como há diferenças fundamentais entre o otimizador do MySQL e Oracle, e porque há limitação se houver sobreposição entre dicas de consulta MySQL e Oracle, recomendamos que você converta qualquer instrução SQL do Oracle que contenha dicas de consulta não especificadas sobre o banco de dados MySQL de destino.

Ajuste o desempenho do MySQL por meio das ferramentas do MySQL (por exemplo, Workbench (em inglês) do MySQL para painéis de desempenho em tempo real) e de recursos como análise de consultas usando planos de execução e ajuste dos parâmetros de instância ou sessão de acordo com o caso de uso.

Planos de execução

O principal objetivo dos planos de execução é fornecer uma visão interna das escolhas feitas pelo otimizador de consultas para acessar dados do banco de dados. O otimizador de consultas gera planos de execução para instruções SELECT, INSERT, UPDATE e DELETE para usuários de banco de dados, permitindo que os administradores tenham uma visão melhor de consultas específicas e operações DML. Elas são especialmente úteis quando você precisa fazer o ajuste de desempenho de consultas, por exemplo, para determinar o desempenho do índice ou para determinar se há índices ausentes que precisam ser criados.

Os planos de execução podem ser afetados por volumes de dados, estatísticas de dados e parâmetros de instância (parâmetros globais ou de sessão).

Considerações sobre conversão

Os planos de execução não são objetos de banco de dados que precisam ser migrados. Em vez disso, eles são uma ferramenta para analisar as diferenças de desempenho entre Oracle e MySQL executando a mesma instrução em conjuntos de dados idênticos.

O MySQL não é compatível com a mesma sintaxe, funcionalidade ou saída do plano de execução do Oracle.

Exemplos

Plano de execução do Oracle

SQL> EXPLAIN PLAN FOR
     SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID = 105;

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY (FORMAT=>'ALL +OUTLINE'));
Plan hash value: 1833546154 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 69 | 1 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 69 | 1 (0)| 00:00:01 | |* 2 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 (0)| 00:00:01 | ---------------------------------------------------------------------------------------------
Plano de execução do MySQL

mysql> EXPLAIN SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID = 105;

+----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ | 1 | SIMPLE | EMPLOYEES | NULL | const | PRIMARY | PRIMARY | 3 | const | 1 | 100.00 | NULL | +----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+

Procedimentos, funções e gatilhos armazenados

PL/SQL é a linguagem processual estendida do Oracle usada para criar, armazenar e aplicar soluções baseadas em código no banco de dados. Em geral, os procedimentos e funções armazenados no banco de dados são elementos de código que consistem em linguagem processual estendida ANSI SQL e SQL, por exemplo, PL/SQL para Oracle, PL/pgSQL para PostgreSQL e linguagem processual MySQL para MySQL. O MySQL usa o mesmo nome do banco de dados para sua própria linguagem processual estendida.

O objetivo desses procedimentos e funções armazenados é fornecer soluções para requisitos mais adequados para execução no banco de dados e não no aplicativo (por exemplo, desempenho, compatibilidade e segurança). Ainda que os procedimentos e as funções armazenados usem PL/SQL, os procedimentos armazenados são usados principalmente para executar operações DDL/DML, e as funções são usadas principalmente para executar cálculos e retornar resultados específicos.

Linguagem processual PL/SQL para MySQL

Do ponto de vista da migração de código do Oracle PL/SQL para o MySQL, a implementação processual do MySQL é diferente da implementação do Oracle. Portanto, a migração de código é necessária para converter a funcionalidade PL/SQL do Oracle em procedimentos e funções armazenados no MySQL. Além disso, o pacote Oracle e o corpo do pacote não são compatíveis com o MySQL. Portanto, ao fazer a conversão de código, converta esses elementos (ou analise-os) em unidades únicas de código MySQL. Observe que os procedimentos e funções armazenados do MySQL também são chamados de rotinas.

Proprietário do objeto de código

No Oracle, o proprietário de um procedimento ou função armazenada é um usuário específico. No MySQL, o proprietário é um esquema específico (criado em um banco de dados por um usuário de banco de dados).

Privilégios e segurança do objeto de código

No Oracle, para criar um procedimento ou função armazenada, o usuário precisa ter o privilégio de sistema CREATE PROCEDURE (para criar procedimentos ou funções em outros usuários diferentes, os usuários do banco de dados precisam ter o privilégio CREATE ANY PROCEDURE). Para executar um procedimento armazenado ou uma função, os usuários do banco de dados precisam ter o privilégio EXECUTE.

No MySQL, para criar um elemento de código, o usuário precisa ter os privilégios CREATE ROUTINE e EXECUTE para executar. A cláusula DEFINER do MySQL define o criador do usuário para o objeto de código, e o usuário precisa ter os privilégios apropriados, como CREATE ROUTINE.

Sintaxe de procedimento e função armazenados do MySQL

O exemplo a seguir mostra o procedimento armazenado do MySQL e a sintaxe (em inglês):

CREATE
    [DEFINER = user]
    PROCEDURE sp_name ([proc_parameter[,...]])
    [characteristic ...] routine_body

CREATE
    [DEFINER = user]
    FUNCTION sp_name ([func_parameter[,...]])
    RETURNS type
    [characteristic ...] routine_body

proc_parameter:
    [ IN | OUT | INOUT ] param_name type

func_parameter:
    param_name type

type:
    Any valid MySQL data type

characteristic:
    COMMENT 'string'
  | LANGUAGE SQL
  | [NOT] DETERMINISTIC
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }

routine_body:
    Valid SQL routine statement