Migrer des utilisateurs Oracle vers Cloud SQL pour MySQL : requêtes, procédures stockées, fonctions et déclencheurs

Ce document fait partie d'une série qui fournit des informations et des conseils clés sur la planification et l'exécution des migrations de base de données Oracle® 11g/12c vers des instances Cloud SQL pour MySQL de deuxième génération, version 5.7. La série comprend les parties suivantes :

Requêtes

Oracle et Cloud SQL pour MySQL sont compatibles avec la norme ANSI SQL. Il est généralement facile de migrer des instructions SQL en n'utilisant que des éléments de syntaxe de base (par exemple, sans spécifier de fonctions scalaires ni aucune autre fonctionnalité Oracle étendue). La section suivante aborde les éléments de requête Oracle courants et leurs équivalents dans Cloud SQL pour MySQL.

Syntaxe SELECT et FROM de base

Nom de la fonctionnalité ou syntaxe Oracle Présentation ou mise en œuvre dans Oracle Compatibilité avec MySQL Solution MySQL correspondante ou alternative
Syntaxe SQL de base pour la récupération de données

SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
Oui

SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
SELECT pour l'impression en sortie

SELECT 1 FROM DUAL
Oui

SELECT 1
OR
SELECT 1 FROM DUAL
Alias de colonne

SELECT COL1 AS C1
Oui

SELECT COL1 AS C1
OR
SELECT COL1 C1
Nom de la table
Sensibilité à la casse
Pas de sensibilité à la casse
(par exemple, le nom de la table peut être orders et/ou ORDERS).
Non Sensibilité à la casse en fonction du nom de table défini (par exemple, le nom de la table ne peut être que orders ou ORDERS).

Apprenez-en davantage sur la syntaxe SELECT de MySQL.

  • Vues intégrées
    • Les vues intégrées (également appelées tables dérivées) sont des instructions SELECT, situées dans la clause FROM et utilisées en tant que sous-requêtes.
    • Les vues intégrées peuvent simplifier les requêtes complexes en supprimant les calculs composés ou en éliminant les opérations de jointure, tout en regroupant plusieurs requêtes distinctes en une seule requête simplifiée.
    • Remarque relative aux conversions : Les vues intégrées Oracle ne nécessitent pas l'utilisation d'alias, tandis que MySQL requiert l'utilisation d'alias spécifiques pour chaque vue intégrée.

Le tableau suivant présente un exemple de conversion d'Oracle vers MySQL, sous la forme d'une vue intégrée.

Oracle 11g/12c

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

Le résultat ressemble à ce qui suit :

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 pour MySQL 5.7
Sans alias pour la vue intégrée :

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

Ajout d'un alias à la vue intégrée :

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

Le résultat ressemble à ce qui suit :

+-------------+---------------+----------+---------------------+
| 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 |

Instructions JOIN

Les instructions Oracle JOIN sont compatibles avec les instructions MySQL JOIN, à l'exception de la clause FULL JOIN. En outre, les instructions MySQL JOIN acceptent l'utilisation d'une syntaxe alternative, telle que la clause USING, la clause WHERE au lieu de la clause ON, ainsi que l'utilisation de SUBQUERY dans l'instruction JOIN.

Le tableau suivant présente un exemple de conversion JOIN.

Type d'instruction JOIN Oracle Compatible avec MySQL Syntaxe JOIN MySQL

INNER JOIN
Oui

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

CROSS JOIN
Oui

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

FULL JOIN
Non Pour contourner ce problème, envisagez d'utiliser UNION avec les instructions LEFT et RIGHT JOIN.

LEFT JOIN
[ OUTER ]
Oui

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

RIGHT JOIN
[ OUTER ]
Oui

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

SUBQUERY
Oui

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 et MINUS

MySQL n'est pas compatible avec les fonctions INTERSECT et MINUS Oracle, à l'exception des fonctions UNION et UNION ALL :

  • UNION : joint les ensembles de résultats d'au moins deux instructions SELECT et supprime les enregistrements en double.
  • UNION ALL : joint les ensembles de résultats d'au moins deux instructions SELECT sans éliminer les enregistrements en double.
  • INTERSECT : renvoie l'intersection de deux instructions SELECT ou plus uniquement si un enregistrement existe dans les deux ensembles de données.
  • MINUS : compare deux ou plusieurs instructions SELECT, et ne renvoie que des lignes distinctes de la première requête qui ne sont pas renvoyées par les autres instructions.

Notes de conversion

Lorsque vous convertissez des fonctions INTERSECT et MINUS Oracle en MySQL, utilisez des instructions JOIN ainsi que IN et EXISTS comme solution alternative.

Exemples

Fonction Oracle Mise en œuvre dans Oracle Compatibilité avec MySQL Solution MySQL correspondante ou alternative

UNION

SELECT COL1 FROM TBL1
UNION
SELECT COL1 FROM TBL2
Oui

SELECT COL1 FROM TBL1
UNION
SELECT COL1 FROM TBL2

UNION ALL

SELECT COL1 FROM TBL1
UNION ALL
SELECT COL1 FROM TBL2
Oui

SELECT COL1 FROM TBL1
UNION ALL
SELECT COL1 FROM TBL2

INTERSECT

SELECT COL1 FROM TBL1
INTERSECT
SELECT COL1 FROM TBL2
Non

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

MINUS

SELECT COL1 FROM TBL1
MINUS
SELECT COL1 FROM TBL2
Non

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

Fonctions scalaires (à une ligne) et de groupe

MySQL fournit une longue liste de fonctions scalaires (à une ligne) et d'agrégation. Certaines fonctions MySQL sont semblables à leurs équivalents Oracle (même nom et mêmes fonctionnalités, ou avec un nom différent, mais avec des fonctionnalités similaires). En revanche, certaines fonctions MySQL ayant des noms identiques à leurs équivalents Oracle peuvent présenter des fonctionnalités différentes.

Les tableaux suivants indiquent lorsque les fonctions MySQL et Oracle sont équivalentes (même nom et mêmes fonctionnalités, spécifié par "Oui") et lorsqu'une conversion est recommandée (tous les autres cas).

Fonctions de caractères
Fonction Oracle Spécification ou mise en œuvre de la fonction Oracle Équivalent MySQL Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

CONCAT(str1,str2)
Renvoie str1 concaténé avec str2 :

CONCAT('A', 1) = A1
Oui

CONCAT
Équivalent à Oracle :

CONCAT('A', 1) = A1

LOWER/UPPER
Renvoie char, avec toutes les lettres minuscules ou majuscules :

LOWER('SQL') = sql
Oui

LOWER/UPPER
Équivalent à Oracle :

LOWER('SQL') = sql

LPAD/RPAD(expr1,n,expr2)
Renvoie expr1, complétée à gauche ou à droite (pour atteindre une longueur de n caractères) à l'aide de la séquence de caractères de expr2 :

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

LPAD/RPAD
Équivalent à Oracle :

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

SUBSTR(char,p,n)
Renvoie une partie de char, commençant à la position de caractère p, avec une longueur de sous-chaîne de n caractères :

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

SUBSTR(char,p,n)
Équivalent à Oracle :

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

INSTR(index,str)
Renvoie la position (index) de la chaîne str :

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

INSTR
Équivalent à Oracle :

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

REPLACE(char,str1,str2)
Renvoie char avec chaque occurrence d'une chaîne de recherche remplacée par une chaîne de remplacement :

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

= MySQLDB
Oui

REPLACE(char,str1,str2)
Équivalent à Oracle :

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

= MySQLDB

TRIM(str)
Coupe les caractères de début ou de fin (ou les deux) d'une chaîne :

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

TRIM(' MySQL ') = MySQL
Oui

TRIM(str)
Équivalent à Oracle :

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

TRIM(' MySQL ') = MySQL

LTRIM/RTRIM(str)
Supprime de l'extrémité gauche ou droite de la chaîne tous les caractères qui apparaissent dans la recherche :

LTRIM('   MySQL', ' ')
= MySQL
En partie

LTRIM/RTRIM(str)
Fonction R/LTRIM Oracle, à l'exception du remplacement du paramètre (espace ou chaîne). MySQL R/LTRIM n'élimine que les espaces, en acceptant uniquement la chaîne d'entrée :

LTRIM('   MySQL')
= MySQL

ASCII(char)
Renvoie la représentation décimale (dans le jeu de caractères de la base de données) du premier caractère de char :

ASCII('A') = 65
Oui

ASCII(char)
Équivalent à Oracle :

ASCII('A') = 65

CHR(char)
Renvoie la valeur du code ASCII (valeur numérique comprise entre 0 et 255) pour un caractère :

CHR(65) = A
En partie avec un nom de fonction différent

CHAR(char)
MySQL utilise la fonction CHAR pour la même fonctionnalité. Vous devez donc modifier un nom de fonction :

CHAR(65) = A

LENGTH(str)
Renvoie la longueur d'une chaîne donnée :


LENGTH ('MySQL') = 5
Oui

LENGTH(str)
Équivalent à Oracle :

LENGTH('MySQL') = 5

REGEXP_REPLACE(str1,expr,str2)
Recherche un modèle d'expression régulière dans une chaîne :

REGEXP_REPLACE('John', '[hn].', '1') = Jo1
Non N/A Compatible uniquement avec la version 8 de MySQL. Pour contourner ce problème, utilisez la fonction REPLACE si possible ou effectuez la conversion vers la couche d'application.

REGEXP_SUBSTR(str,expr)
Étend les fonctionnalités de la fonction SUBSTR en recherchant un modèle d'expression régulière dans une chaîne :

REGEXP_SUBSTR('https://console.cloud.google.com/sql/instances','https://([[:alnum:]]+\.?){3,4}/?')
= https://console.cloud.google.com/
Non N/A Compatible uniquement avec la version 8 de MySQL. Pour contourner ce problème, utilisez la fonction SUBSTR si possible ou convertissez la fonctionnalité vers la couche d'application.

REGEXP_COUNT(str,expr)
Renvoie le nombre d'occurrences d'un modèle dans une chaîne source. Non N/A Vous pouvez aussi convertir la fonctionnalité en couche d'application.

REGEXP_INSTR(index,expr)
Recherche un format d'expression régulière dans une position de chaîne (index). Non N/A Compatible uniquement avec la version 8 de MySQL.

REVERSE(str)
Renvoie une chaîne inversée

REVERSE('MySQL')
= LQSyM
Oui

REVERSE
Équivalent à Oracle :

REVERSE('MySQL')
= LQSyM
Fonctions numériques
Fonction Oracle Spécification ou mise en œuvre de la fonction Oracle Équivalent MySQL Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

ABS(n)
Valeur absolue de n :

ABS(-4.6) = 4.6
Oui

ABS
Équivalent à Oracle :

ABS(-4.6) = 4.6

CEIL(n)
Renvoie le plus petit entier supérieur ou égal à n :

CEIL(21.4) = 22
Oui

CEIL
Équivalent à Oracle :

CEIL(21.4) = 22

FLOOR(n)
Renvoie le plus grand nombre entier égal ou inférieur à n :

FLOOR(-23.7) = -24
Oui

FLOOR
Équivalent à Oracle :

FLOOR(-23.7) = -24

MOD(m,n)
Renvoie le reste de m divisé par n :

MOD(10, 3) = 1
Oui

MOD(m,n)
Équivalent à Oracle :

MOD(10,3) = 1

ROUND(m,n)
Renvoie m arrondi à n chiffres à droite de la virgule :

ROUND(1.39,1) = 1.4
Oui

ROUND
Équivalent à Oracle :

ROUND(1.39,1) = 1.4

TRUNC(n1, n2)
Renvoie n1 tronqué à n2 décimales :

TRUNC(99.999) = 99
TRUNC(99.999,0) = 99
En partie avec un nom de fonction différent

TRUNCATE(n1, n2)
La fonction MySQL TRUNCATE doit accepter un nombre en entrée, ainsi qu'un nombre entier pour spécifier la précision à droite de la virgule :

TRUNCATE(99.999,0) = 99
Fonctions de date et heure
Fonction Oracle Spécification ou mise en œuvre de la fonction Oracle Équivalent MySQL Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

SYSDATE
Renvoie la date et l'heure actuelles du système d'exploitation sur lequel réside le serveur de base de données :

SELECT SYSDATE
FROM DUAL
= 31-JUL-2019
En partie

SYSDATE()
Le fichier MySQL SYSDATE() doit inclure des parenthèses et renvoie un format de date/heure différent de celui de la fonction SYSDATE Oracle :

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

Notez que la mise en forme de la date et de l'heure peut être modifiée au niveau de la session.

SYSTIMESTAMP
Renvoie la date du système, y compris les fractions de seconde et le fuseau horaire :

SELECT SYSTIMESTAMP FROM DUAL
= 01-JAN-19 07.37.11.622187000 AM +00:00
En partie avec un nom de fonction différent

CURRENT_TIMESTAMP
MySQL renvoie un format de date et d'heure différent de celui d'Oracle. Une mise en forme de la date (ou une fonction de date différente) permettant une correspondance avec le format de date/heure d'origine est requise :

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

LOCAL_TIMESTAMP
Renvoie la date et l'heure actuelles dans le fuseau horaire de la session dans une valeur dont le type de données est TIMESTAMP :

SELECT LOCAL_TIMESTAMP
FROM DUAL
= 01-JAN-19 10.01.10.123456 PM
En partie avec une mise en forme de date/heure différente

LOCAL_TIMESTAMP
MySQL renvoie un format de date et d'heure différent de celui d'Oracle. Une mise en forme de la date/heure (ou une fonction de date différente) permettant une correspondance avec le format de date/heure d'origine est requise :

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

CURRENT_DATE
Renvoie la date actuelle dans le fuseau horaire de la session :

SELECT CURRENT_DATE
FROM DUAL
= 31-JAN-19
En partie avec une mise en forme de date/heure différente

CURRENT_DATE
MySQL renvoie un format de date et d'heure différent de celui d'Oracle. Une mise en forme de la date/heure (ou une fonction de date différente) permettant une correspondance avec le format de date/heure d'origine est requise :

SELECT CURRENT_DATE
FROM DUAL
= 2019-01-31

CURRENT_TIMESTAMP
Renvoie la date et l'heure actuelles dans le fuseau horaire de la session :

SELECT CURRENT_TIMESTAMP
FROM DUAL
= 31-JAN-19 06.54.35.543146 AM +00:00
En partie avec une mise en forme de date/heure différente

CURRENT_TIMESTAMP
MySQL renvoie un format de date et d'heure différent de celui d'Oracle. Une mise en forme de la date/heure (ou une fonction de date différente) permettant une correspondance avec le format de date/heure d'origine est requise :

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

ADD_MONTHS
Renvoie la date plus les mois entiers :

ADD_MONTHS(SYSDATE, 1)
= 31-JAN-19
En partie avec un nom de fonction différent

ADDDATE
Pour obtenir les mêmes fonctionnalités, MySQL utilise la fonction ADDDATE :

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

Par défaut, MySQL renvoie une date, une heure, une plage et un format différents de ceux d'Oracle. Une mise en forme de la date/heure (ou une fonction de date différente) permettant une correspondance avec le format de date/heure d'origine est requise.
EXTRACT(partie de la date) Renvoie la valeur d'un champ de date/heure spécifié à partir d'une expression de date/heure ou d'intervalle :

EXTRACT(YEAR FROM DATE '2019-01-31')
= 2019
Oui EXTRACT (partie de la date) Équivalent à Oracle :

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

LAST_DAY
Renvoie la date du dernier jour du mois :

LAST_DAY('01-JAN-2019')
= 31-JAN-19
En partie avec une mise en forme de date/heure différente

LAST_DAY
MySQL renvoie un format de date et d'heure différent de celui d'Oracle. Une mise en forme de la date/heure (ou une fonction de date différente) permettant une correspondance avec le format de date/heure d'origine est requise :

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

MONTH_BETWEEN
Renvoie le nombre de mois compris entre les dates date1 et date2 :

MONTHS_BETWEEN(
SYSDATE, SYSDATE-60)
= 1.96
En partie avec un nom de fonction différent

PERIOD_DIFF(date1,date2)
La fonction MySQL PERIOD_DIFF renvoie la différence en mois entre deux "périodes" (au format YYMM ou YYYYMM) sous forme de nombre entier :

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

Pour obtenir les mêmes valeurs qu'avec la fonction Oracle MONTH_BETWEEN, une conversion plus spécifique est requise.
TO_CHAR (date/heure) Convertit un type de données de date/heure ou d'horodatage en une valeur de type de données VARCHAR2 au format spécifié par le format de date :

TO_CHAR(
SYSDATE,'DD-MM-YYYY HH24:MI:SS')
= 01-01-2019 10:01:01
En partie avec un nom de fonction différent

DATE_FORMAT
La fonction MySQL DATE_FORMAT met en forme une date comme spécifié dans une définition de format de date :

DATE_FORMAT(
SYSDATE(),'%d-%m-%Y %H:%i:%s')
= 01-01-2019 10:01:01
Fonctions d'encodage et de décodage
Fonction Oracle Spécification ou mise en œuvre de la fonction Oracle Équivalent MySQL Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

DECODE
Compare l'expression à chaque valeur de recherche (une par une) à l'aide de la fonctionnalité d'une instruction IF-THEN-ELSE. Non

CASE
Utilisez l'instruction MySQL CASE pour obtenir des fonctionnalités similaires.

DUMP
Renvoie une valeur VARCHAR2 contenant le code du type de données, la longueur en octets et la représentation interne d'une expression donnée. Non N/A Non compatible

ORA_HASH
Calcule une valeur de hachage pour une expression donnée. Non

MD5/SHA
Utilisez MySQL MD5 pour la somme de contrôle de 128 bits ou la fonction SHA pour la somme de contrôle de 160 bits afin de générer des valeurs de hachage.
Fonctions de conversion
Fonction Oracle Spécification ou mise en œuvre de la fonction Oracle Équivalent MySQL Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

CAST
Convertit un type de données intégré ou une valeur de type collection en un autre type de données intégré ou une autre valeur de type collection :

CAST('1' as int) + 1
= 2
En partie

CAST
La fonction MySQL CAST est semblable à la fonctionnalité Oracle, mais dans certains cas, elle doit être ajustée selon qu'une conversion explicite ou implicite est requise :

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

CONVERT
Convertit une chaîne de caractères d'un jeu de caractères en une autre :

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

CONVERT
La fonction MySQL CONVERT nécessite quelques ajustements de la syntaxe et des paramètres pour renvoyer les résultats exacts de la même façon que la fonction Oracle :

CONVERT('Ä Ê Í A B C ' USING utf8)
= Ä Ê Í A B C
TO_CHAR
(chaîne/numérique)
La fonction convertit un nombre ou une date en chaîne :

TO_CHAR(22.73,'$99.9')
= $22.7
Non

FORMAT
La fonction MySQL FORMAT applique le formatage "#,###.##" à un nombre, en arrondissant la valeur à un certain nombre de décimales, puis elle renvoie le résultat sous forme de chaîne. Elle possède des fonctionnalités différentes de celles d'Oracle :

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

TO_DATE
La fonction Oracle TO_DATE convertit une chaîne en date en utilisant le format de date/heure spécifique à la source :

TO_DATE(
'2019/01/01', 'yyyy-mm-dd')
= 01-JAN-2019
En partie avec un nom de fonction et une mise en forme de date/heure différents

STR_TO_DATE
La fonction MySQL STR_TO_DATE utilise une chaîne et renvoie une date au format (date/heure) spécifié :

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

TO_NUMBER
Convertit l'expression en une valeur dont le type de données est NUMBER :

TO_NUMBER('01234')
= 1234
Non

CAST
Vous pouvez également utiliser la fonction MySQL CAST pour renvoyer le même résultat qu'avec Oracle TO_NUMBER :

CAST('01234' as SIGNED)
= 1234
Fonctions SELECT conditionnelles
Fonction Oracle Spécification ou mise en œuvre de la fonction Oracle Équivalent MySQL Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

CASE
L'instruction CASE effectue un choix dans une séquence de conditions et exécute une instruction correspondante avec la syntaxe suivante :

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

CASE
En plus de la fonction CASE, MySQL est également compatible avec l'utilisation de la gestion conditionnelle IF/ELSE dans l'instruction SELECT :

CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Fonctions nulles
Fonction Oracle Spécification ou mise en œuvre de la fonction Oracle Équivalent MySQL Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

COALESCE
Renvoie la première expression non nulle de la liste d'expressions :

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

COALESCE
Équivalent à Oracle :

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

NULLIF
Compare les expressions expr1 et expr2m. Si elles sont égales, la fonction renvoie la valeur "null". Si elles ne sont pas égales, la fonction renvoie "expr1" :
.

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

NULLIF
Équivalent à Oracle :

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

NVL
Remplace la valeur "null" (renvoyée sous forme de valeur vide) par une chaîne dans les résultats d'une requête :

NVL(null, 'a')
= a
Non

IFNULL
La fonction MySQL équivalente serait la fonction IFNULL , qui remplace les valeurs "null" par une chaîne donnée :

IFNULL(null, 'a')
= a

NVL2
Détermine la valeur renvoyée par une requête selon qu'une expression
spécifiée est nulle ou non nulle.
Non

CASE
L'instruction CASE
effectue un choix dans une séquence de conditions et exécute une instruction correspondante :

CASE WHEN condition THEN result
[WHEN ...] [ELSE result]
END
Fonctions d'environnement et d'identification
Fonction Oracle Spécification ou mise en œuvre de la fonction Oracle Équivalent MySQL Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

SYS_GUID
Génère et renvoie un identifiant global unique (valeur RAW) composé de 16 octets :

SELECT SYS_GUID()
FROM DUAL
= 8EFA4A31468B4C6DE05011AC0200009E
Non REPLACE et UUID Pour contourner ce problème, utilisez les fonctions MySQL REPLACE et UUID pour simuler la fonction Oracle SYS_GUID :

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

UID
Renvoie un entier qui identifie de manière unique l'utilisateur de la session (l'utilisateur
qui s'est connecté) :

SELECT UID FROM DUAL
= 43
Non N/A N/A

USER
Renvoie le nom de l'utilisateur de la session actuelle :

SELECT USER FROM DUAL
= UserName
En partie

USER + INSTR + SUBSTR
La fonction USER de MySQL renvoie le nom de l'utilisateur et celui du serveur auquel il est connecté (root@IP). Pour ne récupérer que le nom d'utilisateur, utilisez des fonctions supplémentaires :

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

USERENV
Renvoie des informations sur la session utilisateur actuelle avec la configuration de paramètre actuelle :

SELECT USERENV('LANGUAGE')
FROM DUAL
= ENGLISH_AMERICA.AL32UTF8
Non

SHOW SESSION
VARIABLES
Utilisez l'instruction MySQL SHOW SESSION
VARIABLES pour afficher les paramètres de la session actuelle :

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

ROWID
Le serveur Oracle attribue à chaque ligne de chaque table un ROWID unique pour identifier la ligne dans la table. ROWID est l'adresse de la ligne contenant le numéro de l'objet de données, le bloc de données de la ligne, la position de la ligne et le fichier de données. Non N/A Si possible, essayez d'émuler la même fonctionnalité avec d'autres fonctions MySQL.

ROWNUM
Renvoie un nombre représentant l'ordre dans lequel une ligne est sélectionnée par Oracle dans une table ou des tables jointes. Non N/A Si possible, essayez d'émuler la même fonctionnalité avec d'autres fonctions ou variables de session MySQL.
Fonctions d'agrégation (groupe)
Fonction Oracle Spécification de la fonction Oracle ou mise en œuvre
Équivalent
MySQL
Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

AVG
Renvoie la valeur moyenne de la colonne ou de l'expression. Oui

AVG
Équivalent à Oracle

COUNT
Renvoie le nombre de lignes renvoyées par une requête. Oui

COUNT
Équivalent à Oracle

COUNT
(DISTINCT)
Renvoie le nombre de valeurs uniques dans la colonne ou l'expression. Oui

COUNT
(DISTINCT)
Équivalent à Oracle

MAX
Renvoie la valeur maximale de la colonne ou de l'expression. Oui

MAX
Équivalent à Oracle

MIN
Renvoie la valeur minimale de la colonne ou de l'expression. Oui

MIN
Équivalent à Oracle

SUM
Renvoie la somme des valeurs de la colonne ou de l'expression. Oui

SUM
Équivalent à Oracle

LISTAGG
Affiche les données de chaque groupe sur une seule ligne spécifiée dans la clause ORDER BY en concaténant les valeurs de la colonne de mesure :

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

-- Single line results
= Accounting, Administration, Benefits, Construction
Non

GROUP_CONCAT
Utilisez la fonction MySQL GROUP_CONCAT pour renvoyer des résultats semblables à ceux d'Oracle, des différences de syntaxe étant à prévoir dans certains cas :

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

-- Single line results
= Accounting, Administration, Benefits, Construction
Oracle 12c Fetch
Fonction Oracle Spécification de la fonction Oracle ou mise en œuvre
Équivalent
MySQL
Fonction MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

FETCH
Récupère les lignes de données de l'ensemble de résultats d'une requête sur plusieurs lignes :

SELECT * FROM
EMPLOYEES
FETCH FIRST 10 ROWS ONLY;
Non LIMIT Utilisez la clause MySQL LIMIT pour ne récupérer qu'un ensemble spécifique d'enregistrements :

SELECT * FROM
EMPLOYEES
LIMIT 10;

Filtrage de base, opérateurs et sous-requêtes

Lors de la conversion, le filtrage de base, les fonctions d'opérateur et les sous-requêtes sont relativement simples à effectuer et ne nécessitent presque aucun effort.

Notes de conversion

Vous devez examiner et adapter les formats de date, car les formats Oracle et MySQL renvoient des résultats par défaut différents :

  • La fonction SYSDATE Oracle renvoie par défaut 01-AUG-19.
  • La fonction SYSDATE() MySQL renvoie par défaut 2019-08-01 12:04:05.
  • Les formats de date et d'heure peuvent être définis à l'aide des fonctions 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).
Fonction ou sous-requête Oracle Équivalent MySQL Fonction ou sous-requête MySQL correspondante Spécification ou mise en œuvre de la fonction MySQL

EXISTS/NOT EXISTS
Oui

EXISTS/NOT EXISTS

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

IN/NOT IN
Oui

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
Oui

LIKE/NOT LIKE

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

BETWEEN/NOT BETWEEN
Oui

BETWEEN/NOT BETWEEN

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

AND/OR
Oui

AND/OR

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

SubQuery
Oui

SubQuery
MySQL accepte les sous-requêtes au niveau SELECT, pour les instructions JOIN et pour le filtrage dans les clauses 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);
Opérateurs Oui Opérateurs MySQL est compatible avec tous les opérateurs de base :

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

Fonctions d'analyse (ou fonctions de fenêtre et de classement)

Les fonctions d'analyse Oracle étendent la fonctionnalité des fonctions d'analyse SQL standards en fournissant des capacités de calcul des valeurs agrégées en fonction d'un groupe de lignes. Ces fonctions peuvent être appliquées à des ensembles de résultats partitionnés de manière logique dans une seule expression de requête. Elles sont généralement utilisées conjointement avec des rapports et des analyses d'informatique décisionnelle et permettent d'améliorer les performances des requêtes. Il n'est donc pas nécessaire d'utiliser un code SQL plus complexe et non analytique pour parvenir à un tel résultat.

Notes de conversion

  • La version 5.7 de MySQL ne fournit pas de fonctions d'analyse permettant de convertir des instructions SQL simples. Cependant, cette fonctionnalité a été partiellement ajoutée dans la version 8 de MySQL. Il est donc nécessaire de prévoir un effort manuel dédié à la conversion des fonctions analytiques dans le cadre du processus de migration.
  • Vous pouvez également réécrire le code afin de supprimer l'utilisation de fonctions d'analyse et ainsi revenir à des solutions de code SQL plus traditionnelles, ou encore déplacer cette logique vers une couche d'application.

Le tableau suivant répertorie les fonctions d'analyse courantes d'Oracle.

Famille de fonctions Fonctions associées Compatible avec MySQL 5.7
Analyse et classement

RANK
AVERAGE_RANK
DENSE_RANK
RANK ROW_NUMBER
PERCENT_RANK
CUME_DIST
NTILE
FIRST_VALUE
LAST_VALUE
OVER (PARTITION BY...)
Non
Hiérarchique

CONNECT BY
HIER_ANCESTOR
HIER_CHILD_COUNT
HIER_DEPTH
HIER_LEVEL
HIER_ORDER
HIER_PARENT
HIER_TOP
Non
Lag

LAG
LAG_VARIANCE LAG_VARIANCE_PERCENT LEAD
LEAD_VARIANCE LEAD_VARIANCE_PERCENT
Non

Expression de table commune (CTE)

Les CTE permettent de mettre en œuvre la logique du code séquentiel afin de réutiliser du code SQL pouvant être trop complexe ou peu efficace pour une utilisation polyvalente. Les CTE peuvent être nommées, puis utilisées plusieurs fois dans différentes parties d'une instruction SQL à l'aide de la clause WITH.

Notes de conversion

  • MySQL version 5.7 n'est pas compatible avec les CTE, contrairement à MySQL version 8.
  • En guise de solution alternative, vous pouvez utiliser des tables dérivées ou des sous-requêtes, ou encore réécrire l'instruction SQL pour éliminer la fonctionnalité CTE.

Exemples

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;

Instruction MERGE

L'instruction MERGE (ou UPSERT) permet de spécifier des instructions SQL uniques permettant d'effectuer des opérations LMD de manière conditionnelle dans une opération MERGE, au lieu d'une seule opération LMD exécutée séparément. Elle sélectionne les enregistrements de la table source, puis, en spécifiant une structure logique, effectue automatiquement plusieurs opérations LMD sur la table cible. Cette fonctionnalité vous permet d'éviter l'utilisation de plusieurs insertions, mises à jour ou suppressions. Notez que MERGE est une instruction déterministe, ce qui signifie qu'une fois qu'une ligne a été traitée par l'instruction MERGE, elle ne peut plus être traitée à l'aide de la même instruction MERGE.

Notes de conversion

MySQL 5.7 n'est pas compatible avec la fonctionnalité MERGE, contrairement à Oracle. Pour simuler partiellement la fonctionnalité MERGE, MySQL fournit les instructions REPLACE et INSERT… ON DUPLICATE KEY UPDATE :

  • REPLACE : fonctionne de la même manière qu'une instruction INSERT, à l'exception que, si une ancienne ligne de la table a la même valeur qu'une nouvelle ligne pour un index PRIMARY KEY ou UNIQUE, l'ancienne ligne est supprimée avant l'insertion de la nouvelle ligne.

  • INSERT… ON DUPLICATE KEY UPDATE : si une ligne insérée entraîne la présence d'une valeur en double dans un index PRIMARY KEY ou UNIQUE, un UPDATE de l'ancienne ligne est utilisé afin d'éliminer l'exception de clé en double, comme dans l'exemple suivant :

    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;
    

Une autre solution consiste à convertir la fonctionnalité MERGE en procédure stockée pour gérer les opérations LMD à l'aide des commandes INSERT, UPDATE et DELETE avec gestion des exceptions et des doublons.

Suggestions pour les instructions SQL

Oracle fournit un large éventail de suggestions de requête SQL qui permettent aux utilisateurs d'influencer le comportement de l'optimiseur et sa prise de décision, afin de produire des plans d'exécution de requête plus efficaces. Oracle accepte plus de 60 suggestions différentes relatives aux bases de données. MySQL fournit un ensemble limité de suggestions de requête.

En général, la version MySQL 5.7 accepte deux types de suggestions de requête : OPTIMIZER HINTS et INDEX HINTS. Les suggestions d'optimiseur MySQL permettent de contrôler le comportement de l'optimiseur dans des instructions SQL individuelles, par exemple :

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

Suggestions d'optimiseur disponibles dans la version 5.7 de MySQL

Nom de la suggestion Présentation de la suggestion Champs d'application

BKA, NO_BKA
Affecte le traitement par jointure des accès de clés par lots Bloc de requête, table

BNL, NO_BNL
Affecte le traitement des jointures par boucle imbriquée Bloc de requête, table

MAX_EXECUTION_TIME
Limite le temps d'exécution de l'instruction Global

MRR, NO_MRR
Affecte l'optimisation de la lecture sur plusieurs plages Table, index

NO_ICP
Affecte l'optimisation pushdown des conditions d'index Table, index

NO_RANGE_OPTIMIZATION
Affecte l'optimisation de la plage Table, index

QB_NAME
Attribue un nom au bloc de requêtes Bloc de requête

SEMIJOIN, NO_SEMIJOIN
Affecte les stratégies de semi-jointure Bloc de requête

SUBQUERY
Affecte la matérialisation des stratégies de sous-requêtes IN à EXISTS. Bloc de requête

Les suggestions d'index MySQL fournissent à l'optimiseur des informations sur le choix des index lors du traitement des requêtes. Les mots clés USE, FORCE ou IGNORE permettent de contrôler le processus d'utilisation des index de l'optimiseur, par exemple :

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

Notes de conversion

Comme il existe des différences majeures entre Oracle et l'optimiseur MySQL, et que la correspondance est très limitée, voire inexistante, entre les suggestions de requête Oracle et MySQL, nous vous recommandons de convertir toutes les instructions Oracle SQL contenant des suggestions de requête non spécifiées sur la base de données MySQL cible.

Effectuez un réglage des performances MySQL en vous servant des outils MySQL (par exemple, MySQL Workbench pour les tableaux de bord en temps réel), ainsi que des fonctionnalités telles que l'examen des requêtes à l'aide de plans d'exécution et l'ajustement des paramètres d'instance ou de session en fonction du cas d'utilisation.

Plans d'exécution

L'objectif principal des plans d'exécution est de fournir un aperçu des choix effectués par l'optimiseur de requête pour accéder aux données de la base de données. L'optimiseur de requête génère des plans d'exécution pour les instructions SELECT, INSERT, UPDATE et DELETE pour les utilisateurs de base de données, ce qui offre aux administrateurs une visibilité accrue sur des requêtes et des opérations LMD spécifiques. Ces informations sont particulièrement utiles lorsque vous devez ajuster les performances des requêtes, par exemple pour évaluer les performances des index ou pour déterminer si des index manquants doivent être créés.

Les plans d'exécution peuvent être affectés par les volumes de données, les statistiques de données et les paramètres d'instance (paramètres globaux ou de session).

Remarques sur les conversions

Les plans d'exécution ne sont pas des objets de base de données qui doivent être migrés. Il s'agit plutôt d'une boîte à outils permettant d'analyser les différences de performances entre Oracle et MySQL lorsque ceux-ci exécutent les mêmes instructions sur des ensembles de données identiques.

La syntaxe, les fonctionnalités et les résultats fournis par les plans d'exécution diffèrent entre MySQL et Oracle.

Exemples

Plan d'exécution 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 d'exécution 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 | +----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+

Procédures stockées, fonctions et déclencheurs

PL/SQL est le langage procédural étendu Oracle utilisé pour créer, stocker et appliquer des solutions basées sur du code dans la base de données. En général, les procédures et les fonctions stockées dans la base de données sont des éléments de code constitués sur la base d'un langage procédural étendu ANSI SQL et SQL (par exemple, PL/SQL pour Oracle, PL/pgSQL pour PostgreSQL et MySQL pour MySQL). MySQL utilise le même nom que la base de données pour son propre langage procédural étendu.

Le but de ces procédures et fonctions stockées est de fournir des solutions pour des exigences plus adaptées à l'exécution depuis la base de données et non depuis l'application (par exemple, performances, compatibilité et sécurité). Bien que les procédures stockées et les fonctions utilisent toutes deux PL/SQL, les procédures stockées sont principalement utilisées pour effectuer des opérations LDD/LMD, alors que les fonctions sont principalement utilisées pour effectuer des calculs afin de renvoyer des résultats spécifiques.

Langage procédural PL/SQL vers MySQL

Du point de vue de la migration du code PL/SQL à MySQL, l'implémentation procédurale de MySQL est différente de celle d'Oracle. Par conséquent, la migration du code est nécessaire pour convertir les fonctionnalités PL/SQL d'Oracle en procédures et fonctions stockées MySQL. En outre, Oracle Package et Package Body ne sont pas acceptés par MySQL. Par conséquent, lorsque vous effectuez une conversion de code, convertissez ces éléments (ou analysez-les) en unités de code MySQL uniques. Notez que les procédures et fonctions MySQL stockées sont également appelées routines.

Propriétaire de l'objet de code

Dans Oracle, le propriétaire d'une procédure ou d'une fonction stockée est un utilisateur spécifique. Dans MySQL, le propriétaire est un schéma spécifique (créé dans une base de données par un utilisateur de base de données).

Droits et sécurité des objets de code

Dans Oracle, pour créer une procédure ou une fonction stockée, l'utilisateur doit disposer du droit système CREATE PROCEDURE (pour créer des procédures ou des fonctions pour des utilisateurs différents, les utilisateurs de la base de données doivent disposer du droit CREATE ANY PROCEDURE). Pour exécuter une procédure ou une fonction stockée, les utilisateurs de la base de données doivent disposer du droit EXECUTE.

Dans MySQL, pour créer un élément de code, l'utilisateur doit disposer du droit CREATE ROUTINE et du droit EXECUTE. La clause MySQL DEFINER définit l'utilisateur créateur pour l'objet de code, et l'utilisateur doit disposer des droits appropriés tels que CREATE ROUTINE.

Syntaxe des procédures et fonctions stockées MySQL

L'exemple suivant montre la syntaxe de procédure et de fonction stockées 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