Migra usuarios de Oracle a Cloud SQL para MySQL: consultas, procedimientos almacenados, funciones y activadores

Este documento es parte de una serie que proporciona información clave y orientación relacionada con la planificación y la realización de migraciones de bases de datos de Oracle® 11g o 12c a instancias de segunda generación con versión 5.7 de Cloud SQL para MySQL. En la serie, se incluyen las siguientes partes:

Consultas

Oracle y Cloud SQL para MySQL admiten el estándar ANSI SQL. En general, es sencillo migrar instrucciones de SQL mediante el uso de elementos de sintaxis básicos (por ejemplo, sin especificar ninguna función escalar o cualquier otra característica extendida de Oracle). En la siguiente sección, se analizan los elementos de consulta comunes de Oracle y sus equivalentes de Cloud SQL para MySQL.

Sintaxis básica SELECT y FROM

Nombre de sintaxis o nombre de la característica de Oracle Implementación o descripción general de Oracle Compatibilidad con MySQL Solución alternativa o correspondiente de MySQL
Sintaxis básica de SQL para la recuperación de datos
SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
SELECT para impresión de salida
SELECT 1 FROM DUAL
SELECT 1
OR
SELECT 1 FROM DUAL
Alias de columna
SELECT COL1 AS C1
SELECT COL1 AS C1
OR
SELECT COL1 C1
Distinción entre mayúsculas y minúsculas del
nombre de la tabla
Sin distinción entre mayúsculas y minúsculas
(por ejemplo, el nombre de la tabla puede ser orders o bien ORDERS).
No Distingue entre mayúsculas y minúsculas según el nombre de la tabla definida (por ejemplo, el nombre de la tabla solo puede ser orders o bien ORDERS).

Puedes leer más detalles sobre la sintaxis SELECT de MySQL.

  • Vistas en línea
    • Las vistas en línea (también conocidas como tablas derivadas) son declaraciones SELECT, que se ubican en la cláusula FROM y se usan como una subconsulta.
    • Las vistas en línea pueden ayudar a simplificar las consultas complejas, ya que quitan los cálculos compuestos, o eliminan las operaciones de unión, a la vez que condensan varias consultas separadas en una sola consulta simplificada.
    • Nota de conversión: Las vistas en línea de Oracle no requieren el uso de alias, mientras que MySQL sí requiere alias específicos para cada vista en línea.

En la siguiente tabla, se presenta un ejemplo de conversión de Oracle a MySQL, como una vista en línea.

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

El resultado es similar al siguiente:
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
Sin alias para la vista en línea:
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

Agregar un alias a la vista en línea:
mysql> SELECT FIRST_NAME,
              DEPARTMENT_ID,
              SALARY,
              DATE_COL
       FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL) AS A1;

El resultado es similar al siguiente:
+-------------+---------------+----------+---------------------+
| 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 |

Instrucciones JOIN

Las sentencias JOIN de Oracle son compatibles con las sentencias JOIN de MySQL, excepto la cláusula FULL JOIN. Además, las declaraciones JOIN de MySQL admiten el uso de sintaxis alternativa, como la cláusula USING, la cláusula WHERE en lugar de la cláusula ON y el uso de SUBQUERY en la declaración JOIN.

En la siguiente tabla, se presenta un ejemplo de conversión JOIN.

Tipo de JOIN de Oracle Compatible con MySQL Sintaxis de JOIN de MySQL
INNER JOIN
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
CROSS JOIN
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E CROSS JOIN DEPARTMENTS D
FULL JOIN
No Para una solución alternativa, considera usar UNION con declaraciones LEFT y RIGHT JOIN.
LEFT JOIN
[ OUTER ]
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E LEFT JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
RIGHT JOIN
[ OUTER ]
SELECT E.FIRST_NAME, D.DEPARTMENT_NAME
FROM EMPLOYEES E RIGHT JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID;
SUBQUERY
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 y MINUS

MySQL no admite las funciones INTERSECT y MINUS de Oracle, excepto las funciones UNION y UNION ALL:

  • UNION: Adjunta los conjuntos de resultados de dos o más declaraciones SELECT y elimina los registros duplicados.
  • UNION ALL: Adjunta los conjuntos de resultados de dos o más declaraciones SELECT sin eliminar los registros duplicados.
  • INTERSECT: Muestra la intersección de dos o más declaraciones SELECT solo si existe un registro en ambos conjuntos de datos.
  • MINUS: Compara dos o más declaraciones SELECT y muestra solo filas distintas de la primera consulta que no muestran las otras declaraciones.

Notas de la conversión

Cuando conviertas las funciones INTERSECT y MINUS de Oracle en MySQL, usa las declaraciones JOIN, IN y EXISTS como solución alternativa.

Ejemplos

Función de Oracle Implementación de Oracle Compatibilidad con MySQL Solución alternativa o correspondiente de MySQL
UNION
SELECT COL1 FROM TBL1
UNION
SELECT COL1 FROM TBL2
SELECT COL1 FROM TBL1
UNION
SELECT COL1 FROM TBL2
UNION ALL
SELECT COL1 FROM TBL1
UNION ALL
SELECT COL1 FROM TBL2
SELECT COL1 FROM TBL1
UNION ALL
SELECT COL1 FROM TBL2
INTERSECT
SELECT COL1 FROM TBL1
INTERSECT
SELECT COL1 FROM TBL2
No
SELECT COL1 FROM TBL1
WHERE COL1 IN
(SELECT COL1 FROM TBL2)
MINUS
SELECT COL1 FROM TBL1
MINUS
SELECT COL1 FROM TBL2
No
SELECT A.COL1
FROM TBL1 A LEFT JOIN TBL2 B
ON USING(COL1)
WHERE B.COL1 IS NULL

Funciones escalares (de una sola fila) y de grupo

MySQL proporciona una lista extensa de funciones escalares (de una sola fila) y de agregación. Algunas de las funciones de MySQL son similares a sus contrapartes de Oracle (en cuanto al nombre y la funcionalidad, o tienen un nombre diferente, pero una funcionalidad similar). Aunque las funciones de MySQL pueden tener nombres idénticos a sus contrapartes de Oracle, pueden exhibir una funcionalidad diferente.

En las siguientes tablas, se describe en qué casos son equivalentes Oracle y MySQL por nombre y funcionalidad (especificado por "Sí") y en qué casos se recomienda una conversión (todos los casos distintos de "Sí").

Funciones de caracteres
Función de Oracle Implementación o especificación de la función de Oracle Equivalente de MySQL Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
CONCAT(str1,str2)
Muestra str1 concatenado con str2:
CONCAT('A', 1) = A1
CONCAT
Equivalente a Oracle:
CONCAT('A', 1) = A1
LOWER/UPPER
Muestra char, con todas las letras en minúscula o mayúscula:
LOWER('SQL') = sql
LOWER/UPPER
Equivalente a Oracle:
LOWER('SQL') = sql
LPAD/RPAD(expr1,n,expr2)
Muestra expr1, con relleno izquierdo o derecho con n caracteres, con la secuencia de caracteres en expr2:
LPAD('A',3,'*') = **A
LPAD/RPAD
Equivalente a Oracle:
LPAD('A',3,'*') = **A
SUBSTR(char,p,n)
Muestra una parte de char, que comienza en la posición del carácter p, con una longitud de la substring de n caracteres:
SUBSTR('MySQL', 3, 3)
= SQL
SUBSTR(char,p,n)
Equivalente a Oracle:
SUBSTR('MySQL', 3, 3)
= SQL
INSTR(index,str)
Muestra la posición (índice) de la string str:
INSTR('MySQL', 'y')
= 2
INSTR
Equivalente a Oracle:
INSTR('MySQL', 'y')
= 2
REPLACE(char,str1,str2)
Muestra char con cada ocurrencia de una string de búsqueda reemplazada por una string de reemplazo:
REPLACE('ORADB', 'ORA', 'MySQL')

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

= MySQLDB
TRIM(str)
Recorta los caracteres iniciales o finales (o ambos) de una string:
TRIM(both '-' FROM '-MySQL-')
= MySQL

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

TRIM(' MySQL ') = MySQL
LTRIM/RTRIM(str)
Quita del extremo izquierdo o derecho de la string todos los caracteres que aparecen en la búsqueda:
LTRIM('   MySQL', ' ')
= MySQL
Parcialmente
LTRIM/RTRIM(str)
Función R/LTRIM de Oracle, excepto un reemplazo de parámetro (espacio en blanco o string). R/LTRIM de MySQL solo elimina los espacios en blanco y acepta solo la string de entrada:
LTRIM('   MySQL')
= MySQL
ASCII(char)
Muestra la representación decimal en el grupo de caracteres de la base de datos del primer carácter de char:
ASCII('A') = 65
ASCII(char)
Equivalente a Oracle:
ASCII('A') = 65
CHR(char)
Muestra el valor del código ASCII, que es un valor numérico entre 0 y 225, para un carácter:
CHR(65) = A
De forma parcial con un nombre de función diferente
CHAR(char)
MySQL usa la función CHAR para la misma funcionalidad; por lo tanto, debes modificar el nombre de una función:
CHAR(65) = A
LENGTH(str)
Muestra la longitud de una string determinada:

LENGTH ('MySQL') = 5
LENGTH(str)
Equivalente a Oracle:
LENGTH('MySQL') = 5
REGEXP_REPLACE(str1,expr,str2)
Busca un patrón de expresión regular en una string:
REGEXP_REPLACE('John', '[hn].', '1') = Jo1
No N/A Solo se admite desde la versión 8 de MySQL. Como solución alternativa, usa la función REPLACE, si es posible, o realiza la conversión a la capa de la aplicación.
REGEXP_SUBSTR(str,expr)
Extiende la funcionalidad de la función SUBSTR mediante la búsqueda de un patrón de expresión regular en una string:
REGEXP_SUBSTR('https://console.cloud.google.com/sql/instances','https://([[:alnum:]]+\.?){3,4}/?')
= https://console.cloud.google.com/
No N/A Solo compatible con la versión 8 de MySQL. Como solución alternativa, usa la función SUBSTR, si es posible, o convierte la funcionalidad en la capa de la aplicación.
REGEXP_COUNT(str,expr)
Muestra la cantidad de veces que se produce un patrón en una string de origen. No N/A Como una solución alternativa, convierte la funcionalidad en la capa de la aplicación.
REGEXP_INSTR(index,expr)
Busca una posición de string (índice) para un patrón de expresión regular. No N/A Solo compatible con la versión 8 de MySQL.
REVERSE(str)
Muestra una string invertida
REVERSE('MySQL')
= LQSyM
REVERSE
Equivalente a Oracle:
REVERSE('MySQL')
= LQSyM
Funciones numéricas
Función de Oracle Implementación o especificación de la función de Oracle Equivalente de MySQL Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
ABS(n)
Valor absoluto de n:
ABS(-4.6) = 4.6
ABS
Equivalente a Oracle:
ABS(-4.6) = 4.6
CEIL(n)
Muestra el número entero más pequeño mayor o igual que n:
CEIL(21.4) = 22
CEIL
Equivalente a Oracle:
CEIL(21.4) = 22
FLOOR(n)
Muestra el número entero más grande menor o igual que n:
FLOOR(-23.7) = -24
FLOOR
Equivalente a Oracle:
FLOOR(-23.7) = -24
MOD(m,n)
Muestra el resto de la división de m por n:
MOD(10, 3) = 1
MOD(m,n)
Equivalente a Oracle:
MOD(10,3) = 1
ROUND(m,n)
Muestra m redondeado a n números enteros a la derecha del punto decimal:
ROUND(1.39,1) = 1.4
ROUND
Equivalente a Oracle:
ROUND(1.39,1) = 1.4
TRUNC(n1, n2)
Muestra n1 truncado en n2 decimales:
TRUNC(99.999) = 99
TRUNC(99.999,0) = 99
De forma parcial con un nombre de función diferente
TRUNCATE(n1, n2)
La función TRUNCATE de MySQL debe aceptar un número de entrada y un número entero para especificar la cantidad de precisión a la derecha del punto decimal:
TRUNCATE(99.999,0) = 99
Funciones de fecha y hora
Función de Oracle Implementación o especificación de la función de Oracle Equivalente de MySQL Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
SYSDATE
Muestra la fecha y hora actuales establecidas para el sistema operativo en el que reside el servidor de la base de datos:
SELECT SYSDATE
FROM DUAL
= 31-JUL-2019
Parcialmente
SYSDATE()
El SYSDATE() de MySQL debe incluir paréntesis y muestra un formato de fecha y hora diferente al de la función SYSDATE de Oracle:
SELECT SYSDATE()
FROM DUAL;
= 2019-01-31 10:01:01.0

Ten en cuenta que el formato de fecha y hora se puede cambiar a nivel de la sesión
SYSTIMESTAMP
Muestra la fecha del sistema, incluidos los segundos y la zona horaria:
SELECT SYSTIMESTAMP FROM DUAL
= 01-JAN-19 07.37.11.622187000 AM +00:00
De forma parcial con un nombre de función diferente
CURRENT_TIMESTAMP
MySQL muestra un formato de fecha y hora diferente al de Oracle. Se requiere un formato de fecha (o una función de fecha diferente) para que coincida con el formato de fecha y hora original:
SELECT CURRENT_TIMESTAMP
FROM DUAL
= 2019-01-31 06:55:07
LOCAL_TIMESTAMP
Muestra la fecha y hora actuales en la zona horaria de la sesión en un valor de tipo de datos TIMESTAMP:
SELECT LOCAL_TIMESTAMP
FROM DUAL
= 01-JAN-19 10.01.10.123456 PM
De forma parcial con un formato de fecha y hora diferente.
LOCAL_TIMESTAMP
MySQL muestra un formato de fecha y hora diferente al de Oracle. El formato de fecha y hora es obligatorio (o una función de fecha diferente) para coincidir con el formato de fecha y hora original:
SELECT LOCAL_TIMESTAMP
FROM DUAL
= 2019-01-01 10:01:01.0
CURRENT_DATE
Muestra la fecha actual en la zona horaria de la sesión:
SELECT CURRENT_DATE
FROM DUAL
= 31-JAN-19
De forma parcial con un formato de fecha y hora diferente
CURRENT_DATE
MySQL muestra un formato de fecha y hora diferente al de Oracle. El formato de fecha y hora es obligatorio (o una función de fecha diferente) para coincidir con el formato de fecha y hora original:
SELECT CURRENT_DATE
FROM DUAL
= 2019-01-31
CURRENT_TIMESTAMP
Muestra la fecha y hora actuales en la zona horaria de la sesión:
SELECT CURRENT_TIMESTAMP
FROM DUAL
= 31-JAN-19 06.54.35.543146 AM +00:00
De forma parcial con un formato de fecha y hora diferente
CURRENT_TIMESTAMP
MySQL muestra un formato de fecha y hora diferente al de Oracle. El formato de fecha y hora es obligatorio (o una función de fecha diferente) para coincidir con el formato de fecha y hora original:
SELECT CURRENT_TIMESTAMP
FROM DUAL
= 2019-01-31 06:55:07
ADD_MONTHS
Muestra la fecha y los meses en números enteros:
ADD_MONTHS(SYSDATE, 1)
= 31-JAN-19
De forma parcial con un nombre de función diferente
ADDDATE
Para lograr la misma funcionalidad, MySQL usa la función ADDDATE:
ADDDATE(SYSDATE(), 1)
= 2019-08-01 06:42:49.0

De forma predeterminada, MySQL muestra una fecha/hora y un rango/formato diferentes a los de Oracle. El formato de fecha y hora es obligatorio (o una función de fecha diferente) para coincidir con el formato de fecha y hora original.
EXTRACT(parte de la fecha) Muestra el valor de un campo de fecha/hora especificado de una expresión de fecha/hora o intervalo:
EXTRACT(YEAR FROM DATE '2019-01-31')
= 2019
EXTRACT (parte de la fecha) Equivalente a Oracle:
EXTRACT(YEAR FROM DATE '2019-01-31')
= 2019
LAST_DAY
Muestra la fecha del último día del mes:
LAST_DAY('01-JAN-2019')
= 31-JAN-19
De forma parcial con un formato de fecha y hora diferente
LAST_DAY
MySQL muestra un formato de fecha y hora diferente al de Oracle. El formato de fecha y hora es obligatorio (o una función de fecha diferente) para coincidir con el formato de fecha y hora original:
LAST_DAY('2019-01-01')
= 2019-01-31
MONTH_BETWEEN
Muestra el número de meses entre las fechas date1 y date2:
MONTHS_BETWEEN(
SYSDATE, SYSDATE-60)
= 1.96
De forma parcial con un nombre de función diferente
PERIOD_DIFF(date1,date2)
La función PERIOD_DIFF de MySQL muestra la diferencia en meses como un número entero entre dos períodos (con formato YYMM o YYYYMM):
PERIOD_DIFF(
'201903', '201901')
= 2

Para lograr los mismos valores que la función MONTH_BETWEEN de Oracle, se requerirá una conversión más específica
TO_CHAR (Fecha y hora) Convierte un tipo de datos de fecha/hora o marca de tiempo en un valor de tipo de datos VARCHAR2 en el formato especificado por el formato de fecha:
TO_CHAR(
SYSDATE,'DD-MM-YYYY HH24:MI:SS')
= 01-01-2019 10:01:01
De forma parcial con un nombre de función diferente
DATE_FORMAT
La función DATE_FORMAT de MySQL da formato a una fecha según lo especifica una definición de formato de fecha:
DATE_FORMAT(
SYSDATE(),'%d-%m-%Y %H:%i:%s')
= 01-01-2019 10:01:01
Funciones de codificación y decodificación
Función de Oracle Implementación o especificación de la función de Oracle Equivalente de MySQL Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
DECODE
Compara la expresión con cada valor de búsqueda, uno por uno, mediante la funcionalidad de una declaración IF-THEN-ELSE. No
CASE
Usa la declaración CASE de MySQL para lograr una funcionalidad similar.
DUMP
Muestra un valor VARCHAR2 que contiene el código de tipo de datos, la longitud en bytes y la representación interna para una expresión determinada. No N/A No compatible.
ORA_HASH
Calcula un valor de hash para una expresión determinada. No
MD5/SHA
Usa MD5 de MySQL para la suma de verificación de 128 bits o la función SHA para la suma de verificación de 160 bits a fin de generar valores de hash
Funciones de conversión
Función de Oracle Implementación o especificación de la función de Oracle Equivalente de MySQL Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
CAST
Convierte un tipo de datos integrado o un valor de tipo de colección en otro tipo de datos integrado o un valor de tipo de colección:
CAST('1' as int) + 1
= 2
Parcialmente
CAST
La función CAST de MySQL es similar a la funcionalidad de Oracle, pero en ciertos casos debe ajustarse según si se requiere una conversión explícita o implícita:
CAST('1' AS SIGNED) + 1
= 2
CONVERT
Convierte una string de caracteres de un conjunto de caracteres en otro:
CONVERT('Ä Ê Í Õ Ø A B C D E ', 'US7ASCII', 'WE8ISO8859P1')
= ?? ?? ?? A B C
Parcialmente
CONVERT
La función CONVERT de MySQL requiere algunos ajustes en la sintaxis y los parámetros para mostrar los resultados exactos como Oracle:
CONVERT('Ä Ê Í A B C ' USING utf8)
= Ä Ê Í A B C
TO_CHAR
(string/numérico)
La función convierte un número o una fecha en una string:
TO_CHAR(22.73,'$99.9')
= $22.7
No
FORMAT
La función FORMAT de MySQL realiza un formato de “#,###.##” de un número, lo redondea a una cantidad determinada de decimales y, luego, muestra el resultado como una string; tiene una funcionalidad diferente a la de Oracle:
CONCAT('$',
FORMAT(22.73, 1))
= $22.7
TO_DATE
La función TO_DATE de Oracle convierte una string en una fecha según el formato de fecha y hora específico de la fuente:
TO_DATE(
'2019/01/01', 'yyyy-mm-dd')
= 01-JAN-2019
De forma parcial con diferente nombre de función y formato de fecha/hora
STR_TO_DATE
La función STR_TO_DATE de MySQL toma una string y muestra una fecha especificada por formato de fecha/hora:
STR_TO_DATE(
'2019/01/01', '%Y/%m/%d')
= 2019-01-01
TO_NUMBER
Convierte la expresión en un valor de un tipo de datos NUMBER:
TO_NUMBER('01234')
= 1234
No
CAST
Como alternativa, usa la función CAST de MySQL para mostrar el mismo resultado que Oracle TO_NUMBER:
CAST('01234' as SIGNED)
= 1234
Funciones SELECT condicionales
Función de Oracle Implementación o especificación de la función de Oracle Equivalente de MySQL Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
CASE
La declaración CASE elige entre una secuencia de condiciones y ejecuta una declaración correspondiente con la siguiente sintaxis:
CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
CASE
Además de la función CASE, MySQL también admite el uso del control condicional IF/ELSE dentro de la declaración SELECT:
CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Funciones nulas
Función de Oracle Implementación o especificación de la función de Oracle Equivalente de MySQL Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
COALESCE
Muestra la primera expresión que no es nula en la lista de expresiones:
COALESCE(
null, '1', 'a')
= a
COALESCE
Equivalente a Oracle:
COALESCE(
null, '1', 'a')
= 1
NULLIF
Compara expr1 y expr2m. Si son iguales, la función muestra un valor nulo. Si no son iguales, la función muestra expr1:
NULLIF('1', '2')
= a
NULLIF
Equivalente a Oracle:
NULLIF('1', '2')
= a
NVL
Reemplaza nulo (se muestra como un espacio en blanco) por una string en los resultados de una consulta:
NVL(null, 'a')
= a
No
IFNULL
La función equivalente de MySQL sería la función IFNULL , que reemplaza los valores nulos por una string determinada:
IFNULL(null, 'a')
= a
NVL2
Determina el valor que muestra una consulta en función de si una expresión
especificada es nula o no.
No
CASE
La declaración CASE
elige entre una secuencia de condiciones y ejecuta una declaración correspondiente:
CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Funciones de identificador y entorno
Función de Oracle Implementación o especificación de la función de Oracle Equivalente de MySQL Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
SYS_GUID
Genera y muestra un identificador único global (valor RAW) compuesto por 16 bytes:
SELECT SYS_GUID()
FROM DUAL
= 8EFA4A31468B4C6DE05011AC0200009E
No REPLACE y UUID Como una solución alternativa, usa las funciones REPLACE y UUID de MySQL a fin de simular la función SYS_GUID de Oracle:
REPLACE(
UUID(), '-', '')
UID
Muestra un número entero que identifica de forma única al usuario de la sesión (el usuario
que accedió):
SELECT UID FROM DUAL
= 43
No N/A N/A
USER
Muestra el nombre de usuario de la sesión actual:
SELECT USER FROM DUAL
= UserName
Parcialmente
USER + INSTR + SUBSTR
La función USER de MySQL muestra el nombre de usuario y el servidor de conexión (root@IP). Para recuperar solo el nombre de usuario, usa funciones complementarias adicionales:
SELECT
SUBSTR(USER(), 1, INSTR(USER(), '@') -1) FROM DUAL
= root
USERENV
Muestra información sobre la sesión de usuario actual con la configuración de parámetros actual:
SELECT USERENV('LANGUAGE')
FROM DUAL
= ENGLISH_AMERICA.AL32UTF8
No
SHOW SESSION
VARIABLES
Usa la declaración SHOW SESSION
VARIABLES de MySQL para ver la configuración de la sesión actual:
SHOW SESSION VARIABLES LIKE '%collation%';
= utf8_general_ci
ROWID
El servidor de Oracle asigna a cada fila un ROWID único para identificar la fila en la tabla. ROWID es la dirección de la fila que contiene el número de objeto de datos, el bloque de datos de la fila, la posición de la fila y el archivo de datos. No N/A Si es posible, intenta emular la misma funcionalidad con otras funciones de MySQL.
ROWNUM
Muestra un número que representa el orden en que Oracle selecciona una fila de una tabla o tablas unidas. No N/A Si es posible, intenta emular la misma funcionalidad con otras funciones de MySQL o variables de sesión.
Funciones de agregación (grupo)
Función de Oracle Implementación o especificación de la función
de Oracle
Equivalente
de MySQL
Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
AVG
Muestra el valor promedio de la columna o expresión.
AVG
Equivalente a Oracle
COUNT
Muestra la cantidad de filas que muestra una consulta.
COUNT
Equivalente a Oracle
COUNT
(DISTINCT)
Muestra el número de valores únicos en la columna o expresión.
COUNT
(DISTINCT)
Equivalente a Oracle
MAX
Muestra el valor máximo de la columna o expresión.
MAX
Equivalente a Oracle
MIN
Muestra el valor mínimo de la columna o expresión.
MIN
Equivalente a Oracle
SUM
Muestra la suma del valor de la columna o expresión.
SUM
Equivalente a Oracle
LISTAGG
Muestra los datos dentro de cada grupo mediante una sola fila especificada en la cláusula ORDER BY mediante la concatenación de los valores de la columna de medición:
SELECT LISTAGG(
DEPARTMENT_NAME, ', ')
WITHIN GROUP
(ORDER BY DEPARTMENT_NAME) DEPT
FROM DEPARTMENTS;

-- Single line results
= Accounting, Administration, Benefits, Construction
No
GROUP_CONCAT
Usa la función GROUP_CONCAT de MySQL para mostrar resultados similares a los de Oracle. Verás diferencias de sintaxis en ciertos casos:
SELECT GROUP_CONCAT(
DEPARTMENT_NAME ORDER BY DEPARTMENT_NAME SEPARATOR ', ') DEPT
FROM DEPARTMENTS;

-- Single line results
= Accounting, Administration, Benefits, Construction
Recuperación de Oracle 12c
Función de Oracle Implementación o especificación de la función
de Oracle
Equivalente
de MySQL
Función correspondiente de MySQL Implementación o especificación de funciones de MySQL
FETCH
Recupera filas de datos del conjunto de resultados de una consulta de varias filas:
SELECT * FROM
EMPLOYEES
FETCH FIRST 10 ROWS ONLY;
No LIMIT Usa la cláusula LIMIT de MySQL para recuperar solo un conjunto específico de registros:
SELECT * FROM
EMPLOYEES
LIMIT 10;

Filtrado básico, operadores y subconsultas

Durante la conversión, el filtrado básico, las funciones del operador y las subconsultas son relativamente sencillas y no requieren ningún esfuerzo adicional.

Notas de la conversión

Examina y aborda los formatos de fecha porque los formatos de Oracle y MySQL muestran diferentes resultados predeterminados:

  • La función SYSDATE de Oracle muestra 01-AUG-19 de forma predeterminada.
  • La función SYSDATE() de MySQL muestra 2019-08-01 12:04:05 de forma predeterminada.
  • Los formatos de fecha y hora se pueden configurar mediante las funciones [DATE_FORMAT](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format) de MySQL o [STR_TO_DATE](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_str-to-date).
Función o subconsulta de Oracle Equivalente de MySQL Función o subconsulta correspondiente de MySQL Implementación o especificación de funciones de MySQL
EXISTS/NOT EXISTS
EXISTS/NOT EXISTS
SELECT * FROM DEPARTMENTS D
WHERE EXISTS (SELECT 1
              FROM EMPLOYEES E
              WHERE
              E.DEPARTMENT_ID =
              D.DEPARTMENT_ID);
IN/NOT IN
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
LIKE/NOT LIKE
SELECT * FROM EMPLOYEES
WHERE FIRST_NAME LIKE '_e_n%';
BETWEEN/NOT BETWEEN
BETWEEN/NOT BETWEEN
SELECT * FROM EMPLOYEES
WHERE EXTRACT(YEAR FROM HIRE_DATE)
NOT BETWEEN 2001 and 2004;
AND/OR
AND/OR
SELECT * FROM EMPLOYEES
WHERE DEPARTMENT_ID IN(100, 101)
AND (SALARY >= 1000 OR HIRE_DATE <= '2006-02-05');
SubQuery
SubQuery
MySQL admite subconsultas en el nivel SELECT, para declaraciones JOIN y a fin de filtrar en las 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 Operadores MySQL admite todos los operadores básicos:
> | >= | < | <= | = | <> | !=

Funciones analíticas (o funciones analíticas y de clasificación)

Las funciones analíticas de Oracle amplían la funcionalidad de las funciones analíticas de SQL estándar, ya que proporcionan capacidades para calcular valores agregados basados en un grupo de filas. Estas funciones se pueden aplicar a conjuntos de resultados con particiones lógicas dentro del alcance de una sola expresión de consulta. Por lo general, se usan en combinación con informes de inteligencia empresarial y estadísticas, con el potencial de aumentar el rendimiento de las consultas como alternativa a fin de lograr el mismo resultado con un código SQL más analítico.

Notas de la conversión

  • La versión 5.7 de MySQL no proporciona funciones analíticas para admitir una conversión de instrucciones de SQL sencilla. Sin embargo, esta funcionalidad se agregó de forma parcial en MySQL versión 8, lo que hace que la conversión de funciones analíticas sea un punto a tener en cuenta. Es probable que esto requiera esfuerzo manual en el proceso de migración.
  • Una solución opcional es volver a escribir el código para quitar el uso de funciones analíticas, revertir a soluciones de código SQL más tradicionales o mover esta lógica a una capa de aplicación.

En la siguiente tabla, se enumeran las funciones analíticas comunes de Oracle.

Familia de funciones Funciones relacionadas Compatible con MySQL 5.7
Analíticas y de clasificación
RANK
AVERAGE_RANK
DENSE_RANK
RANK ROW_NUMBER
PERCENT_RANK
CUME_DIST
NTILE
FIRST_VALUE
LAST_VALUE
OVER (PARTITION BY...)
No
Jerárquicas
CONNECT BY
HIER_ANCESTOR
HIER_CHILD_COUNT
HIER_DEPTH
HIER_LEVEL
HIER_ORDER
HIER_PARENT
HIER_TOP
No
Lag
LAG
LAG_VARIANCE LAG_VARIANCE_PERCENT LEAD
LEAD_VARIANCE LEAD_VARIANCE_PERCENT
No

Expresión de tabla común (CTE)

Las CTE proporcionan una forma de implementar la lógica del código secuencial a fin de reutilizar el código SQL que puede ser demasiado complejo o no eficiente para varios usos. Las CTE se pueden nombrar y, luego, usar en varias partes de una instrucción de SQL mediante la cláusula WITH.

Notas de la conversión

  • La versión 5.7 de MySQL no admite CTE, pero la versión 8 de MySQL sí.
  • Como una solución alternativa, usa tablas derivadas o SubQueries, o reescribe la instrucción de SQL para eliminar la funcionalidad de CTE.

Ejemplos

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;

Declaración MERGE

La declaración MERGE (o UPSERT) proporciona un medio para especificar instrucciones de SQL individuales que realizan operaciones DML de forma condicional en una operación MERGE, en lugar de una sola operación DML, que se ejecuta por separado. Selecciona registros de la tabla de origen y, luego, especifica una estructura lógica a fin de realizar de forma automática varias operaciones DML en la tabla de destino. Esta función te ayuda a evitar el uso de varias inserciones, actualizaciones o eliminaciones. Ten en cuenta que MERGE es una declaración determinista, lo que significa que una vez que la declaración MERGE procesa una fila, no se puede volver a procesar mediante la misma declaración MERGE.

Notas de la conversión

A diferencia de Oracle, la versión 5.7 de MySQL no admite la funcionalidad MERGE. Para simular de forma parcial la funcionalidad de MERGE, MySQL proporciona las instrucciones REPLACE y INSERT… ON DUPLICATE KEY UPDATE:

  • REPLACE: Funciona de la misma manera que una declaración INSERT, excepto que si una fila anterior de la tabla tiene el mismo valor que una fila nueva para un índice PRIMARY KEY o UNIQUE, la fila anterior se borra antes de insertar la fila nueva.

  • INSERT… ON DUPLICATE KEY UPDATE: Si una fila insertada causara un valor duplicado en un índice PRIMARY KEY o UNIQUE, se produce un UPDATE de la fila anterior para eliminar la excepción de clave duplicada, por ejemplo:

    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;
    

Otra solución sería convertir la funcionalidad de MERGE en un procedimiento almacenado para administrar las operaciones de DML, mediante comandos INSERT, UPDATE y DELETE con excepciones y manejo de duplicaciones.

Sugerencias de instrucciones de SQL

Oracle proporciona una gran colección de sugerencias de consulta de SQL que permite a los usuarios influir en el comportamiento del optimizador y en su toma de decisiones, con el objetivo de producir planes de ejecución de consultas más eficientes. Oracle admite más de 60 sugerencias de bases de datos diferentes. MySQL proporciona un conjunto limitado de sugerencias de consulta.

En general, la versión 5.7 de MySQL admite dos tipos de sugerencias de consulta: INDEX HINTS y OPTIMIZER HINTS. Las sugerencias del optimizador de MySQL proporcionan la capacidad de controlar el comportamiento del optimizador dentro de instrucciones de SQL individuales, por ejemplo:

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

MySQL MySQL

Nombre de la sugerencia Descripción general de la sugerencia Alcances aplicables
BKA, NO_BKA
Afecta el procesamiento de unión de acceso a las claves por lotes Bloque de consultas, tabla
BNL, NO_BNL
Afecta el procesamiento de unión de bucle anidado de bloque Bloque de consultas, tabla
MAX_EXECUTION_TIME
Limita el tiempo de ejecución de la declaración Global
MRR, NO_MRR
Afecta la optimización de lectura en varios rangos Tabla, índice
NO_ICP
Afecta la optimización de pushdown de la condición del índice Tabla, índice
NO_RANGE_OPTIMIZATION
Afecta la optimización del rango Tabla, índice
QB_NAME
Asigna un nombre al bloque de consulta Bloque de consulta
SEMIJOIN, NO_SEMIJOIN
Afecta las estrategias de semiunión Bloque de consulta
SUBQUERY
Afecta la materialización, estrategias de SubQuery IN a EXISTS. Bloque de consulta

Las sugerencias de índice de MySQL proporcionan al optimizador información sobre cómo elegir índices durante el procesamiento de consultas. Las palabras clave USE, FORCE o IGNORE se usan para controlar el proceso de uso del índice del optimizador, por ejemplo:

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

Notas de la conversión

Debido a que existen diferencias fundamentales entre Oracle y el optimizador de MySQL, y dado que existe alguna superposición entre las sugerencias de consulta de Oracle y MySQL, recomendamos que conviertas cualquier instrucción de SQL de Oracle que contenga sugerencias de consulta no especificadas sobre la base de datos de MySQL de destino.

Realiza ajustes de rendimiento de MySQL a través de herramientas de MySQL (por ejemplo, MySQL Workbench para paneles de rendimiento en tiempo real), y características como examinar consultas mediante planes de ejecución y ajustar la instancia o los parámetros de sesión según el caso práctico.

Planes de ejecución

El objetivo principal de los planes de ejecución es proporcionar una mirada interna a las elecciones que realiza el optimizador de consultas para acceder a los datos de la base de datos. El optimizador de consultas genera planes de ejecución para las declaraciones SELECT, INSERT, UPDATE y DELETE para los usuarios de la base de datos, lo que también permite que los administradores tengan una mejor visión de las consultas y operaciones de DML específicas. Son útiles en especial cuando necesitas ajustar el rendimiento de las consultas, por ejemplo, para determinar el rendimiento del índice o determinar si faltan índices que deben crearse.

Los planes de ejecución pueden verse afectados por los volúmenes de datos, las estadísticas de datos y los parámetros de instancia (parámetros globales o de sesión).

Consideraciones sobre las conversiones

Los planes de ejecución no son objetos de base de datos que se deban migrar; en su lugar, son una herramienta para analizar las diferencias de rendimiento entre Oracle y MySQL que ejecutan la misma declaración en conjuntos de datos idénticos.

MySQL no admite la misma sintaxis, funcionalidad o salida del plan de ejecución que Oracle.

Ejemplos

Plan de ejecución de 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 | ---------------------------------------------------------------------------------------------
Plan de ejecución de 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 | +----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+

Procedimientos almacenados, funciones y activadores

PL/SQL es el lenguaje de procedimiento extendido de Oracle que se usa para crear, almacenar y aplicar soluciones basadas en código dentro de la base de datos. En general, las funciones y los procedimientos almacenados en la base de datos son elementos de código que constan de ANSI SQL y del lenguaje de procedimiento extendido de SQL, por ejemplo, PL/SQL para Oracle, PL/pgSQL para PostgreSQL, y lenguaje de procedimiento de MySQL para MySQL. MySQL usa el mismo nombre que la base de datos para su propio lenguaje de procedimiento extendido.

El propósito de estos procedimientos almacenados y funciones es proporcionar soluciones para aquellos requisitos que son más adecuados para ejecuciones desde la base de datos y no desde la aplicación (por ejemplo, rendimiento, compatibilidad y seguridad). Aunque los procedimientos almacenados y las funciones usan PL/SQL, los procedimientos almacenados se usan en especial para realizar operaciones DDL/DML, y las funciones se usan en especial a fin de realizar cálculos con el objetivo de mostrar resultados específicos.

Lenguaje de procedimiento de PL/SQL a MySQL

Desde la perspectiva de la migración de código de PL/SQL a MySQL, la implementación de procedimientos de MySQL es diferente de la de Oracle. Por lo tanto, se requiere la migración de código para convertir la funcionalidad de PL/SQL de Oracle en procedimientos almacenados y funciones en MySQL. Además, MySQL no es compatible con Oracle Package y Package Body, por lo que, cuando realices la conversión de código, conviértelos en unidades individuales de código de MySQL (o analízalos). Ten en cuenta que los procedimientos almacenados y las funciones de MySQL también se denominan routines.

Propietario de objetos de código

En Oracle, el propietario de un procedimiento almacenado o una función es un usuario específico. En MySQL, el propietario es un esquema específico (creado en una base de datos por un usuario de la base de datos).

Seguridad y privilegios de objetos de código

En Oracle, para crear un procedimiento almacenado o una función, el usuario debe tener el privilegio del sistema CREATE PROCEDURE (a fin de crear procedimientos o funciones con otros usuarios, los usuarios de la base de datos deben tener el privilegio CREATE ANY PROCEDURE). Para ejecutar un procedimiento almacenado o una función, los usuarios de la base de datos deben tener el privilegio EXECUTE.

En MySQL, para crear un elemento de código, el usuario debe tener el privilegio CREATE ROUTINE y el privilegio EXECUTE para ejecutar. La cláusula DEFINER de MySQL define el creador del usuario para el objeto de código, y el usuario debe tener los privilegios adecuados, como CREATE ROUTINE.

Sintaxis de funciones y procedimiento almacenados de MySQL

En el siguiente ejemplo, se muestra la sintaxis de la función y el procedimiento almacenado de 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