このドキュメントは、Oracle® 11g/12c データベースから Cloud SQL for MySQL バージョン 5.7 の第 2 世代インスタンスへの移行を計画し、実施する際に必要な情報とガイダンスを提供するシリーズの一つです。このシリーズは次のパートから構成されています。
- Oracle から Cloud SQL for MySQL への移行: 用語と機能
- Oracle から Cloud SQL for MySQL への移行: データ型、ユーザー、テーブル
- Oracle から Cloud SQL for MySQL への移行: クエリ、ストアド プロシージャ、関数、トリガー(このドキュメント)
- Oracle から Cloud SQL for MySQL への移行: セキュリティ、オペレーション、モニタリング、ロギング
クエリ
Oracle と Cloud SQL for MySQL は ANSI SQL 標準に対応しています。一般に、SQL ステートメントの移行は難しくありません、基本的な構文要素を使用するだけで移行できます。スカラー関数やその他の Oracle 拡張機能を指定する必要はありません。以下では、一般的な Oracle クエリ要素とそれに対応する Cloud SQL for MySQL の要素について説明します。
基本的な SELECT 構文と FROM 構文
Oracle の機能名または構文名 | Oracle の概要または実装 | MySQL のサポート | MySQL の対応または代替ソリューション |
---|---|---|---|
データ取得用の SQL 基本構文 | SELECT FROM WHERE GROUP BY HAVING ORDER BY |
○ | SELECT FROM WHERE GROUP BY HAVING ORDER BY |
出力用の SELECT |
SELECT 1 FROM DUAL |
○ | SELECT 1 OR SELECT 1 FROM DUAL |
列のエイリアス | SELECT COL1 AS C1 |
○ | SELECT COL1 AS C1 OR SELECT COL1 C1 |
テーブル名での 大文字と小文字の区別 |
大文字と小文字は区別しない (例: テーブル名として orders と ORDERS のどちらも使用可能) |
× | 定義済みのテーブル名に応じて大文字と小文字を区別する(例: テーブル名として orders か ORDERS のいずれかを使用可能)。 |
MySQL の SELECT
構文の詳細をご覧ください。
- インライン ビュー
- インラインビュー(別名、派生テーブル)は
FROM
句に指定されるSELECT
ステートメントで、サブクエリとして使用されます。 - インライン ビューを利用して複合計算を削除したり、結合オペレーションを排除したりすると、複雑なクエリをシンプルにできます。また、複数の個別クエリを 1 つの簡素化されたクエリに要約することもできます。
- 変換に関する注記: Oracle ではインライン ビューにエイリアスを使用する必要はありませんが、MySQL ではインライン ビューごとに固有のエイリアスが必要です。
- インラインビュー(別名、派生テーブル)は
次の表に、Oracle から MySQL へのインライン ビューの変換例を記載します。
Oracle 11g / 12c |
---|
SQL> SELECT FIRST_NAME, DEPARTMENT_ID, SALARY, DATE_COL FROM EMPLOYEES, (SELECT SYSDATE AS DATE_COL FROM DUAL); 次のような出力になります。 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 for MySQL 5.7 |
インライン ビューにエイリアスを使用しない場合:mysql> SELECT FIRST_NAME, DEPARTMENT_ID, SALARY, DATE_COL FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL); インライン ビューにエイリアスを追加した場合: mysql> SELECT FIRST_NAME, DEPARTMENT_ID, SALARY, DATE_COL FROM EMPLOYEES, (SELECT SYSDATE() AS DATE_COL FROM DUAL) AS A1; 次のような出力になります。 +-------------+---------------+----------+---------------------+ | 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 | |
JOIN ステートメント
Oracle の JOIN
ステートメントは、FULL JOIN
句を除き、MySQL の JOIN
ステートメントでサポートされています。さらに、MySQL の JOIN
ステートメントは代替構文の使用をサポートしています。たとえば、ON
句や JOIN
ステートメントで SUBQUERY
を使用する代わりに、USING
句や WHERE
句を使用できます。
次の表に、JOIN の変換例を示します。
Oracle の JOIN の種類 | MySQL でのサポート | MySQL の JOIN 構文 |
---|---|---|
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 |
× | 代わりに、LEFT ステートメントと RIGHT JOIN ステートメントで UNION を使用することを検討してください。 |
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、MINUS
MySQL では、UNION
関数と UNION ALL
関数を除き、Oracle の INTERSECT
関数と MINUS
関数はサポートされていません。
UNION
: 2 つ以上のSELECT
ステートメントの結果セットを結合しますが、重複するレコードは除外します。UNION ALL
: 重複レコードを除外せずに、複数のSELECT
ステートメントの結果セットを結合します。INTERSECT
: レコードが両方のデータセットに存在する場合にのみ、2 つ以上のSELECT
ステートメントの結果で共通する部分を返します。MINUS
: 2 つ以上のSELECT
ステートメントを比較し、最初のクエリで他のステートメントから返されない個別の行のみを返します。
変換に関する注記
Oracle の INTERSECT
関数と MINUS
関数を MySQL に変換する場合は、代わりに JOIN
ステートメントで IN
と EXISTS
を使用します。
例
Oracle の関数 | Oracle の実装 | MySQL のサポート | 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 |
いいえ | SELECT COL1 FROM TBL1 WHERE COL1 IN (SELECT COL1 FROM TBL2) |
MINUS |
SELECT COL1 FROM TBL1 MINUS SELECT COL1 FROM TBL2 |
× | SELECT A.COL1 FROM TBL1 A LEFT JOIN TBL2 B ON USING(COL1) WHERE B.COL1 IS NULL |
スカラー(単一行)関数とグループ化関数
MySQL にはさまざまなスカラー(単一行)関数と集計関数が用意されています。一部の MySQL 関数は、対応する Oracle 関数に非常によく似ています(名前と機能が似ている関数や、名前は異なっていても機能が似ている関数などがあります)。MySQL と Oracle で同じ関数名が使用されていても、機能がそれぞれ異なる場合もあります。
次の表に、Oracle と MySQL の間で名前と機能が同じ関数(「○」で示しています)と、変換が推奨される関数(「○」以外)を示します。
文字関数
Oracle の関数 | Oracle 関数の仕様または実装 | MySQL の同等関数 | MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
CONCAT(str1,str2) |
str1 と str2 を連結した文字列を返します。CONCAT('A', 1) = A1 |
○ | CONCAT |
Oracle と同等:CONCAT('A', 1) = A1 |
LOWER/UPPER |
すべての文字を小文字または大文字にして返します。LOWER('SQL') = sql |
○ | LOWER/UPPER |
Oracle と同等:LOWER('SQL') = sql |
LPAD/RPAD(expr1,n,expr2) |
expr1 の左側または右側に、expr2 で指定した文字を連続的に埋め込んで n 桁にして返します。LPAD('A',3,'*') = **A |
○ | LPAD/RPAD |
Oracle と同等:LPAD('A',3,'*') = **A |
SUBSTR(char,p,n) |
char の一部分(文字位置 p から n 文字の長さのサブ文字列)を返します。SUBSTR('MySQL', 3, 3) = SQL |
○ | SUBSTR(char,p,n) |
Oracle と同等:SUBSTR('MySQL', 3, 3) = SQL |
INSTR(index,str) |
文字列 str の位置(index)を返します。INSTR('MySQL', 'y') = 2 |
○ | INSTR |
Oracle と同等:INSTR('MySQL', 'y') = 2 |
REPLACE(char,str1,str2) |
検索文字列を置換文字列で置き換えた char を返します。REPLACE('ORADB', 'ORA', 'MySQL') |
○ | REPLACE(char,str1,str2) |
Oracle と同等:REPLACE('ORADB', 'ORA', 'MySQL') |
TRIM(str) |
文字列から先頭または末尾(あるいは両方)の文字を削除します。TRIM(both '-' FROM '-MySQL-') = MySQL |
○ | TRIM(str) |
Oracle と同等:TRIM(both '-' FROM '-MySQL-') = MySQL |
LTRIM/RTRIM(str) |
文字列の左端または右端から、検索で指定されたすべての文字を削除します。LTRIM(' MySQL', ' ') = MySQL |
部分的 | LTRIM/RTRIM(str) |
Oracle の R/LTRIM 関数。ただし、パラメータ(空白または文字列)の削除は除きます。MySQL の R/LTRIM は空白文字のみを削除し、入力文字列のみを受け入れます。LTRIM(' MySQL') = MySQL |
ASCII(char) |
データベースの文字セットに含まれる char の最初の文字の 10 進表現を返します。ASCII('A') = 65 |
○ | ASCII(char) |
Oracle と同等:ASCII('A') = 65 |
CHR(char) |
ASCII コード値(0~225 の数値)に対応する文字を返します。CHR(65) = A |
関数名の一部が異なる | CHAR(char) |
MySQL では同じ機能に CHAR 関数を使用するため、関数名を変更する必要があります。CHAR(65) = A |
LENGTH(str) |
指定した文字列の長さを返します。LENGTH ('MySQL') = 5 |
○ | LENGTH(str) |
Oracle と同等:LENGTH('MySQL') = 5 |
REGEXP_REPLACE(str1,expr,str2) |
正規表現パターンに一致する文字列を検索します。REGEXP_REPLACE('John', '[hn].', '1') = Jo1 |
× | なし | MySQL バージョン 8 以降でのみサポートされます。可能であれば代わりに REPLACE 関数を使用するか、アプリケーション層に変換してください。 |
REGEXP_SUBSTR(str,expr) |
正規表現パターンに一致する文字列を検索できるように、SUBSTR 関数の機能を拡張したものです。REGEXP_SUBSTR('https://console.cloud.google.com/sql/instances','https://([[:alnum:]]+\.?){3,4}/?') = https://console.cloud.google.com/ |
× | なし | MySQL バージョン 8 以降でのみサポートされます。可能であれば、代わりに SUBSTR 関数を使用するか、この機能をアプリケーション層に変換してください。 |
REGEXP_COUNT(str,expr) |
ソース文字列でのパターン出現回数を返します。 | × | なし | 代わりに、この機能をアプリケーション層に変換してください。 |
REGEXP_INSTR(index,expr) |
正規表現パターンに一致する文字列の位置(インデックス)を検索します。 | × | なし | MySQL バージョン 8 以降でのみサポートされます。 |
REVERSE(str) |
文字列を反転させて返します。REVERSE('MySQL') = LQSyM |
○ | REVERSE |
Oracle と同等:REVERSE('MySQL') = LQSyM |
数値関数
Oracle の関数 | Oracle 関数の仕様または実装 | MySQL の同等関数 | MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
ABS(n) |
n の絶対値を返します。ABS(-4.6) = 4.6 |
○ | ABS |
Oracle と同等:ABS(-4.6) = 4.6 |
CEIL(n) |
n 以上の最小の整数を返します。CEIL(21.4) = 22 |
○ | CEIL |
Oracle と同等:CEIL(21.4) = 22 |
FLOOR(n) |
n 以下の最大の整数を返します。FLOOR(-23.7) = -24 |
○ | FLOOR |
Oracle と同等:FLOOR(-23.7) = -24 |
MOD(m,n) |
m を n で割った余りを返します。MOD(10, 3) = 1 |
○ | MOD(m,n) |
Oracle と同等:MOD(10,3) = 1 |
ROUND(m,n) |
小数点以下 n 桁に丸めた m を返します。ROUND(1.39,1) = 1.4 |
○ | ROUND |
Oracle と同等:ROUND(1.39,1) = 1.4 |
TRUNC(n1, n2) |
n1 を小数点以下 n2 桁に切り捨てた数値を返します。TRUNC(99.999) = 99 TRUNC(99.999,0) = 99 |
関数名の一部が異なる | TRUNCATE(n1, n2) |
MySQL の TRUNCATE 関数は入力値と、小数点以下の桁数を指定する整数値を受け入れる必要があります。TRUNCATE(99.999,0) = 99 |
日付と時刻の関数
Oracle の関数 | Oracle 関数の仕様または実装 | MySQL の同等関数 | MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
SYSDATE |
データベース サーバーが存在するオペレーティング システムに設定されている現在の日付と時刻を返します。SELECT SYSDATE FROM DUAL = 31-JUL-2019 |
部分的 | SYSDATE() |
MySQL の SYSDATE() には括弧を含める必要があります。この関数は、Oracle の SYSDATE 関数とは異なる形式の日時を返します。SELECT SYSDATE() FROM DUAL; = 2019-01-31 10:01:01.0 日時形式はセッション レベルで変更できます。 |
SYSTIMESTAMP |
小数点以下の秒とタイムゾーンを含む、システムの日付を返します。SELECT SYSTIMESTAMP FROM DUAL = 01-JAN-19 07.37.11.622187000 AM +00:00 |
関数名の一部が異なる | CURRENT_TIMESTAMP |
MySQL は、Oracle とは異なる日付 / 時刻形式を返します。日付の形式は元の日付 / 時刻形式と一致させる必要があります(または別の日付関数を使用する必要があります)。SELECT CURRENT_TIMESTAMP FROM DUAL = 2019-01-31 06:55:07 |
LOCAL_TIMESTAMP |
セッションのタイムゾーンでの現在の日付と時刻を TIMESTAMP データ型の値で返します。SELECT LOCAL_TIMESTAMP FROM DUAL = 01-JAN-19 10.01.10.123456 PM |
部分的(日時形式が異なる) | LOCAL_TIMESTAMP |
MySQL は、Oracle とは異なる日付 / 時刻形式を返します。日付と時刻の形式は、元の日付と時刻の形式と一致する必要があります(または別の日付関数を使用する必要があります)。SELECT LOCAL_TIMESTAMP FROM DUAL = 2019-01-01 10:01:01.0 |
CURRENT_DATE |
セッションのタイムゾーンでの現在の日付を返します。SELECT CURRENT_DATE FROM DUAL = 31-JAN-19 |
部分的(日時形式が異なる) | CURRENT_DATE |
MySQL は、Oracle とは異なる日付 / 時刻形式を返します。日付と時刻の形式は、元の日付と時刻の形式と一致する必要があります(または別の日付関数を使用する必要があります)。SELECT CURRENT_DATE FROM DUAL = 2019-01-31 |
CURRENT_TIMESTAMP |
セッションのタイムゾーンでの現在の日付と時刻を返します。SELECT CURRENT_TIMESTAMP FROM DUAL = 31-JAN-19 06.54.35.543146 AM +00:00 |
部分的(日時形式が異なる) | CURRENT_TIMESTAMP |
MySQL は、Oracle とは異なる日付 / 時刻形式を返します。日付と時刻の形式は、元の日付と時刻の形式と一致する必要があります(または別の日付関数を使用する必要があります)。SELECT CURRENT_TIMESTAMP FROM DUAL = 2019-01-31 06:55:07 |
ADD_MONTHS |
日付と、月を表す整数を返します。ADD_MONTHS(SYSDATE, 1) = 31-JAN-19 |
関数名の一部が異なる | ADDDATE |
同じ機能を実現するには、MySQL で ADDDATE 関数を使用します。ADDDATE(SYSDATE(), 1) = 2019-08-01 06:42:49.0 デフォルトでは、MySQL は Oracle とは異なる日付 / 時刻と範囲 / 形式を返します。日付と時刻の形式は、元の日付と時刻の形式と一致する必要があります(または別の日付関数を使用する必要があります)。 |
EXTRACT (date part) |
日付 / 時刻または期間の式から、指定された日付 / 時刻フィールドの値を返します。EXTRACT(YEAR FROM DATE '2019-01-31') = 2019 |
○ | EXTRACT (date part) |
Oracle と同等:EXTRACT(YEAR FROM DATE '2019-01-31') = 2019 |
LAST_DAY |
月の最終日の日付を返します。LAST_DAY('01-JAN-2019') = 31-JAN-19 |
部分的(日時形式が異なる) | LAST_DAY |
MySQL は、Oracle とは異なる日付 / 時刻形式を返します。日付と時刻の形式は、元の日付と時刻の形式と一致する必要があります(または別の日付関数を使用する必要があります)。LAST_DAY('2019-01-01') = 2019-01-31 |
MONTH_BETWEEN |
date1 と date2 の間の月数を返します。MONTHS_BETWEEN( SYSDATE, SYSDATE-60) = 1.96 |
関数名の一部が異なる | PERIOD_DIFF(date1,date2) |
MySQL の PERIOD_DIFF 関数は、2 つの月(YYMM または YYYYMM 形式)の差を整数として返します。PERIOD_DIFF( '201903', '201901') = 2 Oracle の MONTH_BETWEEN 関数と同じ値を取得するには、より具体的な変換が必要になります。 |
TO_CHAR (date/time) |
日付形式で指定された形式で、日付 / 時刻またはタイムスタンプのデータ型を VARCHAR2 データ型の値に変換します。TO_CHAR( SYSDATE,'DD-MM-YYYY HH24:MI:SS') = 01-01-2019 10:01:01 |
関数名の一部が異なる | DATE_FORMAT |
MySQL の DATE_FORMAT 関数は、日付を日付形式の定義で指定した形式に設定します。DATE_FORMAT( SYSDATE(),'%d-%m-%Y %H:%i:%s') = 01-01-2019 10:01:01 |
エンコーディング関数とデコーディング関数
Oracle の関数 | Oracle 関数の仕様または実装 | MySQL の同等関数 | MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
DECODE |
IF-THEN-ELSE ステートメントの機能を使用して、各検索値を 1 つずつ式と比較します。 |
× | CASE |
同等の機能を実現するには、MySQL CASE ステートメントを使用します。 |
DUMP |
データ型コード、長さ(バイト数)、指定された式の内部表現を含む VARCHAR2 値を返します。 |
× | なし | サポートされていません。 |
ORA_HASH |
指定した式のハッシュ値を計算します。 | × | MD5/SHA |
ハッシュ値を生成するには、MySQL の MD5 関数(128 ビットのチェックサムの場合)または SHA 関数(160 ビットのチェックサムの場合)を使用します。 |
変換関数
Oracle の関数 | Oracle 関数の仕様または実装 | MySQL の同等関数 | MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
CAST |
1 つの組み込みデータ型または集合型の値を別の組み込みデータ型または集合型の値に変換します。CAST('1' as int) + 1 = 2 |
部分的 | CAST |
MySQL の CAST 関数は Oracle の関数と同様ですが、必要な変換が明示的か暗黙的かによって調整が必要になることがあります。CAST('1' AS SIGNED) + 1 = 2 |
CONVERT |
文字列をある文字セットから別の文字セットに変換します。CONVERT('Ä Ê Í Õ Ø A B C D E ', 'US7ASCII', 'WE8ISO8859P1') = ?? ?? ?? A B C |
部分的 | CONVERT |
MySQL の CONVERT 関数で Oracle と同じ結果を取得するには、関数の構文とパラメータを調整する必要があります。CONVERT('Ä Ê Í A B C ' USING utf8) = Ä Ê Í A B C |
TO_CHAR (string/numeric) |
この関数は数値または日付を文字列に変換します。TO_CHAR(22.73,'$99.9') = $22.7 |
× | FORMAT |
MySQL の FORMAT 関数は、数値を '#,###.##' の形式に設定して特定の小数点以下の桁数に丸めてから、その結果を文字列として返します。したがって、Oracle とは異なる機能です。CONCAT('$', FORMAT(22.73, 1)) = $22.7 |
TO_DATE |
Oracle の TO_DATE 関数は、文字列をソース固有の日付 / 時刻形式の日付に変換します。TO_DATE( '2019/01/01', 'yyyy-mm-dd') = 01-JAN-2019 |
部分的(関数名と日付 / 時刻形式が異なる) | STR_TO_DATE |
MySQL の STR_TO_DATE 関数は文字列を取り、日付 / 時刻形式で指定された日付を返します。STR_TO_DATE( '2019/01/01', '%Y/%m/%d') = 2019-01-01 |
TO_NUMBER |
式を NUMBER データ型の値に変換します。TO_NUMBER('01234') = 1234 |
× | CAST |
Oracle の TO_NUMBER と同じ結果を返すには、代わりに MySQL の CAST 関数を使用します。CAST('01234' as SIGNED) = 1234 |
条件付き SELECT 関数
Oracle の関数 | Oracle 関数の仕様または実装 | MySQL の同等関数 | MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
CASE |
CASE ステートメントは、一連の条件に基づいて対応するステートメントを選択して実行します。構文は次のとおりです。CASE WHEN condition THEN result [WHEN ...] [ELSE result] END |
○ | CASE |
MySQL では、CASE 関数だけでなく、SELECT ステートメント内で IF/ELSE を使用して条件付きの処理を行うこともできます。CASE WHEN condition THEN result [WHEN ...] [ELSE result] END |
null 関数
Oracle の関数 | Oracle 関数の仕様または実装 | MySQL の同等関数 | MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
COALESCE |
式のリスト内の最初の null 以外の式を返します。COALESCE( null, '1', 'a') = a |
○ | COALESCE |
Oracle と同等:COALESCE( null, '1', 'a') = 1 |
NULLIF |
expr1 と expr2m を比較します。同じ式である場合は null を返します。同じ式ではない場合は、expr1 を返します。NULLIF('1', '2') = a |
○ | NULLIF |
Oracle と同等:NULLIF('1', '2') = a |
NVL |
null(空白として返される)をクエリ結果に含まれる文字列で置き換えます。NVL(null, 'a') = a |
× | IFNULL |
MySQL の同等の関数は IFNULL 関数です。これは、null 値を指定された文字列で置き換えます。IFNULL(null, 'a') = a |
NVL2 |
指定された式が null または null 以外であるかどうかによって、クエリで返す値を決定します。 |
× | CASE |
CASE ステートメントは、一連の条件を基に対応するステートメントを選択して実行します。 CASE WHEN condition THEN result [WHEN ...] [ELSE result] END |
環境関数と ID 関数
Oracle の関数 | Oracle 関数の仕様または実装 | MySQL の同等関数 | MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
SYS_GUID |
最大 16 バイトからなる、グローバルに一意の ID(RAW 値)を生成して返します。SELECT SYS_GUID() FROM DUAL = 8EFA4A31468B4C6DE05011AC0200009E |
× | REPLACE と UUID |
Oracle の SYS_GUID 関数をシミュレートするには、代わりに MySQL の REPLACE 関数と UUID 関数を使用します。REPLACE( UUID(), '-', '') |
UID |
セッション ユーザー(ログオンしているユーザー)を 一意に識別する整数を返します。 SELECT UID FROM DUAL = 43 |
× | なし | なし |
USER |
現在のセッション ユーザー名を返します。SELECT USER FROM DUAL = UserName |
部分的 | USER + INSTR + SUBSTR |
MySQL の USER 関数は、ユーザー名と接続サーバー(root@IP )を返します。ユーザー名のみを取得するには、サポート関数を追加で使用します。SELECT SUBSTR(USER(), 1, INSTR(USER(), '@') -1) FROM DUAL = root |
USERENV |
現在のユーザー セッションに関する情報と現在のパラメータ構成を返します。SELECT USERENV('LANGUAGE') FROM DUAL = ENGLISH_AMERICA.AL32UTF8 |
× | SHOW SESSION VARIABLES |
MySQL の SHOW SESSION VARIABLES ステートメントを使用して、現在のセッションの設定を表示します。SHOW SESSION VARIABLES LIKE '%collation%'; = utf8_general_ci |
ROWID |
Oracle サーバーは各テーブルの行ごとに、テーブル内でその行を識別する一意の ROWID を割り当てます。ROWID は行のアドレスであり、データ オブジェクト番号、行のデータブロック、行の位置、データファイルからなります。 |
× | なし | 可能であれば、他の MySQL 関数を使用して同じ機能をエミュレートするようにしてください。 |
ROWNUM |
Oracle によりテーブルまたは結合テーブルから行が選択される順番を表す数値を返します。 | × | なし | 可能であれば、他の MySQL 関数またはセッション変数を使用して同じ機能をエミュレートするようにしてください。 |
集計(グループ化)関数
Oracle の関数 | Oracle 関数の仕様または 実装 |
MySQL の 同等関数 |
MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
AVG |
列または式の平均値を返します。 | ○ | AVG |
Oracle と同等 |
COUNT |
クエリによって返される行数を返します。 | ○ | COUNT |
Oracle と同等 |
COUNT (DISTINCT) |
列または式に含まれる固有の値の数を返します。 | ○ | COUNT (DISTINCT) |
Oracle と同等。 |
MAX |
列または式の最大値を返します。 | ○ | MAX |
Oracle と同等。 |
MIN |
列または式の最小値を返します。 | ○ | MIN |
Oracle と同等。 |
SUM |
列または式の値の合計を返します。 | ○ | SUM |
Oracle と同等。 |
LISTAGG |
測定列の各グループに含まれる値を連結して、ORDER BY 句で指定された単一行でグループ内のデータを表示します。SELECT LISTAGG( DEPARTMENT_NAME, ', ') WITHIN GROUP (ORDER BY DEPARTMENT_NAME) DEPT FROM DEPARTMENTS; |
× | GROUP_CONCAT |
Oracle と同様の結果を取得するには、MySQL の GROUP_CONCAT 関数を使用します。ただし、構文が異なる場合があります。SELECT GROUP_CONCAT( DEPARTMENT_NAME ORDER BY DEPARTMENT_NAME SEPARATOR ', ') DEPT FROM DEPARTMENTS; |
Oracle 12c でのフェッチ
Oracle の関数 | Oracle 関数の仕様または 実装 |
MySQL の 同等関数 |
MySQL の対応関数 | MySQL 関数の仕様または実装 |
---|---|---|---|---|
FETCH |
複数行クエリの結果セットからデータ行を取得します。SELECT * FROM EMPLOYEES FETCH FIRST 10 ROWS ONLY; |
× | LIMIT | 特定のレコードセットのみを取得するには、MySQL の LIMIT 句を使用します。SELECT * FROM EMPLOYEES LIMIT 10; |
基本的なフィルタリング、演算子、サブクエリ
基本的なフィルタリング、演算子関数、サブクエリは、最小限の追加の作業を行うだけで比較的簡単に変換できます。
変換に関する注記
デフォルトで返される日付形式は Oracle と MySQL で異なるため、日付の形式を確認し、必要な処置を行う必要があります。
- Oracle の
SYSDATE
関数はデフォルトで01-AUG-19
を返します。 - MySQL の
SYSDATE()
関数はデフォルトで2019-08-01 12:04:05
を返します。 - 日付 / 時刻形式を設定するには、MySQL の
[DATE_FORMAT](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format)
関数または[STR_TO_DATE](https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_str-to-date)
関数を使用します。
Oracle の関数またはサブクエリ | MySQL の同等関数 | MySQL の対応関数またはサブクエリ | 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); |
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 では、JOIN ステートメントを使用する場合と WHERE/AND 句でフィルタリングを行う場合に、SELECT レベルでサブクエリを使用できます。-- 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; |
演算子 | ○ | 演算子 | MySQL は、基本的な演算子をすべてサポートしています。> | >= | < | <= | = | <> | != |
分析関数(またはウィンドウ関数とランキング関数)
Oracle の分析関数では、標準 SQL の分析関数の機能を拡張して、行のグループに基づいて集約値を計算できます。これらの関数は、単一のクエリ式の範囲内で論理的に分割された結果セットに適用できます。これらの関数は一般にビジネス インテリジェンス レポートおよびアナリティクスと組み合わせて使用されます。分析的ではない複雑な SQL コードの代わりに分析関数を使用すると、クエリのパフォーマンスが向上する可能性があります。
変換に関する注記
- MySQL バージョン 5.7 には、単純な SQL ステートメントの変換をサポートする分析関数はありません。ただし、この機能は部分的に MySQL バージョン 8 に追加されているため、分析関数の変換に留意する必要があります。移行プロセス全体で手動による追加作業が必要となる可能性があるためです。
- オプションのソリューションとして、分析関数を使用しないようにコードを作成し直して従来の SQL コード ソリューションに戻すことができます。また、このロジックをアプリケーション層に移すこともできます。
次の表に、Oracle の一般的な分析関数を示します。
関数ファミリー | 関連する関数 | MySQL 5.7 での対応状況 |
---|---|---|
分析とランキング | RANK AVERAGE_RANK DENSE_RANK RANK ROW_NUMBER PERCENT_RANK CUME_DIST NTILE FIRST_VALUE LAST_VALUE OVER (PARTITION BY...) |
× |
階層表示 | CONNECT BY HIER_ANCESTOR HIER_CHILD_COUNT HIER_DEPTH HIER_LEVEL HIER_ORDER HIER_PARENT HIER_TOP |
× |
ラグ | LAG LAG_VARIANCE LAG_VARIANCE_PERCENT LEAD LEAD_VARIANCE LEAD_VARIANCE_PERCENT |
× |
共通テーブル式(CTE)
CTE では、一連のコードのロジックを実装して、複雑すぎるか何度も使用するには効率的ではないと考えられる SQL コードを再利用できます。CTE に名前を付けた後、SQL ステートメントのさまざまな部分で WITH
句を使って CTE を複数回使用できます。
変換に関する注記
- CTE は MySQL バージョン 5.7 ではサポートされませんが、MySQL バージョン 8 ではサポートされます。
- 代わりに、派生テーブル / サブクエリを使用するか、CTE 機能を使用しないように SQL ステートメントを作成し直してください。
例
Oracle |
---|
WITH DEPT_COUNT (DEPARTMENT_ID, DEPT_COUNT) AS (SELECT DEPARTMENT_ID, COUNT(*) FROM EMPLOYEES GROUP BY DEPARTMENT_ID) |
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; |
MERGE ステートメント
MERGE
(または UPSERT
)ステートメントを使用すると、1 つの DML オペレーションを別個に実行するのではなく、1 つの MERGE
オペレーションの中で条件付きで複数の DML オペレーションを実行する単一の SQL ステートメントを指定できます。ソーステーブルからレコードを選択した後、論理構造を指定することによって、ターゲット テーブルに対して複数の DML オペレーションを自動的に実行します。この機能を使用すると、挿入、更新、削除を何度も行う必要がありません。MERGE
は確定的なステートメントです。つまり、MERGE
ステートメントで行が処理された後、その行を同じ MERGE
ステートメントで再処理することはできません。
変換に関する注記
Oracle とは異なり、MySQL バージョン 5.7 では MERGE
機能をサポートしていません。MERGE
機能を部分的にシミュレートするために、MySQL には REPLACE
ステートメントと INSERT… ON DUPLICATE KEY UPDATE
ステートメントが用意されています。
REPLACE
:INSERT
ステートメントと同じように機能しますが、テーブル内の古い行に新しい行のPRIMARY KEY
またはUNIQUE
インデックスと同じ値が設定されている場合、古い行が削除されてから新しい行が挿入されます。INSERT… ON DUPLICATE KEY UPDATE
: 挿入された行によってPRIMARY KEY
またはUNIQUE
インデックスの値が重複する場合、重複するキーによる例外が発生しないよう、古い行のUPDATE
が行われます。次に例を示します。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;
代わりに、MERGE
機能をストアド プロシージャに変換し、例外 / 重複の処理で INSERT
、UPDATE
、DELETE
コマンドを使用して DML オペレーションを管理することもできます。
SQL ステートメントのヒント
Oracle では、クエリ実行計画の効率化を目的に、ユーザーが豊富な SQL クエリヒントを使用してオプティマイザーの動作と決定に影響を与えられるようになっています。Oracle のデータベースでは 60 種類を超えるヒントがサポートされていますが、MySQL で使用できるクエリヒントの数は限られています。
MySQL バージョン 5.7 では通常、OPTIMIZER
HINTS
と INDEX HINTS
の 2 種類のクエリヒントをサポートしています。MySQL オプティマイザーのヒントを使用すると、個々の SQL ステートメントでオプティマイザーの動作を制御できます。例:
SELECT /*+ NO_RANGE_OPTIMIZATION(tbl PRIMARY, col1_idx) */ col1 FROM tbl;
MySQL バージョン 5.7 で使用できるオプティマイザー ヒント
ヒント名 | ヒントの概要 | 適用範囲 |
---|---|---|
BKA, NO_BKA |
BKA(Batched Key Access)結合処理に影響を与えます。 | クエリブロック、テーブル |
BNL, NO_BNL |
BNL(Block Nested-Loop)結合処理に影響を与えます。 | クエリブロック、テーブル |
MAX_EXECUTION_TIME |
ステートメントの実行時間を制限します。 | グローバル |
MRR, NO_MRR |
MRR(Multi-Range Read)最適化に影響を与えます。 | テーブル、インデックス |
NO_ICP |
ICP(Index Condition Pushdown)最適化に影響を与えます。 | テーブル、インデックス |
NO_RANGE_OPTIMIZATION |
範囲最適化に影響を与えます。 | テーブル、インデックス |
QB_NAME |
クエリブロックに名前を割り当てます。 | クエリブロック |
SEMIJOIN, NO_SEMIJOIN |
準結合戦略に影響を与えます。 | クエリブロック |
SUBQUERY |
マテリアル化、IN 〜EXISTS のサブクエリ戦略に影響を与えまます。 |
クエリブロック |
MySQL のインデックス ヒントは、クエリ処理中のインデックスの選択方法に関する情報をオプティマイザーに提供します。USE
、FORCE
、または IGNORE
キーワードを使用して、オプティマイザーによるインデックスの使用プロセスを制御します。次に例を示します。
SELECT * FROM tbl USE INDEX (col1_index, col2_index);
-- OR
SELECT * FROM tbl IGNORE INDEX (col1_index, col2_index);
変換に関する注記
Oracle と MySQL オプティマイザーは根本的に異なり、Oracle と MySQL のクエリヒントの重複部分は限られているため、クエリヒントが指定されていないすべての Oracle SQL ステートメントをターゲット MySQL データベースに変換することをおすすめします。
MySQL のツール(リアルタイム パフォーマンス ダッシュボードの MySQL Workbench など)と機能を使用して、MySQL のパフォーマンスを調整してください。たとえば、実行計画を使ってクエリを検査し、ユースケースに応じてインスタンス / セッション パラメータを調整します。
実行計画
実行計画の主な目的は、クエリ オプティマイザーがデータベースのデータにアクセスする際に行った選択についての詳細を提供することです。クエリ オプティマイザーによって、データベース ユーザー用に SELECT
、INSERT
、UPDATE
、DELETE
の各ステートメントの実行計画が生成されます。また、管理者は特定のクエリや DML オペレーションについての理解を深めることができます。これは、クエリのパフォーマンスを調整する場合に非常に有効です。たとえば、インデックスのパフォーマンスを確認する場合や、作成する必要があるインデックスがあるかどうかを判断する場合に役立ちます。
実行計画は、データ量、データ統計、インスタンス パラメータ(グローバル パラメータまたはセッション パラメータ)によって影響される可能性があります。
変換に関する考慮事項
実行計画は移行の必要があるデータベース オブジェクトではありません。これは、同じデータセットに対して同じステートメントを実行する場合に、Oracle と MySQL の間のパフォーマンスの違いを分析するためのツールです。
MySQL でサポートしている実行計画の構文、機能、出力は、Oracle とは異なります。
例
Oracle の実行計画 |
---|
SQL> EXPLAIN PLAN FOR SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID = 105; |
MySQL の実行計画 |
mysql> EXPLAIN SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID = 105; |
ストアド プロシージャ、関数、トリガー
PL/SQL は Oracle の拡張プロシージャ言語であり、データベース内でコードベースのソリューションを作成、保管、適用するために使用されます。通常、データベースのストアド プロシージャと関数は、Oracle の PL/SQL、PostgreSQL の PL/pgSQL、MySQL の MySQL プロシージャ言語などの ANSI SQL および SQL 拡張プロシーシャ言語からなるコード要素です。MySQL では固有の拡張プロシージャ言語にデータベースと同じ名前を使用しています。
これらのストアド プロシージャと関数の目的は、パフォーマンス、互換性、セキュリティなどの要件に応じて、アプリケーションからではなくデータベース内から実行するのに適したソリューションを提供することです。ストアド プロシージャと関数では両方とも PL/SQL を使用しますが、ストアド プロシージャは主に DDL/DML オペレーションを実行するために使用されます。関数は主に、計算を行って特定の結果を返すために使用されます。
PL/SQL から MySQL へのプロシージャ言語の移行
Oracle PL/SQL から MySQL へのコードの移行という観点では、MySQL プロシージャの実装は Oracle の実装と異なります。したがって、コードを移行するには Oracle の PL/SQL 機能を MySQL のストアド プロシージャと関数に変換する必要があります。さらに、Oracle のパッケージとパッケージ本体は MySQL ではサポートされていないため、コードを変換する際は、これらの要素を個々の MySQL コードに変換(または解析)する必要があります。MySQL のストアド プロシージャと関数はルーティンとも呼ばれます。
コード オブジェクトのオーナー
Oracle では、ストアド プロシージャまたは関数のオーナーは特定のユーザーですが、MySQL ではデータベース ユーザーがデータベースで作成した特定のスキーマです。
コード オブジェクトの権限とセキュリティ
Oracle でストアド プロシージャまたは関数を作成するには、CREATE PROCEDURE
システム権限が必要です(他のユーザーでプロシージャまたは関数を作成するには、CREATE
ANY PROCEDURE
権限が必要です)。ストアド プロシージャまたは関数を実行するには、データベース ユーザーに EXECUTE
権限が必要です。
MySQL では、コード要素を作成するには CREATE
ROUTINE
権限が必要です。また、実行するには EXECUTE
権限が必要です。MYSQL の DEFINER
句は、ユーザーをコード オブジェクトの作成者として定義しますが、そのユーザーには CREATE ROUTINE
権限などの適切な権限が必要です。
MySQL のストアド プロシージャと関数の構文
次の例は、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