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

Este documento forma parte de una serie que proporciona información y directrices clave relacionadas con la planificación y la realización de migraciones de bases de datos Oracle® 11g/12c a instancias de segunda generación de Cloud SQL para MySQL versión 5.7. La serie incluye las siguientes partes:

Consultas

Oracle y Cloud SQL para MySQL admiten el estándar ANSI SQL. Por lo general, la migración de instrucciones SQL es sencilla si solo se usan elementos de sintaxis básicos (por ejemplo, si no se especifican funciones escalares ni ninguna otra función ampliada de Oracle). En la siguiente sección se describen los elementos de consulta de Oracle habituales y sus equivalentes en Cloud SQL para MySQL.

Sintaxis básica de SELECT y FROM

Nombre de la función o de la sintaxis de Oracle Descripción general o implementación de Oracle Compatibilidad con MySQL Solución correspondiente o alternativa de MySQL
Sintaxis básica de SQL para recuperar datos
SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
SELECT para la 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
Nombre de la tabla
distinción entre mayúsculas y minúsculas
No se distingue entre mayúsculas y minúsculas
(por ejemplo, el nombre de la tabla puede ser orders o ORDERS).
No Distinguen entre mayúsculas y minúsculas según el nombre de tabla definido (por ejemplo, el nombre de tabla solo puede ser orders o ORDERS).

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

  • Vistas insertadas
    • Las vistas insertadas (también conocidas como tablas derivadas) son instrucciones SELECT que se encuentran en la cláusula FROM y se usan como subconsultas.
    • Las vistas insertadas pueden simplificar las consultas complejas eliminando cálculos compuestos o operaciones de unión, al tiempo que condensan varias consultas independientes en una sola consulta simplificada.
    • Nota sobre las conversiones: Las vistas insertadas de Oracle no requieren el uso de alias, mientras que MySQL sí requiere alias específicos para cada vista insertada.

En la siguiente tabla se muestra un ejemplo de conversión de Oracle a MySQL como vista insertada.

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

La salida es similar a la 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 insertada:
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

Añadir un alias a la vista insertada:
mysql> SELECT FIRST_NAME,
              DEPARTMENT_ID,
              SALARY,
              DATE_COL
       FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL) AS A1;

La salida es similar a la 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

MySQL admite las instrucciones JOIN de Oracle JOIN, excepto la cláusula FULL JOIN. Además, las instrucciones JOIN de MySQL admiten el uso de sintaxis alternativas, como la cláusula USING, la cláusula WHERE en lugar de la cláusula ON y el uso de SUBQUERY en la instrucción JOIN.

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

Tipo de JOIN de Oracle Admitido por 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 solucionar este problema, puedes usar UNION con las instrucciones 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 instrucciones SELECT y elimina los registros duplicados.
  • UNION ALL: adjunta los conjuntos de resultados de dos o más instrucciones SELECT sin eliminar los registros duplicados.
  • INTERSECT: devuelve la intersección de dos o más SELECT instrucciones solo si existe un registro en ambos conjuntos de datos.
  • MINUS: compara dos o más instrucciones SELECT y devuelve solo las filas distintas de la primera consulta que no devuelven las otras instrucciones.

Notas de conversión

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

Ejemplos

Función de Oracle Implementación de Oracle Compatibilidad con MySQL Solución correspondiente o alternativa 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 amplia lista de funciones escalares (de una sola fila) y de agregación. Algunas funciones de MySQL son similares a sus equivalentes de Oracle (por nombre y funcionalidad, o con un nombre diferente pero con una funcionalidad similar). Aunque las funciones de MySQL pueden tener nombres idénticos a sus equivalentes de Oracle, pueden mostrar funcionalidades diferentes.

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

Funciones de caracteres
Función de Oracle Especificación o implementación de funciones de Oracle Equivalente de MySQL Función correspondiente de MySQL Especificación o implementación de la función MySQL
CONCAT(str1,str2)
Devuelve str1 concatenado con str2:
CONCAT('A', 1) = A1
CONCAT
Equivalente a Oracle:
CONCAT('A', 1) = A1
LOWER/UPPER
Devuelve el carácter con todas las letras en minúsculas o mayúsculas:
LOWER('SQL') = sql
LOWER/UPPER
Equivalente a Oracle:
LOWER('SQL') = sql
LPAD/RPAD(expr1,n,expr2)
Devuelve expr1, con relleno a la izquierda o a la derecha hasta alcanzar una longitud de n caracteres con la secuencia de caracteres de expr2:
LPAD('A',3,'*') = **A
LPAD/RPAD
Equivalente a Oracle:
LPAD('A',3,'*') = **A
SUBSTR(char,p,n)
Devuelve una parte de char, que empieza en la posición del carácter p y tiene una longitud de n caracteres:
SUBSTR('MySQL', 3, 3)
= SQL
SUBSTR(char,p,n)
Equivalente a Oracle:
SUBSTR('MySQL', 3, 3)
= SQL
INSTR(index,str)
Devuelve la posición (índice) de la cadena str:
INSTR('MySQL', 'y')
= 2
INSTR
Equivalente a Oracle:
INSTR('MySQL', 'y')
= 2
REPLACE(char,str1,str2)
Devuelve el carácter con cada instancia de una cadena de búsqueda sustituida por una cadena de sustitución:
REPLACE('ORADB', 'ORA', 'MySQL')

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

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

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

TRIM(' MySQL ') = MySQL
LTRIM/RTRIM(str)
Elimina del extremo izquierdo o derecho de la cadena todos los caracteres que aparezcan en la búsqueda:
LTRIM('   MySQL', ' ')
= MySQL
Parcialmente
LTRIM/RTRIM(str)
Función R/LTRIM de Oracle, excepto una sustitución del parámetro (espacio en blanco o cadena). MySQL R/LTRIM solo elimina los espacios en blanco y acepta únicamente la cadena de entrada:
LTRIM('   MySQL')
= MySQL
ASCII(char)
Devuelve la representación decimal en el conjunto 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)
Devuelve el valor del código ASCII, que es un valor numérico entre 0 y 225, de un carácter:
CHR(65) = A
Parcialmente con un nombre de función diferente
CHAR(char)
MySQL usa la función CHAR para la misma función, por lo que debes modificar el nombre de la función:
CHAR(65) = A
LENGTH(str)
Devuelve la longitud de una cadena determinada:

LENGTH ('MySQL') = 5
LENGTH(str)
Equivalente a Oracle:
LENGTH('MySQL') = 5
REGEXP_REPLACE(str1,expr,str2)
Buscar una cadena con un patrón de expresión regular:
REGEXP_REPLACE('John', '[hn].', '1') = Jo1
No N/A Solo se admite a partir de la versión 8 de MySQL. Como solución alternativa, usa la función REPLACE si es posible o convierte a la capa de aplicación.
REGEXP_SUBSTR(str,expr)
Amplía la funcionalidad de la función SUBSTR buscando en una cadena un patrón de expresión regular:
REGEXP_SUBSTR('https://console.cloud.google.com/sql/instances','https://([[:alnum:]]+\.?){3,4}/?')
= https://console.cloud.google.com/
No N/A Solo se admite a partir de la versión 8 de MySQL. Como solución alternativa, usa la función SUBSTR si es posible o convierte la función a la capa de aplicación.
REGEXP_COUNT(str,expr)
Devuelve el número de veces que aparece un patrón en una cadena de origen. No N/A Para encontrar una solución alternativa, convierte la función en la capa de aplicación.
REGEXP_INSTR(index,expr)
Busca una posición de cadena (índice) para un patrón de expresión regular. No N/A Solo se admite a partir de la versión 8 de MySQL.
REVERSE(str)
Devolver una cadena invertida
REVERSE('MySQL')
= LQSyM
REVERSE
Equivalente a Oracle:
REVERSE('MySQL')
= LQSyM
Funciones numéricas
Función de Oracle Especificación o implementación de funciones de Oracle Equivalente de MySQL Función correspondiente de MySQL Especificación o implementación de la función MySQL
ABS(n)
Valor absoluto de n:
ABS(-4.6) = 4.6
ABS
Equivalente a Oracle:
ABS(-4.6) = 4.6
CEIL(n)
Devuelve el menor número entero que sea mayor o igual que n:
CEIL(21.4) = 22
CEIL
Equivalente a Oracle:
CEIL(21.4) = 22
FLOOR(n)
Devuelve el mayor número entero igual o inferior a n:
FLOOR(-23.7) = -24
FLOOR
Equivalente a Oracle:
FLOOR(-23.7) = -24
MOD(m,n)
Devuelve el resto de m dividido entre n:
MOD(10, 3) = 1
MOD(m,n)
Equivalente a Oracle:
MOD(10,3) = 1
ROUND(m,n)
Devuelve m redondeado a n decimales 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)
Devuelve n1 truncado a n2 decimales:
TRUNC(99.999) = 99
TRUNC(99.999,0) = 99
Parcialmente 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 Especificación o implementación de funciones de Oracle Equivalente de MySQL Función correspondiente de MySQL Especificación o implementación de la función MySQL
SYSDATE
Devuelve la fecha y la hora actuales definidas en el sistema operativo en el que reside el servidor de la base de datos:
SELECT SYSDATE
FROM DUAL
= 31-JUL-2019
Parcialmente
SYSDATE()
La función SYSDATE() de MySQL debe incluir paréntesis y devuelve 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

Tenga en cuenta que el formato de fecha y hora se puede cambiar a nivel de sesión.
SYSTIMESTAMP
Devuelve la fecha del sistema, incluidos los segundos fraccionarios y la zona horaria:
SELECT SYSTIMESTAMP FROM DUAL
= 01-JAN-19 07.37.11.622187000 AM +00:00
Parcialmente con un nombre de función diferente
CURRENT_TIMESTAMP
MySQL devuelve un formato de fecha y hora diferente al de Oracle. Es necesario aplicar un formato de fecha (o usar otra función de fecha) para que coincida con el formato de fecha y hora original:
SELECT CURRENT_TIMESTAMP
FROM DUAL
= 2019-01-31 06:55:07
LOCAL_TIMESTAMP
Devuelve la fecha y la hora actuales en la zona horaria de la sesión como un valor de tipo de datos TIMESTAMP:
SELECT LOCAL_TIMESTAMP
FROM DUAL
= 01-JAN-19 10.01.10.123456 PM
Parcialmente con un formato de fecha y hora diferente.
LOCAL_TIMESTAMP
MySQL devuelve un formato de fecha y hora diferente al de Oracle. Es necesario aplicar un formato de fecha y hora (o usar otra función de fecha) para que coincida con el formato de fecha y hora original:
SELECT LOCAL_TIMESTAMP
FROM DUAL
= 2019-01-01 10:01:01.0
CURRENT_DATE
Devuelve la fecha actual en la zona horaria de la sesión:
SELECT CURRENT_DATE
FROM DUAL
= 31-JAN-19
Parcialmente con un formato de fecha y hora diferente
CURRENT_DATE
MySQL devuelve un formato de fecha y hora diferente al de Oracle. Es necesario aplicar un formato de fecha y hora (o usar otra función de fecha) para que coincida con el formato de fecha y hora original:
SELECT CURRENT_DATE
FROM DUAL
= 2019-01-31
CURRENT_TIMESTAMP
Devuelve la fecha y la 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
Parcialmente con un formato de fecha y hora diferente
CURRENT_TIMESTAMP
MySQL devuelve un formato de fecha y hora diferente al de Oracle. Es necesario aplicar un formato de fecha y hora (o usar otra función de fecha) para que coincida con el formato de fecha y hora original:
SELECT CURRENT_TIMESTAMP
FROM DUAL
= 2019-01-31 06:55:07
ADD_MONTHS
Devuelve la fecha más los meses enteros:
ADD_MONTHS(SYSDATE, 1)
= 31-JAN-19
Parcialmente con un nombre de función diferente
ADDDATE
Para conseguir la misma función, MySQL usa la ADDDATEfunción:
ADDDATE(SYSDATE(), 1)
= 2019-08-01 06:42:49.0

De forma predeterminada, MySQL devuelve una fecha, una hora, un intervalo o un formato distintos a los de Oracle. Es necesario aplicar el formato de fecha y hora (o una función de fecha diferente) para que coincida con el formato de fecha y hora original.
EXTRACT(parte de la fecha) Devuelve el valor de un campo de fecha y hora especificado a partir de una expresión de fecha y hora o de 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
Devuelve la fecha del último día del mes:
LAST_DAY('01-JAN-2019')
= 31-JAN-19
Parcialmente con un formato de fecha y hora diferente
LAST_DAY
MySQL devuelve un formato de fecha y hora diferente al de Oracle. Es necesario aplicar un formato de fecha y hora (o usar otra función de fecha) para que coincida con el formato de fecha y hora original:
LAST_DAY('2019-01-01')
= 2019-01-31
MONTH_BETWEEN
Devuelve el número de meses entre las fechas fecha1 y fecha2:
MONTHS_BETWEEN(
SYSDATE, SYSDATE-60)
= 1.96
Parcialmente con un nombre de función diferente
PERIOD_DIFF(date1,date2)
La función PERIOD_DIFF de MySQL devuelve la diferencia en meses como un número entero entre dos periodos (con el formato YYMM o YYYYMM):
PERIOD_DIFF(
'201903', '201901')
= 2

Para obtener los mismos valores que la función MONTH_BETWEEN de Oracle, se necesitará una conversión más específica.
TO_CHAR (fecha/hora) Convierte un tipo de datos de fecha, hora o marca de tiempo en un valor del tipo de datos VARCHAR2 con el formato especificado por el formato de fecha:
TO_CHAR(
SYSDATE,'DD-MM-YYYY HH24:MI:SS')
= 01-01-2019 10:01:01
Parcialmente con un nombre de función diferente
DATE_FORMAT
La función DATE_FORMAT de MySQL da formato a una fecha según lo especificado por 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 Especificación o implementación de funciones de Oracle Equivalente de MySQL Función correspondiente de MySQL Especificación o implementación de la función MySQL
DECODE
Compara una expresión con cada valor de búsqueda uno por uno mediante la función de una instrucción IF-THEN-ELSE. No
CASE
Usa la instrucción CASE de MySQL para conseguir una función similar.
DUMP
Devuelve un valor VARCHAR2 que contiene el código del tipo de datos, la longitud en bytes y la representación interna de una expresión determinada. No N/A No es compatible.
ORA_HASH
Calcula un valor hash para una expresión determinada. No
MD5/SHA
Usa MD5 de MySQL para la suma de comprobación de 128 bits o la función SHA para la suma de comprobación de 160 bits para generar valores hash.
Funciones de conversión
Función de Oracle Especificación o implementación de funciones de Oracle Equivalente de MySQL Función correspondiente de MySQL Especificación o implementación de la función MySQL
CAST
Convierte un tipo de datos integrado o un valor de tipo colección en otro tipo de datos integrado o valor de tipo colección:
CAST('1' as int) + 1
= 2
Parcialmente
CAST
La función CAST de MySQL es similar a la de Oracle, pero en algunos casos debe ajustarse en función de si se requiere una conversión explícita o implícita:
CAST('1' AS SIGNED) + 1
= 2
CONVERT
Convierte una cadena de caracteres de un conjunto de caracteres a 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 devolver los mismos resultados que Oracle:
CONVERT('Ä Ê Í A B C ' USING utf8)
= Ä Ê Í A B C
TO_CHAR
(cadena o número)
La función convierte un número o una fecha en una cadena:
TO_CHAR(22.73,'$99.9')
= $22.7
No
FORMAT
La función FORMAT de MySQL aplica el formato "#,###.##" a un número, lo redondea a un número determinado de decimales y, a continuación, devuelve el resultado como una cadena. 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 cadena 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
Parcialmente con un nombre de función y un formato de fecha y hora diferentes
STR_TO_DATE
La función STR_TO_DATE de MySQL toma una cadena y devuelve una fecha especificada por el formato de fecha y hora:
STR_TO_DATE(
'2019/01/01', '%Y/%m/%d')
= 2019-01-01
TO_NUMBER
Convierte una expresión en un valor de tipo de datos NUMBER:
TO_NUMBER('01234')
= 1234
No
CAST
Como alternativa, usa la función CAST de MySQL para devolver el mismo resultado que TO_NUMBER de Oracle:
CAST('01234' as SIGNED)
= 1234
Funciones SELECT condicionales
Función de Oracle Especificación o implementación de funciones de Oracle Equivalente de MySQL Función correspondiente de MySQL Especificación o implementación de la función MySQL
CASE
La instrucción CASE elige entre una secuencia de condiciones y ejecuta una instrucció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 de IF/ELSE gestión condicional dentro de la instrucción SELECT:
CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Funciones nulas
Función de Oracle Especificación o implementación de funciones de Oracle Equivalente de MySQL Función correspondiente de MySQL Especificación o implementación de la función MySQL
COALESCE
Devuelve la primera expresión no nula de 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 devuelve un valor nulo. Si no son iguales, la función devuelve expr1:
NULLIF('1', '2')
= a
NULLIF
Equivalente a Oracle:
NULLIF('1', '2')
= a
NVL
Sustituye el valor nulo (que se devuelve como un espacio en blanco) por una cadena en los resultados de una consulta:
NVL(null, 'a')
= a
No
IFNULL
La función equivalente en MySQL sería la función IFNULL , que sustituye los valores nulos por una cadena determinada:
IFNULL(null, 'a')
= a
NVL2
Determina el valor devuelto por una consulta en función de si una expresión
especificada es nula o no.
No
CASE
La instrucción CASE
elige entre una secuencia de condiciones y ejecuta una instrucción correspondiente:
CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Funciones de entorno e identificador
Función de Oracle Especificación o implementación de funciones de Oracle Equivalente de MySQL Función correspondiente de MySQL Especificación o implementación de la función MySQL
SYS_GUID
Genera y devuelve un identificador único global (valor RAW) compuesto por 16 bytes:
SELECT SYS_GUID()
FROM DUAL
= 8EFA4A31468B4C6DE05011AC0200009E
No REPLACE y UUID Para solucionar este problema, usa las funciones REPLACE y UUID de MySQL para simular la función SYS_GUID de Oracle:
REPLACE(
UUID(), '-', '')
UID
Devuelve un número entero que identifica de forma única al usuario de la sesión (el usuario que ha iniciado sesión):

SELECT UID FROM DUAL
= 43
No N/A N/A
USER
Devuelve el nombre de usuario de la sesión actual:
SELECT USER FROM DUAL
= UserName
Parcialmente
USER + INSTR + SUBSTR
La función USER de MySQL devuelve el nombre de usuario junto con el servidor de conexión (root@IP). Para obtener solo el nombre de usuario, utiliza funciones complementarias:
SELECT
SUBSTR(USER(), 1, INSTR(USER(), '@') -1) FROM DUAL
= root
USERENV
Devuelve información sobre la sesión del usuario actual con la configuración de parámetros actual:
SELECT USERENV('LANGUAGE')
FROM DUAL
= ENGLISH_AMERICA.AL32UTF8
No
SHOW SESSION
VARIABLES
Usa la instrucció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 de cada tabla un ROWID único para identificar la fila en la tabla. ROWID es la dirección de la fila que contiene el número del 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 función con otras funciones de MySQL.
ROWNUM
Devuelve un número que representa el orden en el que Oracle selecciona una fila de una tabla o de tablas combinadas. No N/A Si es posible, intenta emular la misma función con otras funciones o variables de sesión de MySQL.
Funciones de agregación (grupo)
Función de Oracle Especificación o implementación de la función Oracle
Equivalente de MySQL
Función correspondiente de MySQL Especificación o implementación de la función MySQL
AVG
Devuelve el valor medio de una columna o una expresión.
AVG
Equivalente a Oracle
COUNT
Devuelve el número de filas devueltas por una consulta.
COUNT
Equivalente a Oracle
COUNT
(DISTINCT)
Devuelve el número de valores únicos de la columna o expresión.
COUNT
(DISTINCT)
Equivalente a Oracle
MAX
Devuelve el valor máximo de una columna o una expresión.
MAX
Equivalente a Oracle
MIN
Devuelve el valor mínimo de una columna o una expresión.
MIN
Equivalente a Oracle
SUM
Devuelve la suma del valor de una columna o una expresión.
SUM
Equivalente a Oracle
LISTAGG
Muestra los datos de cada grupo en una sola fila especificada en la cláusula ORDER BY concatenando los valores de la columna de medida:
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 obtener resultados similares a los de Oracle. Ten en cuenta que la sintaxis es diferente en algunos casos:
SELECT GROUP_CONCAT(
DEPARTMENT_NAME ORDER BY DEPARTMENT_NAME SEPARATOR ', ') DEPT
FROM DEPARTMENTS;

-- Single line results
= Accounting, Administration, Benefits, Construction
Obtención de Oracle 12c
Función de Oracle Especificación o implementación de la función Oracle
Equivalente de MySQL
Función correspondiente de MySQL Especificación o implementación de la función MySQL
FETCH
Obtiene 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 obtener 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 de operador y las subconsultas son relativamente sencillos y requieren poco o ningún esfuerzo adicional.

Notas de conversión

Examina y corrige los formatos de fecha, ya que los formatos de Oracle y MySQL devuelven resultados predeterminados diferentes:

  • La función SYSDATE de Oracle devuelve 01-AUG-19 de forma predeterminada.
  • La función SYSDATE() de MySQL devuelve 2019-08-01 12:04:05 de forma predeterminada.
  • Los formatos de fecha y hora se pueden definir con las funciones de MySQL [DATE_FORMAT](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format) 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 Especificación o implementación de la función 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 las instrucciones JOIN y para 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 de ventana y de clasificación)

Las funciones analíticas de Oracle amplían la funcionalidad de las funciones analíticas de SQL estándar al proporcionar funciones para calcular valores agregados basados en un grupo de filas. Estas funciones se pueden aplicar a conjuntos de resultados particionados lógicamente dentro del ámbito de una sola expresión de consulta. Se suelen usar en combinación con informes y analíticas de inteligencia empresarial, con el potencial de mejorar el rendimiento de las consultas como alternativa para conseguir el mismo resultado con un código SQL no analítico más complejo.

Notas de conversión

  • La versión 5.7 de MySQL no proporciona funciones analíticas para admitir una conversión sencilla de instrucciones SQL. Sin embargo, esta función se añadió parcialmente en MySQL 8, por lo que la conversión de funciones analíticas es un aspecto que se debe tener en cuenta y que probablemente requiera un esfuerzo manual en el proceso de migración.
  • Otra solución opcional es reescribir el código para eliminar el uso de funciones analíticas, volver 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árquico
CONNECT BY
HIER_ANCESTOR
HIER_CHILD_COUNT
HIER_DEPTH
HIER_LEVEL
HIER_ORDER
HIER_PARENT
HIER_TOP
No
Retraso
LAG
LAG_VARIANCE LAG_VARIANCE_PERCENT LEAD
LEAD_VARIANCE LEAD_VARIANCE_PERCENT
No

Expresión de tabla común (CTE)

Las CTEs proporcionan una forma de implementar la lógica del código secuencial para reutilizar el código SQL que puede ser demasiado complejo o no eficiente para un uso múltiple. Las CTEs se pueden nombrar y, a continuación, usar varias veces en diferentes partes de una instrucción SQL mediante la cláusula WITH.

Notas de conversión

  • La versión 5.7 de MySQL no admite CTEs, pero la versión 8 de MySQL sí.
  • Para obtener una solución alternativa, usa tablas derivadas o subconsultas, o reescribe la instrucción SQL para eliminar la función 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;

Instrucción MERGE

La instrucción MERGE (o UPSERT) permite especificar instrucciones SQL únicas que realizan operaciones de DML de forma condicional en una operación MERGE, en lugar de una sola operación de DML que se ejecuta por separado. Selecciona registros de la tabla de origen y, a continuación, al especificar una estructura lógica, realiza automáticamente 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 instrucción determinista, lo que significa que, una vez que una fila se ha procesado con la instrucción MERGE, no se puede volver a procesar con la misma instrucción MERGE.

Notas de conversión

La versión 5.7 de MySQL no admite la función MERGE, a diferencia de Oracle. Para simular parcialmente la función MERGE, MySQL proporciona las instrucciones REPLACE y INSERT… ON DUPLICATE KEY UPDATE:

  • REPLACE: funciona de la misma forma que una instrucción INSERT, excepto que, si una fila antigua de la tabla tiene el mismo valor que una fila nueva para un índice PRIMARY KEY o UNIQUE, la fila antigua se elimina antes de insertar la nueva.

  • INSERT… ON DUPLICATE KEY UPDATE: Si una fila insertada provoca un valor duplicado en un índice PRIMARY KEY o UNIQUE, se produce una UPDATE de la fila antigua 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 función MERGE en un procedimiento almacenado para gestionar las operaciones de DML, usando los comandos INSERT, UPDATE y DELETE con gestión de excepciones y duplicaciones.

Pistas de instrucciones SQL

Oracle ofrece una gran colección de sugerencias de consultas SQL que permiten a los usuarios influir en el comportamiento del optimizador y en sus 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: OPTIMIZER HINTS y INDEX HINTS. Sugerencias del optimizador de MySQL te permiten controlar el comportamiento del optimizador en instrucciones SQL concretas. Por ejemplo:

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

Sugerencias de optimización disponibles en MySQL versión 5.7

Nombre de la pista Resumen de las pistas Permisos aplicables
BKA, NO_BKA
Afecta al procesamiento de la unión de acceso de clave por lotes Bloque de consulta, tabla
BNL, NO_BNL
Afecta al procesamiento de combinaciones de bucles anidados de bloques. Bloque de consulta, tabla
MAX_EXECUTION_TIME
Limita el tiempo de ejecución de las instrucciones. Global
MRR, NO_MRR
Afecta a la optimización de lectura de varios intervalos Tabla, índice
NO_ICP
Afecta a la optimización de la inserción de condiciones de índice Tabla, índice
NO_RANGE_OPTIMIZATION
Afecta a la optimización del intervalo Tabla, índice
QB_NAME
Asigna un nombre al bloque de consulta. Bloque de consulta
SEMIJOIN, NO_SEMIJOIN
Afecta a las estrategias de combinación semi-join Bloque de consulta
SUBQUERY
Afecta a la materialización y a las estrategias de subconsultas de IN a EXISTS. Bloque de consulta

Las sugerencias de índice de MySQL proporcionan al optimizador información sobre cómo elegir los índices durante el procesamiento de las 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 conversión

Debido a las diferencias fundamentales entre los optimizadores de Oracle y MySQL, y a que las sugerencias de consulta de Oracle y MySQL apenas se solapan, te recomendamos que conviertas cualquier instrucción SQL de Oracle que contenga sugerencias de consulta no especificadas en la base de datos MySQL de destino.

Ajusta el rendimiento de MySQL con herramientas de MySQL (por ejemplo, Workbench de MySQL para obtener paneles de rendimiento en tiempo real) y funciones como examinar consultas mediante planes de ejecución y ajustar los parámetros de la instancia o de la sesión según el caso práctico.

Planes de ejecución

El objetivo principal de los planes de ejecución es ofrecer una visión interna de las decisiones que toma 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 instrucciones SELECT, INSERT, UPDATE y DELETE de los usuarios de la base de datos, y también permite a los administradores tener una mejor visión de las consultas y las operaciones de DML específicas. Son especialmente útiles cuando necesitas ajustar el rendimiento de las consultas; por ejemplo, para determinar el rendimiento de los índices o para 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 la conversión

Los planes de ejecución no son objetos de base de datos que deban migrarse, sino una herramienta para analizar las diferencias de rendimiento entre Oracle y MySQL al ejecutar la misma instrucción en conjuntos de datos idénticos.

MySQL no admite la misma sintaxis, funcionalidad ni 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 procedimental ampliado de Oracle que se usa para crear, almacenar y aplicar soluciones basadas en código en la base de datos. En general, los procedimientos almacenados y las funciones de las bases de datos son elementos de código que constan de ANSI SQL y un lenguaje procedimental ampliado de SQL, como PL/SQL para Oracle, PL/pgSQL para PostgreSQL y el lenguaje procedimental de MySQL para MySQL. MySQL usa el mismo nombre que la base de datos para su propio lenguaje de procedimiento ampliado.

El objetivo de estos procedimientos y funciones almacenados es ofrecer soluciones para requisitos que se adapten mejor a la ejecución desde la base de datos y no desde la aplicación (por ejemplo, rendimiento, compatibilidad y seguridad). Aunque tanto los procedimientos almacenados como las funciones usan PL/SQL, los procedimientos almacenados se usan principalmente para realizar operaciones DDL o DML, y las funciones se usan principalmente para realizar cálculos y devolver resultados específicos.

PL/SQL a lenguaje de procedimientos de MySQL

Desde el punto de vista de la migración de código de Oracle PL/SQL a MySQL, la implementación de procedimientos de MySQL es diferente a la de Oracle. Por lo tanto, es necesario migrar el código para convertir la funcionalidad de PL/SQL de Oracle en procedimientos almacenados y funciones de MySQL. Además, MySQL no admite los paquetes ni los cuerpos de paquetes de Oracle, por lo que, cuando conviertas código, convierte estos elementos (o analízalos) en unidades individuales de código de MySQL. Ten en cuenta que los procedimientos almacenados y las funciones de MySQL también se denominan rutinas.

Propietario del objeto de código

En Oracle, el propietario de un procedimiento o una función almacenados 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).

Privilegios y seguridad de los objetos de código

En Oracle, para crear un procedimiento o una función almacenados, el usuario debe tener el privilegio de sistema CREATE PROCEDURE (para crear procedimientos o funciones en 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 ejecutarlo. La cláusula DEFINER de MySQL define el creador del objeto de código y el usuario debe tener los privilegios adecuados, como CREATE ROUTINE.

Sintaxis de procedimientos y funciones almacenados de MySQL

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