Migrar utilizadores da Oracle para o Cloud SQL para MySQL: consultas, procedimentos armazenados, funções e acionadores

Este documento faz parte de uma série que fornece informações e orientações importantes relacionadas com o planeamento e a execução de migrações de bases 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 seguintes partes:

Consultas

O Oracle e o Cloud SQL para MySQL suportam a norma ANSI SQL. Geralmente, a migração de declarações SQL é simples quando usa apenas elementos de sintaxe básicos (por exemplo, não especificar funções escalares nem qualquer outra funcionalidade expandida do Oracle). A secção seguinte aborda os elementos de consulta Oracle comuns e os respetivos equivalentes do Cloud SQL para MySQL.

Sintaxe básica SELECT e FROM

Nome da funcionalidade ou nome da sintaxe da Oracle Vista geral ou implementação da Oracle Suporte do MySQL Solução correspondente ou alternativa do MySQL
Sintaxe básica de SQL para obtençã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
Alias de colunas
SELECT COL1 AS C1
Sim
SELECT COL1 AS C1
OR
SELECT COL1 C1
Nome da tabela
sensibilidade a maiúsculas e minúsculas
Sem sensibilidade a maiúsculas e minúsculas
(por exemplo, o nome da tabela pode ser orders e/ou ORDERS).
Não Sensível a maiúsculas e minúsculas de acordo com o nome da tabela definido (por exemplo, o nome da tabela só pode ser orders ou ORDERS).

Pode ler mais detalhes sobre a sintaxe SELECT do MySQL.

  • Visualizações incorporadas
    • As vistas em linha (também conhecidas como tabelas derivadas) são declarações SELECT localizadas na cláusula FROM e usadas como uma subconsulta.
    • As vistas incorporadas podem ajudar a simplificar consultas complexas removendo cálculos compostos ou eliminando operações de junção, ao mesmo tempo que condensam várias consultas separadas numa única consulta simplificada.
    • Nota de conversão: as visualizações inline do Oracle não requerem a utilização de alias, enquanto o MySQL requer alias específicos para cada visualização inline.

A tabela seguinte apresenta um exemplo de conversão do Oracle para o MySQL, como uma vista inline.

Oracle 11g/12c
SQL> SELECT FIRST_NAME,
            DEPARTMENT_ID,
            SALARY,
            DATE_COL
     FROM EMPLOYEES,
          (SELECT SYSDATE AS DATE_COL FROM DUAL);

O resultado é semelhante ao seguinte:
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 vista inline:
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

Adicionar um alias à vista inline:
mysql> SELECT FIRST_NAME,
              DEPARTMENT_ID,
              SALARY,
              DATE_COL
       FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL) AS A1;

O resultado é semelhante ao seguinte:
+-------------+---------------+----------+---------------------+
| 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 |

Declarações JOIN

As declarações JOIN do Oracle são suportadas pelas declarações JOIN do MySQL, exceto pela cláusula FULL JOIN. Além disso, as declarações JOIN do MySQL suportam a utilização de sintaxe alternativa, como a cláusula USING, a cláusula WHERE em vez da cláusula ON e a utilização de SUBQUERY na declaração JOIN.

A tabela seguinte apresenta um exemplo de conversão de JOIN.

Tipo de JOIN da Oracle Suportado pelo MySQL Sintaxe 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 contornar o problema, considere usar UNION com declaraçõ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 suporta 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 declarações SELECT e elimina os registos duplicados.
  • UNION ALL: anexa os conjuntos de resultados de duas ou mais declarações SELECT sem eliminar registos duplicados.
  • INTERSECT: devolve a interseção de duas ou mais declarações SELECT apenas se existir um registo em ambos os conjuntos de dados.
  • MINUS: compara duas ou mais declarações SELECT, devolvendo apenas linhas distintas da primeira consulta que não são devolvidas pelas outras declarações.

Notas de conversão

Quando converter funções Oracle INTERSECT e MINUS em MySQL, use declarações JOIN e IN e EXISTS como solução alternativa.

Exemplos

Função Oracle Implementação da Oracle Suporte do MySQL Solução correspondente ou alternativa 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 oferece uma lista extensa de funções escalares (de linha única) e de agregação. Algumas funções do MySQL são semelhantes às suas equivalentes do Oracle (pelo nome e funcionalidade ou com um nome diferente, mas com uma funcionalidade semelhante). Embora as funções do MySQL possam ter nomes idênticos aos das funções equivalentes do Oracle, podem apresentar uma funcionalidade diferente.

As tabelas seguintes descrevem onde o Oracle e o MySQL são equivalentes por nome e funcionalidade (especificado por "Sim") e onde é recomendada uma conversão (todos os casos que não sejam "Sim").

Funções de carateres
Função Oracle Especificação ou implementação da função Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função MySQL
CONCAT(str1,str2)
Devolve str1 concatenado com str2:
CONCAT('A', 1) = A1
Sim
CONCAT
Equivalente a Oracle:
CONCAT('A', 1) = A1
LOWER/UPPER
Devolve char com todas as letras em minúsculas ou maiúsculas:
LOWER('SQL') = sql
Sim
LOWER/UPPER
Equivalente a Oracle:
LOWER('SQL') = sql
LPAD/RPAD(expr1,n,expr2)
Devolve expr1, com preenchimento à esquerda ou à direita até ao comprimento de n carateres com a sequência de carateres em expr2:
LPAD('A',3,'*') = **A
Sim
LPAD/RPAD
Equivalente a Oracle:
LPAD('A',3,'*') = **A
SUBSTR(char,p,n)
Devolve uma parte de char, começando na posição do caráter p, com um comprimento de substring de n carateres:
SUBSTR('MySQL', 3, 3)
= SQL
Sim
SUBSTR(char,p,n)
Equivalente a Oracle:
SUBSTR('MySQL', 3, 3)
= SQL
INSTR(index,str)
Devolve a posição (index) da string str:
INSTR('MySQL', 'y')
= 2
Sim
INSTR
Equivalente a Oracle:
INSTR('MySQL', 'y')
= 2
REPLACE(char,str1,str2)
Devolve o carater com todas as ocorrências de uma string de pesquisa substituídas por uma string de substituição:
REPLACE('ORADB', 'ORA', 'MySQL')

= MySQLDB
Sim
REPLACE(char,str1,str2)
Equivalente a Oracle:
REPLACE('ORADB', 'ORA', 'MySQL')

= MySQLDB
TRIM(str)
Remova carateres à esquerda ou à direita (ou ambos) de uma string:
TRIM(both '-' FROM '-MySQL-')
= MySQL

TRIM(' MySQL ') = MySQL
Sim
TRIM(str)
Equivalente a Oracle:
TRIM(both '-' FROM '-MySQL-')
= MySQL

TRIM(' MySQL ') = MySQL
LTRIM/RTRIM(str)
Remove do início ou do fim da string todos os carateres que aparecem na pesquisa:
LTRIM('   MySQL', ' ')
= MySQL
Parcialmente
LTRIM/RTRIM(str)
Função R/LTRIM da Oracle, exceto uma substituição do parâmetro (espaço em branco ou string). O MySQL R/LTRIM só elimina os espaços em branco, aceitando apenas a string de entrada:
LTRIM('   MySQL')
= MySQL
ASCII(char)
Devolve a representação decimal no conjunto de carateres da base de dados do primeiro caráter de char:
ASCII('A') = 65
Sim
ASCII(char)
Equivalente a Oracle:
ASCII('A') = 65
CHR(char)
Devolve o valor do código ASCII, que é um valor numérico entre 0 e 225, para um caráter:
CHR(65) = A
Parcialmente com um nome de função diferente
CHAR(char)
O MySQL usa a função CHAR para a mesma funcionalidade. Por isso, tem de modificar um nome de função:
CHAR(65) = A
LENGTH(str)
Devolver o comprimento de uma determinada string:

LENGTH ('MySQL') = 5
Sim
LENGTH(str)
Equivalente a Oracle:
LENGTH('MySQL') = 5
REGEXP_REPLACE(str1,expr,str2)
Pesquise uma string por um padrão de expressão regular:
REGEXP_REPLACE('John', '[hn].', '1') = Jo1
Não N/A Apenas suportado a partir da versão 8 do MySQL. Como solução alternativa, use a função REPLACE, se possível, ou converta para a camada de aplicação
REGEXP_SUBSTR(str,expr)
Expande a funcionalidade da função SUBSTR pesquisando uma string por um padrão de expressão regular:
REGEXP_SUBSTR('https://console.cloud.google.com/sql/instances','https://([[:alnum:]]+\.?){3,4}/?')
= https://console.cloud.google.com/
Não N/A Apenas suportado a partir da versão 8 do MySQL. Para uma solução alternativa, use a função SUBSTR, se possível, ou converta a funcionalidade na camada de aplicação.
REGEXP_COUNT(str,expr)
Devolve o número de vezes que um padrão ocorre numa string de origem. Não N/A Para uma solução alternativa, converta a funcionalidade para a camada de aplicação.
REGEXP_INSTR(index,expr)
Pesquise uma posição (índice) de string para um padrão de expressão regular. Não N/A Apenas suportado a partir da versão 8 do MySQL.
REVERSE(str)
Devolva uma string invertida
REVERSE('MySQL')
= LQSyM
Sim
REVERSE
Equivalente a Oracle:
REVERSE('MySQL')
= LQSyM
Funções numéricas
Função Oracle Especificação ou implementação da função Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função MySQL
ABS(n)
Valor absoluto de n:
ABS(-4.6) = 4.6
Sim
ABS
Equivalente a Oracle:
ABS(-4.6) = 4.6
CEIL(n)
Devolve o menor número inteiro que é maior ou igual a n:
CEIL(21.4) = 22
Sim
CEIL
Equivalente a Oracle:
CEIL(21.4) = 22
FLOOR(n)
Devolve o maior número inteiro igual ou inferior a n:
FLOOR(-23.7) = -24
Sim
FLOOR
Equivalente a Oracle:
FLOOR(-23.7) = -24
MOD(m,n)
Devolve o resto de m dividido por n:
MOD(10, 3) = 1
Sim
MOD(m,n)
Equivalente a Oracle:
MOD(10,3) = 1
ROUND(m,n)
Devolve m arredondado a n casas decimais à direita da vírgula decimal:
ROUND(1.39,1) = 1.4
Sim
ROUND
Equivalente a Oracle:
ROUND(1.39,1) = 1.4
TRUNC(n1, n2)
Devolve n1 truncado para n2 casas decimais:
TRUNC(99.999) = 99
TRUNC(99.999,0) = 99
Parcialmente com um nome de função diferente
TRUNCATE(n1, n2)
A função TRUNCATE do MySQL tem de aceitar um número de entrada e um número inteiro para especificar a quantidade de precisão à direita do ponto decimal:
TRUNCATE(99.999,0) = 99
Funções de data e hora
Função Oracle Especificação ou implementação da função Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função MySQL
SYSDATE
Devolve a data e a hora atuais definidas para o sistema operativo no qual o servidor de base de dados reside:
SELECT SYSDATE
FROM DUAL
= 31-JUL-2019
Parcialmente
SYSDATE()
O MySQL SYSDATE() tem de incluir parênteses e devolve um formato de data/hora diferente da função Oracle SYSDATE:
SELECT SYSDATE()
FROM DUAL;
= 2019-01-31 10:01:01.0

Tenha em atenção que a formatação de data/hora pode ser alterada ao nível da sessão
SYSTIMESTAMP
Devolve a data do sistema, incluindo frações de segundos e o fuso horário:
SELECT SYSTIMESTAMP FROM DUAL
= 01-JAN-19 07.37.11.622187000 AM +00:00
Parcialmente com um nome de função diferente
CURRENT_TIMESTAMP
O MySQL devolve uma formatação de data/hora diferente da do Oracle. É necessária uma formatação de data (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
Devolve a data e hora atuais no fuso horário da sessão num valor do tipo de dados TIMESTAMP:
SELECT LOCAL_TIMESTAMP
FROM DUAL
= 01-JAN-19 10.01.10.123456 PM
Parcialmente com uma formatação de data/hora diferente.
LOCAL_TIMESTAMP
O MySQL devolve uma formatação de data/hora diferente da do Oracle. A formatação de data/hora é necessá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
Devolve 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 devolve uma formatação de data/hora diferente da do Oracle. A formatação de data/hora é necessá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
Devolve a data e 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 devolve uma formatação de data/hora diferente da do Oracle. A formatação de data/hora é necessária (ou usar 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
Devolve a data mais um número inteiro de meses:
ADD_MONTHS(SYSDATE, 1)
= 31-JAN-19
Parcialmente com um nome de função diferente
ADDDATE
Para alcançar a mesma funcionalidade, o MySQL usa a função ADDDATE:
ADDDATE(SYSDATE(), 1)
= 2019-08-01 06:42:49.0

Por predefinição, o MySQL devolve uma data/hora e um intervalo/formato diferentes dos do Oracle. A formatação de data/hora é necessária (ou uma função de data diferente) para corresponder à formatação de data/hora original.
EXTRACT(date part) Devolve o valor de um campo de data/hora especificado a partir de uma expressão de data/hora ou de intervalo:
EXTRACT(YEAR FROM DATE '2019-01-31')
= 2019
Sim EXTRACT (date part) Equivalente a Oracle:
EXTRACT(YEAR FROM DATE '2019-01-31')
= 2019
LAST_DAY
Devolve 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 devolve uma formatação de data/hora diferente da do Oracle. A formatação de data/hora é necessá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
Devolve o número de meses entre as datas date1 e date2:
MONTHS_BETWEEN(
SYSDATE, SYSDATE-60)
= 1.96
Parcialmente com um nome de função diferente
PERIOD_DIFF(date1,date2)
A função PERIOD_DIFF do MySQL devolve a diferença em meses como um número inteiro entre dois períodos (formatados como YYMM ou YYYYMM):
PERIOD_DIFF(
'201903', '201901')
= 2

Para alcançar os mesmos valores que a função MONTH_BETWEEN do Oracle, é necessária uma conversão mais específica
TO_CHAR (data/hora) Converte um tipo de dados de data/hora ou indicação de tempo num valor do 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 um 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 descodificação
Função Oracle Especificação ou implementação da função Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função MySQL
DECODE
Compara a expressão com cada valor de pesquisa um a um através da funcionalidade de uma declaração IF-THEN-ELSE Não
CASE
Use a declaração CASE do MySQL para alcançar uma funcionalidade semelhante.
DUMP
Devolve 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 Não suportado.
ORA_HASH
Calcula um valor de hash para uma determinada expressão. Não
MD5/SHA
Use o MySQL MD5 para a soma de verificação de 128 bits ou a função SHA para a soma de verificação de 160 bits para gerar valores hash
Funções de conversão
Função Oracle Especificação ou implementação da função Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função MySQL
CAST
Converte um tipo de dados incorporado ou um valor de tipo de coleção noutro tipo de dados incorporado ou valor de tipo de coleção:
CAST('1' as int) + 1
= 2
Parcialmente
CAST
A função CAST do MySQL é semelhante à funcionalidade do Oracle, mas, em determinados casos, tem de ser ajustada consoante seja necessária uma conversão explícita ou implícita:
CAST('1' AS SIGNED) + 1
= 2
CONVERT
Converte uma string de carateres de um conjunto de carateres para outro:
CONVERT('Ä Ê Í Õ Ø A B C D E ', 'US7ASCII', 'WE8ISO8859P1')
= ?? ?? ?? A B C
Parcialmente
CONVERT
A função CONVERT do MySQL requer alguns ajustes à sintaxe e aos parâmetros para devolver os resultados exatos como o 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 numa string:
TO_CHAR(22.73,'$99.9')
= $22.7
Não
FORMAT
A função FORMAT do MySQL executa formatos de "#,###.##" a partir de um número, arredondando-o para um determinado número de casas decimais e, em seguida, devolve o resultado como uma string. Tem uma funcionalidade diferente da do Oracle:
CONCAT('$',
FORMAT(22.73, 1))
= $22.7
TO_DATE
A função TO_DATE do Oracle converte uma string numa data através do formato de data/hora específico da origem:
TO_DATE(
'2019/01/01', 'yyyy-mm-dd')
= 01-JAN-2019
Parcialmente com um nome de função e uma formatação de data/hora diferentes
STR_TO_DATE
A função STR_TO_DATE do MySQL usa uma string e devolve 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 num valor de um tipo de dados NUMBER:
TO_NUMBER('01234')
= 1234
Não
CAST
Em alternativa, use a função CAST do MySQL para devolver o mesmo resultado que a função TO_NUMBER do Oracle:
CAST('01234' as SIGNED)
= 1234
Funções SELECT condicionais
Função Oracle Especificação ou implementação da função Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função MySQL
CASE
A declaração CASE escolhe a partir de uma sequência de condições e executa uma declaraçã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 suporta a utilização do processamento condicional IF/ELSE na declaraçã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 Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função MySQL
COALESCE
Devolve a primeira expressão não nula na lista de expressões:
COALESCE(
null, '1', 'a')
= a
Sim
COALESCE
Equivalente a Oracle:
COALESCE(
null, '1', 'a')
= 1
NULLIF
Compare expr1 e expr2m. Se forem iguais, a função devolve nulo. Se não forem iguais, a função devolve expr1:
NULLIF('1', '2')
= a
Sim
NULLIF
Equivalente a Oracle:
NULLIF('1', '2')
= a
NVL
Substitua o valor nulo (devolvido como um espaço 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 os valores nulos por uma string especificada:
IFNULL(null, 'a')
= a
NVL2
Determinar o valor devolvido por uma consulta com base no facto de uma expressão especificada
ser nula ou não nula.
Não
CASE
A declaração CASE
escolhe a partir de uma sequência de condições e executa uma declaração correspondente:
CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Funções de ambiente e identificadores
Função Oracle Especificação ou implementação da função Oracle Equivalente do MySQL Função correspondente do MySQL Especificação ou implementação da função MySQL
SYS_GUID
Gera e devolve um identificador único global (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
Devolve um número inteiro que identifica exclusivamente o utilizador da sessão (o utilizador que iniciou sessão):

SELECT UID FROM DUAL
= 43
Não N/A N/A
USER
Devolve o nome de utilizador da sessão atual:
SELECT USER FROM DUAL
= UserName
Parcialmente
USER + INSTR + SUBSTR
A função USER do MySQL devolve o nome de utilizador juntamente com o servidor de ligação (root@IP). Para obter apenas o nome de utilizador, use funções de apoio adicionais:
SELECT
SUBSTR(USER(), 1, INSTR(USER(), '@') -1) FROM DUAL
= root
USERENV
Devolve informações sobre a sessão do utilizador atual com a configuração de parâmetros atual:
SELECT USERENV('LANGUAGE')
FROM DUAL
= ENGLISH_AMERICA.AL32UTF8
Não
SHOW SESSION
VARIABLES
Use a declaração SHOW SESSION
VARIABLES do MySQL para ver as definições da sessão atual:
SHOW SESSION VARIABLES LIKE '%collation%';
= utf8_general_ci
ROWID
O servidor Oracle atribui a cada linha de cada tabela um número único ROWID 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 ficheiro de dados. Não N/A Se possível, tente emular a mesma funcionalidade com outras funções do MySQL.
ROWNUM
Devolve um número que representa a ordem pela qual uma linha é selecionada pelo Oracle a partir de uma tabela ou de tabelas unidas. 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 Oracle Especificação da função Oracle ou
implementação
MySQL
equivalente
Função correspondente do MySQL Especificação ou implementação da função MySQL
AVG
Devolve o valor médio da coluna ou da expressão. Sim
AVG
Equivalente a Oracle
COUNT
Devolve o número de linhas devolvidas por uma consulta. Sim
COUNT
Equivalente a Oracle
COUNT
(DISTINCT)
Devolve o número de valores únicos na coluna ou expressão. Sim
COUNT
(DISTINCT)
Equivalente a Oracle
MAX
Devolve o valor máximo da coluna ou da expressão. Sim
MAX
Equivalente a Oracle
MIN
Devolve o valor mínimo da coluna ou da expressão. Sim
MIN
Equivalente a Oracle
SUM
Devolve a soma do valor da coluna ou da expressão. Sim
SUM
Equivalente a Oracle
LISTAGG
Apresenta os dados em cada grupo por uma única linha especificada na cláusula ORDER BY, concatenando os valores da coluna de métricas:
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 devolver resultados semelhantes aos do Oracle, exceto diferenças de sintaxe em determinados casos:
SELECT GROUP_CONCAT(
DEPARTMENT_NAME ORDER BY DEPARTMENT_NAME SEPARATOR ', ') DEPT
FROM DEPARTMENTS;

-- Single line results
= Accounting, Administration, Benefits, Construction
Oracle 12c Fetch
Função Oracle Especificação da função Oracle ou
implementação
MySQL
equivalente
Função correspondente do MySQL Especificação ou implementação da função MySQL
FETCH
Obtém 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 obter apenas um conjunto específico de registos:
SELECT * FROM
EMPLOYEES
LIMIT 10;

Filtragem básica, operadores e subconsultas

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

Notas de conversão

Examine e resolva os formatos de data, porque os formatos Oracle e MySQL devolvem resultados predefinidos diferentes:

  • Por predefinição, a função SYSDATEOracle01-AUG-19 devolve 01-AUG-19.
  • Por predefinição, a função SYSDATE() do MySQL devolve 2019-08-01 12:04:05.
  • Os formatos de data e hora podem ser definidos através das funções MySQL [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).
Função ou subconsulta Oracle Equivalente do MySQL Função ou subconsulta correspondente do MySQL Especificação ou implementação da função 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 suporta subconsultas ao nível de SELECT, para declaraçõ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 suporta todos os operadores básicos:
> | >= | < | <= | = | <> | !=

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

As funções analíticas da Oracle expandem a funcionalidade das funções analíticas SQL padrão, oferecendo capacidades para calcular valores agregados com base num grupo de linhas. Estas funções podem ser aplicadas a conjuntos de resultados logicamente particionados no âmbito de uma única expressão de consulta. Normalmente, são usadas em combinação com relatórios e estatísticas de Business Intelligence, com o potencial de aumentar o desempenho das consultas como alternativa para alcançar o mesmo resultado usando código SQL não analítico mais complexo.

Notas de conversão

  • A versão 5.7 do MySQL não fornece funções analíticas para suportar uma conversão simples de declarações SQL. No entanto, esta funcionalidade foi adicionada parcialmente na versão 8 do MySQL, o que faz da conversão de funções analíticas um ponto a considerar, que provavelmente requer esforço manual no processo de migração.
  • Uma solução opcional é reescrever o código para remover a utilização de funções analíticas, revertendo para soluções de código SQL mais tradicionais ou movendo esta lógica para uma camada de aplicação.

A tabela seguinte lista as funções analíticas comuns da Oracle.

Família de funções Funções relacionadas Suportado pelo 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)

As CTEs oferecem uma forma de implementar a lógica de código sequencial para reutilizar código SQL que pode ser demasiado complexo ou não eficiente para utilização múltipla. As CTEs podem ser nomeadas e, em seguida, usadas várias vezes em diferentes partes de uma declaração SQL através da cláusula WITH.

Notas de conversão

  • A versão 5.7 do MySQL não suporta CTEs, mas a versão 8 do MySQL suporta.
  • Para uma solução alternativa, use tabelas derivadas ou subconsultas, ou reescreva a declaração SQL para eliminar a funcionalidade 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 declaração MERGE (ou UPSERT) oferece um meio de especificar declarações SQL únicas que realizam condicionalmente operações DML numa operação MERGE, em oposição a uma única operação DML, executada separadamente. Seleciona registos da tabela de origem e, em seguida, especificando uma estrutura lógica, executa automaticamente várias operações DML na tabela de destino. Esta funcionalidade ajuda a evitar a utilização de várias inserções, atualizações ou eliminações. Tenha em atenção que MERGE é uma declaração determinística, o que significa que, depois de uma linha ser processada pela declaração MERGE, não pode ser processada novamente com a mesma declaração MERGE.

Notas de conversão

A versão 5.7 do MySQL não suporta a funcionalidade MERGE, ao contrário do Oracle. Para simular parcialmente a funcionalidade MERGE, o MySQL fornece as declarações REPLACE e INSERT… ON DUPLICATE KEY UPDATE:

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

  • INSERT… ON DUPLICATE KEY UPDATE: se uma linha inserida causar um valor duplicado num índice PRIMARY KEY ou UNIQUE, ocorre uma 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 num procedimento armazenado para gerir operações DML, usando comandos INSERT, UPDATE e DELETE com processamento de exceções e duplicações.

Instruções de declarações SQL

A Oracle oferece uma grande coleção de sugestões de consultas SQL que permitem aos utilizadores influenciar o comportamento do otimizador e a respetiva tomada de decisões, com o objetivo de produzir planos de execução de consultas mais eficientes. A Oracle suporta mais de 60 sugestões de bases de dados diferentes. O MySQL oferece um conjunto limitado de sugestões de consultas.

Em geral, a versão 5.7 do MySQL suporta dois tipos de sugestões de consultas: OPTIMIZER HINTS e INDEX HINTS. As sugestões do otimizador do MySQL oferecem a capacidade de controlar o comportamento do otimizador em declarações SQL individuais, por exemplo:

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

Versão 5.7 do MySQL Sugestões do otimizador disponíveis

Nome da sugestão Vista geral das sugestões Âmbitos aplicáveis
BKA, NO_BKA
Afeta o processamento de junções de acesso de chaves em lote Bloco de consultas, tabela
BNL, NO_BNL
Afeta o processamento de junções de ciclo aninhado de blocos Bloco de consultas, tabela
MAX_EXECUTION_TIME
Limita o tempo de execução da declaração Global
MRR, NO_MRR
Afeta a otimização de leitura de vários intervalos Tabela, índice
NO_ICP
Afeta a otimização de pushdown da condição de índice Tabela, índice
NO_RANGE_OPTIMIZATION
Afeta a otimização do intervalo Tabela, índice
QB_NAME
Atribui um nome ao bloco de consultas Bloco de consultas
SEMIJOIN, NO_SEMIJOIN
Afeta as estratégias de junção parcial Bloco de consultas
SUBQUERY
Afeta a materialização das estratégias de subconsulta de IN para EXISTS. Bloco de consultas

As sugestões de índice do MySQL fornecem ao otimizador informações sobre como escolher índices durante o processamento de consultas. As palavras-chave USE, FORCE ou IGNORE são usadas para controlar o processo de utilização 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);

Notas de conversão

Como existem diferenças fundamentais entre o otimizador do Oracle e do MySQL e, como existem poucas ou nenhumas sobreposições entre as sugestões de consultas do Oracle e do MySQL, recomendamos que converta qualquer declaração SQL do Oracle que contenha sugestões de consultas não especificadas na base de dados MySQL de destino.

Faça o ajuste de desempenho do MySQL através de ferramentas do MySQL (por exemplo, o MySQL Workbench para painéis de controlo de desempenho em tempo real) e funcionalidades como examinar consultas usando planos de execução e ajustar os parâmetros da instância ou da sessão de acordo com o exemplo de utilização.

Planos de execução

O objetivo principal dos planos de execução é fornecer uma análise detalhada das escolhas feitas pelo otimizador de consultas para aceder aos dados da base de dados. O otimizador de consultas gera planos de execução para declarações SELECT, INSERT, UPDATE e DELETE para utilizadores da base de dados, o que também permite aos administradores ter uma melhor vista das consultas específicas e das operações DML. São especialmente úteis quando precisa de otimizar o desempenho das consultas, por exemplo, para determinar o desempenho dos índices ou determinar se existem índices em falta que precisam de ser criados.

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

Considerações sobre as conversões

Os planos de execução não são objetos de base de dados que precisam de ser migrados. Em alternativa, são uma ferramenta para analisar as diferenças de desempenho entre o Oracle e o MySQL que executam a mesma declaração em conjuntos de dados idênticos.

O MySQL não suporta a mesma sintaxe, funcionalidade nem resultado do plano de execução que o Oracle.

Exemplos

Plano de execução da 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 armazenados, funções e acionadores

O PL/SQL é a linguagem processual expandida da Oracle usada para criar, armazenar e aplicar soluções baseadas em código na base de dados. Em geral, os procedimentos e as funções armazenados na base de dados são elementos de código que consistem em ANSI SQL e linguagem processual estendida de SQL, por exemplo, PL/SQL para Oracle, PL/pgSQL para PostgreSQL e linguagem processual de MySQL para MySQL. O MySQL usa o mesmo nome que a base de dados para o seu próprio idioma processual expandido.

O objetivo destes procedimentos e funções armazenados é fornecer soluções para requisitos mais adequados para execução a partir da base de dados e não da aplicação (por exemplo, desempenho, compatibilidade e segurança). Embora os procedimentos e as funções armazenados usem PL/SQL, os procedimentos armazenados são usados principalmente para realizar operações DDL/DML e as funções são usadas principalmente para realizar cálculos para devolver resultados específicos.

PL/SQL para linguagem procedural 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 do Oracle. Por conseguinte, é necessária a migração de código para converter a funcionalidade PL/SQL do Oracle em funções e procedimentos armazenados do MySQL. Além disso, o Oracle Package e o Package Body não são suportados pelo MySQL. Por isso, quando fizer a conversão de código, converta estes elementos (ou analise-os) em unidades únicas de código MySQL. Tenha em atenção que os procedimentos armazenados e as funções do MySQL também são denominados rotinas.

Proprietário do objeto de código

No Oracle, o proprietário de um procedimento ou uma função armazenada é um utilizador específico. No MySQL, o proprietário é um esquema específico (criado numa base de dados por um utilizador da base de dados).

Privilégios e segurança de objetos de código

No Oracle, para criar um procedimento ou uma função armazenada, o utilizador tem de ter o privilégio do sistema CREATE PROCEDURE (para criar procedimentos ou funções sob outros utilizadores diferentes, os utilizadores da base de dados têm de ter o privilégio CREATE ANY PROCEDURE). Para executar um procedimento armazenado ou uma função, os utilizadores da base de dados têm de ter o privilégio EXECUTE.

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

Sintaxe de funções e procedimentos armazenados do MySQL

O exemplo seguinte mostra a sintaxe da função e do procedimento armazenado do MySQL:

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