OracleからMySQLへのテーブル定義（DDL）の移行時のトラブルシューティング

[OracleからMySQLへのテーブル定義（DDL）の移行](https://qiita.com/C_HERO/items/3ddc6be93414b448ad50)の際に発生したエラーとその解決方法です。

## 環境と前提条件

- OS（ローカルPC）：Windows10
- OS（MySQLインストール先）：CentOS6.8
- 移行元DB：Oracle Database 12c
- 移行先DB：MySQL8.0

## 使用ツール、方法
- Oracleからのデータエクスポート：SQL Developer
- Oracle → MySQLへDDLコンバート：Sqlines
- データインポート：Linuxコマンド

## エラーとその解決方法
## 1. テーブル定義（DDL）インポート to MySQL
#### （1）You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETENTION~.

構文エラー（syntax error）です。
DDLの内容が以下のような場合に出ます。

```sql:修正前
CREATE TABLE `HOGE`.`FOO`
 (	`XXXXX` BIGINT,
`YYYYY` VARCHAR(200),
`ZZZZZ` DATETIME
.....
 )
RETENTION
NOCACHE LOGGING ) ;
```
RETENTION以降はLOB型の列の保持に関する記述で、MySQLのCREATE TABLE文これに相当するものはないので、RETENTION以降を削除して以下のようにしてあげればOK。

```sql:修正後
CREATE TABLE `HOGE`.`FOO`
 (	`XXXXX` BIGINT,
`YYYYY` VARCHAR(200),
`ZZZZZ` DATETIME
......
 );
```

### (2) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'KEEP_DUPLICATES~.

こちらも構文エラー（syntax error）。
DDLの内容が以下のような場合に出ます。

```sql:修正前
CREATE TABLE `HOGE`.`FOO`
 (	`XXXXX` BIGINT,
`YYYYY` VARCHAR(200),
`ZZZZZ` DATETIME
.....
 )
KEEP_DUPLICATES
STORAGE(INITIAL 106496 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT))
LOB (`XML_CLOB`) STORE AS SECUREFILE (
TABLESPACE `TCLB_DAT_TS` ENABLE STORAGE IN ROW CHUNK 8192
NOCACHE LOGGING  NOCOMPRESS  KEEP_DUPLICATES
STORAGE(INITIAL 106496 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)) ;
```
KEEP_DUPLICATES以降は重複除外に関する記述で、MySQLのCREATE TABLE文にはこれに相当するものはないので、KEEP_DUPLICATES以降を削除して以下のようにしてあげればOK。

```sql:修正後
CREATE TABLE `HOGE`.`FOO`
 (	`XXXXX` BIGINT,
`YYYYY` VARCHAR(200),
`ZZZZZ` DATETIME
.....
 );
```

### (3) Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
ストレージエンジンがInnoDBでページサイズが16KBの場合、3072バイトを超えるデータ型が宣言されていると、このエラーが出ます。
1文字あたり、文字コードがutf8の場合は3バイト、utf8mb4の場合は4バイト消費するので、前者はVARCHAR(1024）、後者はVARCHAR(768)が最大になりますね。

```sql:修正前
CREATE TABLE `HOGE`.`FOO`
 (	`XXXXX` INT,
`YYYYY` VARCHAR(4000),
`ZZZZZ` DATETIME,
.....
 )
;
```
もともとのデータ長を削るのは不具合のもとなので、BLOBかLONGTEXTに変換してあげることで対処しましょう。

```sql:修正後
CREATE TABLE `HOGE`.`FOO`
 (	`XXXXX` INT,
`YYYYY` LONGTEXT,
`ZZZZZ` DATETIME,
.....
 )
;

```

#### (4) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SYSDATE(),

日付周りの構文エラーがあると、このエラーが出ます。

```sql:修正前
CREATE TABLE `HOGE`.`FOO`
 (	`XXXXX` VARCHAR(50),
`YYYYY` DATETIME DEFAULT SYSDATE(),
`ZZZZZ` VARCHAR(100),
......
 )
;
```
上記の場合、
DATETIME DEFAULT SYSDATE()
を
DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
に修正してあげれば大丈夫。

```sql:修正後
CREATE TABLE `HOGE`.`FOO`
 (	`XXXXX` VARCHAR(50),
`YYYYY` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ZZZZZ` VARCHAR(100),
......
 )
;
```
### 3. VIEW定義（DDL）インポート to MySQL
####(1) Table 'HOGE.FOO' doesn't exist
テーブルが存在しません、というこのエラー。
本当に対象のテーブルがないこともありますが（この場合は作成する）、MySQLでは、デフォルトでは、テーブル名の大文字と小文字が区別されるので（※）、このエラーにはまることがあります。
VIEWの大文字、小文字を確認してそちらもそろえた内容にしましょう。

※大文字、小文字を区別しているかは、以下を実行すればわかります。
　table_namesとありますが、VIEWも同様です。

```sql
show variables where variable_name='lower_case_table_names';
```
取りうる値と意味合いは以下の通り。

|値 | 意味|
|---|---|
|0|大文字小文字を区別する（デフォルト）|
|1|大文字小文字を区別しない（テーブル名をすべて小文字にして格納）|
|2|大文字小文字を区別しない（テーブル名をそのまま格納；ただし、InnoDBでは全て小文字）|


####(2) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at ~
「)」に原因があるのかと思いきや、外部結合演算子(+)を使用していると、このエラーが出ます。

```sql:修正前
CREATE OR REPLACE VIEW `FOO_VIEW` (`aaaaa`, `bbbbb`, `ccccc`, `ddddd`) AS
SELECT FOO.AAAAA, FOO1.YYYYY, FOO.BBBBB
FROM   FOO,
       ( SELECT XXXXX, YYYYY FROM FOO1_TABLE WHERE ZZZZZ = 1) FOO1,
WHERE  FOO.XXXXX = FOO1.CCCCC (+)
;

```

JOIN句を使用した内容に書き換えてあげればOK。

```sql:修正後
CREATE OR REPLACE VIEW `FOO_VIEW` (`aaaaa`, `bbbbb`, `ccccc`, `ddddd`) AS
SELECT FOO.AAAAA, FOO1.YYYYY, FOO.BBBBB
FROM   FOO
LEFT OUTER JOIN  ( SELECT XXXXX, YYYYY FROM FOO1_TABLE WHERE ZZZZZ = 1) FOO1 ON FOO.XXXXX = FOO1.CCCCC 
;
```
####(3) 'FOO' is not BASE TABLE
MySQLでVIEWにコメントをつけようとするとこのエラーが出ます。

```sql:修正前
CREATE OR REPLACE VIEW `FOO_VIEW` (`aaaaa`, `bbbbb`, `ccccc`, `ddddd`) AS
SELECT FOO.AAAAA, FOO1.YYYYY, FOO.BBBBB
FROM   FOO
LEFR OUTER JOIN  ( SELECT XXXXX, YYYYY FROM FOO1_TABLE WHERE ZZZZZ = 1) FOO1 ON FOO.XXXXX = FOO1.CCCCC
;

ALTER TABLE `FOO_VIEW`  COMMENT 'Bery Bery Mg Mg Calcium Str Bari Bari Lan Lan Lan'
;
```
MySQLには、VIEWにコメントを付けるオプションがないので、コメントに当たる箇所（上では、ALTER TABLE以降）を削除してあげればOK。
※ALTER VIEWにしても構文エラーになります。

```sql:修正後
CREATE OR REPLACE VIEW `FOO_VIEW` (`aaaaa`, `bbbbb`, `ccccc`, `ddddd`) AS
SELECT FOO.AAAAA, FOO1.YYYYY, FOO.BBBBB
FROM   FOO
LEFR OUTER JOIN  ( SELECT XXXXX, YYYYY FROM FOO1_TABLE WHERE ZZZZZ = 1) FOO1 ON FOO.XXXXX = FOO1.CCCCC
;
```

## 終わりに
異なるDBへのテーブル等の移行は困難がつきものですが、ひとつひとつ課題をクリアしていきましょう！

## 参考
- [11 LOB記憶域 | Oracle® Database SecureFilesおよびラージ・オブジェクト開発者ガイド 11gリリース2 (11.2)](https://docs.oracle.com/cd/E16338_01/appdev.112/b56263/adlob_tables.htm)
- [4 Oracle SecureFiles LOBの使用 | Oracle® Database SecureFilesおよびラージ・オブジェクト開発者ガイド 11gリリース2 (11.2)](https://docs.oracle.com/cd/E16338_01/appdev.112/b56263/adlob_smart.htm)
- [津島博士のパフォーマンス講座　
第28回 表圧縮とLOBデータ型について | Oracle Technology Network](https://www.oracle.com/technetwork/jp/database/articles/tsushima/tsushima-28-1966240-ja.html)
- [3 Oracle LOB記憶域の使用 | SecureFiles and Large Objects Developer's Guide](https://docs.oracle.com/cd/E82638_01/adlob/using-oracle-LOBs-storage.html#GUID-EC76077B-3EE9-491E-AC6D-171DA919B84C)
- [MySQL道普請便り 第32回　InnoDBインデックスの最大キー長について | gihyo.jp](https://gihyo.jp/dev/serial/01/mysql-road-construction-news/0032)
- [MySQLで登録日時と更新日時を自動的に設定する | みけぽんブログ -自称中級SEの戯言-](https://mikepon.jp/mysql-create-update-at/)
- [MySQL 8.0 Reference Manual 13.1.20 CREATE TABLE Statement | MySQL](https://dev.mysql.com/doc/refman/8.0/en/create-table.html)
- [MySQL 8.0 Reference Manual 13.1.23 CREATE VIEW Statement | MySQL](https://dev.mysql.com/doc/refman/8.0/en/create-view.html)
- [MySQL 8.0 Reference Manual 9.2.3 Identifier Case Sensitivity | MySQL](https://dev.mysql.com/doc/refman/8.0/en/identifier-case-sensitivity.html)
- [テーブル名で大文字・小文字の区別をしているか確認するには （ MySQL ・ SQLServer ・ PostgreSQL ・ SQLite ）| みどりのウェブ開発日記](https://web-atelier-midori.com/blog/%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9/mysql/1519/)