

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 從 Oracle 遷移至 Amazon RDS for MySQL 或 Amazon Aurora MySQL AWS Schema Conversion Tool
<a name="CHAP_Source.Oracle.ToMySQL"></a>

若要在轉換後的 MySQL 程式碼中模擬 Oracle 資料庫函數，請使用 Oracle 到 MySQL 延伸套件 AWS SCT。如需詳細了解延伸套件，請參閱：[搭配 使用延伸套件 AWS Schema Conversion Tool](CHAP_ExtensionPack.md)。

**Topics**
+ [MySQL 做為目標資料庫的權限](#CHAP_Source.Oracle.ToMySQL.ConfigureTarget)
+ [Oracle 到 MySQL 的轉換設定](#CHAP_Source.Oracle.ToMySQL.ConversionSettings)
+ [遷移考量事項](#CHAP_Source.Oracle.ToMySQL.MigrationConsiderations)
+ [將 Oracle 中的 WITH 陳述式轉換為 RDS for MySQL 或 Amazon Aurora MySQL](#CHAP_Source.Oracle.ToMySQL.With)

## MySQL 做為目標資料庫的權限
<a name="CHAP_Source.Oracle.ToMySQL.ConfigureTarget"></a>

做為目標的 MySQL 所需的權限如下：
+ CREATE ON \$1.\$1
+ ALTER ON \$1.\$1
+ DROP ON \$1.\$1
+ INDEX ON \$1.\$1
+ ON \$1.\$1 參考資料
+ SELECT ON \$1.\$1
+ 在 \$1.\$1 上建立檢視
+ SHOW VIEW ON \$1.\$1
+ 觸發開啟 \$1.\$1
+ 建立路由開啟 \$1.\$1
+ ALTER ROUTINE ON \$1.\$1
+ EXECUTE ON \$1.\$1
+ 在 \$1.\$1 上建立暫存資料表
+ AWS\$1LAMBDA\$1ACCESS
+ INSERT，更新 AWS\$1ORACLE\$1EXT.\$1
+ 在 AWS\$1ORACLE\$1EXT\$1DATA 上插入、更新、刪除。\$1

如果您使用 MySQL 資料庫 5.7 版或更低版本做為目標，請授予 INVOKE LAMBDA \$1.\$1 許可，而非 AWS\$1LAMBDA\$1ACCESS。對於 MySQL 資料庫 8.0 版和更新版本，授予 AWS\$1LAMBDA\$1ACCESS 許可。

您可以使用下列程式碼範例來建立資料庫使用者並授與權限。

```
CREATE USER 'user_name' IDENTIFIED BY 'your_password';
GRANT CREATE ON *.* TO 'user_name';
GRANT ALTER ON *.* TO 'user_name';
GRANT DROP ON *.* TO 'user_name';
GRANT INDEX ON *.* TO 'user_name';
GRANT REFERENCES ON *.* TO 'user_name';
GRANT SELECT ON *.* TO 'user_name';
GRANT CREATE VIEW ON *.* TO 'user_name';
GRANT SHOW VIEW ON *.* TO 'user_name';
GRANT TRIGGER ON *.* TO 'user_name';
GRANT CREATE ROUTINE ON *.* TO 'user_name';
GRANT ALTER ROUTINE ON *.* TO 'user_name';
GRANT EXECUTE ON *.* TO 'user_name';
GRANT CREATE TEMPORARY TABLES ON *.* TO 'user_name';
GRANT AWS_LAMBDA_ACCESS TO 'user_name';
GRANT INSERT, UPDATE ON AWS_ORACLE_EXT.* TO 'user_name';
GRANT INSERT, UPDATE, DELETE ON AWS_ORACLE_EXT_DATA.* TO 'user_name';
```

在上述範例中，請將 *user\$1name* 替換為您的使用者名稱。然後，將 *your\$1password* 替換為一個安全的密碼。

如果您使用 MySQL 資料庫 5.7 版或更低版本做為目標，請使用 `GRANT INVOKE LAMBDA ON *.* TO 'user_name'`而非 `GRANT AWS_LAMBDA_ACCESS TO 'user_name'`。

若要使用 Amazon RDS for MySQL 或 Aurora MySQL 作為目標，請將 `lower_case_table_names` 參數設定為 `1`。此值意味著 MySQL 服務器在處理資料表、索引、觸發程式和資料庫等對象名稱的識別碼時不區分大小寫。如果您已在目標執行個體中開啟二進位記錄功能，請將 `log_bin_trust_function_creators` 參數設定為 `1`。在這種情況下，您不需要使用 `DETERMINISTIC`、`READS SQL DATA` 或 `NO SQL` 特性來建立已儲存的函數。若要設定這些參數，請建立新的參數群組，或是修改現有的資料庫參數群組。

## Oracle 到 MySQL 的轉換設定
<a name="CHAP_Source.Oracle.ToMySQL.ConversionSettings"></a>

若要編輯 Oracle 到 MySQL 轉換設定，請選擇 中的**設定** AWS SCT，然後選擇**轉換設定**。從上方清單中，選擇 **Oracle**，然後選擇 **Oracle – MySQL**。 AWS SCT 會顯示 Oracle 到 MySQL 轉換的所有可用設定。

中的 Oracle 到 MySQL 轉換設定 AWS SCT 包含下列項目的選項：
+ 限制轉換程式碼中具有動作項目的註解數量。

  針對**所選嚴重性及更高層級之動作項目的轉換後程式碼中新增註解**，請選擇動作項目的嚴重性。針對所選嚴重性及更高層級的動作項目，在轉換後程式碼中 AWS SCT 新增註解。

  例如，若要將已轉換程式碼中的註解數量降到最低，請選擇**僅限錯誤**。若要在已轉換的程式碼中包含所有動作項目的註解，請選擇**所有訊息**。
+ 若要解決來源 Oracle 資料庫可以使用`ROWID`虛擬資料欄，但 MySQL 不支援類似的功能。 AWS SCT 可以在轉換後的程式碼中模擬`ROWID`虛擬資料欄。若要這樣做，請選擇**產生作為產生資料列 ID 的身分****？**。

  如果您的來源 Oracle `ROWID` 程式碼不使用虛擬資料欄，請選擇**不為產生資料列 ID 產生** **？** 在此情況下，轉換後的程式碼運作得更快。
+ 在包含具有 MySQL 不支援之參數的 `TO_CHAR`、 和 `TO_NUMBER`函數時`TO_DATE`，使用來源 Oracle 程式碼。根據預設， 會在轉換後的程式碼中 AWS SCT 模擬這些參數的使用情況。

  當您的來源 Oracle 程式碼僅包含 PostgreSQL 支援的參數時，您可以使用原生 MySQL `TO_CHAR`、 `TO_DATE`和 `TO_NUMBER`函數。在此情況下，轉換後的程式碼運作得更快。若要僅包含這些參數，請選取下列值：
  + **函數 TO\$1CHAR() 不使用 Oracle 特定的格式字串**
  + **函數 TO\$1DATE() 不使用 Oracle 特定的格式字串**
  + **函數 TO\$1NUMBER() 不使用 Oracle 特定的格式字串**
+ 新增資料庫和應用程式是否在不同時區執行。根據預設， AWS SCT 會在轉換後的程式碼中模擬時區。但是，當您的資料庫和應用程式使用相同的時區時，就不需要此模擬。在此情況下，請選取**用戶端的時區與伺服器上的時區相符**。

## 遷移考量事項
<a name="CHAP_Source.Oracle.ToMySQL.MigrationConsiderations"></a>

當您將 Oracle 轉換為 RDS for MySQL 或 Aurora MySQL 時，若要變更陳述式執行的順序，您可以使用`GOTO`陳述式和標籤。任何遵循陳述式的 PL/SQL `GOTO`陳述式都會略過，處理會在標籤繼續。您可以在程序、批次或`GOTO`陳述式區塊內的任何位置使用陳述式和標籤。您也可以下一個 GOTO 陳述式。

MySQL 不使用 `GOTO` 陳述式。當 AWS SCT 轉換包含`GOTO`陳述式的程式碼時，它會將陳述式轉換為使用 `BEGIN…END`或 `LOOP…END LOOP`陳述式。

您可以在下表中找到如何 AWS SCT 轉換`GOTO`陳述式的範例。


| Oracle 陳述式 | MySQL 陳述式 | 
| --- | --- | 
|  <pre>BEGIN<br />   ....<br />   statement1;<br />   ....<br />   GOTO label1;<br />   statement2;<br />   ....<br />   label1:<br />   Statement3;<br />   ....<br />END<br /></pre>  |  <pre>BEGIN<br /> label1:<br /> BEGIN<br />   ....<br />   statement1;<br />   ....<br />   LEAVE label1;<br />   statement2;<br />   ....<br /> END;<br />   Statement3;<br />   ....<br />END<br /></pre>  | 
|  <pre>BEGIN<br />   ....<br />   statement1;<br />   ....<br />   label1:<br />   statement2;<br />   ....<br />   GOTO label1;<br />   statement3;<br />   ....<br />   statement4;<br />   ....<br />END<br /></pre>  |  <pre>BEGIN<br />   ....<br />   statement1;<br />   ....<br />   label1:<br />   LOOP<br />    statement2;<br />    ....<br />    ITERATE label1;<br />    LEAVE label1;<br />   END LOOP; <br />    statement3;<br />    ....<br />    statement4;<br />    ....<br />END<br /></pre>  | 
|  <pre>BEGIN<br />   ....<br />   statement1;<br />   ....<br />   label1:<br />   statement2;<br />   ....<br />   statement3;<br />   ....<br />   statement4;<br />   ....<br />END<br /></pre>  |  <pre>BEGIN<br />   ....<br />   statement1;<br />   ....<br />   label1:<br />   BEGIN<br />    statement2;<br />    ....    <br />    statement3;<br />    ....<br />    statement4;<br />    ....    <br />   END; <br />END<br /></pre>  | 

## 將 Oracle 中的 WITH 陳述式轉換為 RDS for MySQL 或 Amazon Aurora MySQL
<a name="CHAP_Source.Oracle.ToMySQL.With"></a>

您可以使用 Oracle 的 WITH 子句 (subquery\$1factoring) 對子查詢區塊指派名稱 (query\$1name)。接著，您即可透過指定 query\$1name 在查詢中的多處位置參考該子查詢區塊。如果子查詢區塊不包含連結或參數 （本機、程序、函數、套件），則 會將 子句 AWS SCT 轉換為檢視或暫存資料表。

將子句轉換為暫時資料表的優點是，對子查詢的重複引用可能會更有效率。效率更高的是因為資料很容易從暫時資料表中檢索，而不是每個引用都需要。您可以使用其他檢視或暫時資料表來模擬此項目。視圖名稱會使用格式 `<procedure_name>$<subselect_alias>`。

您可以在下表中找到範例。


| Oracle 陳述式 | MySQL 陳述式 | 
| --- | --- | 
|  <pre>CREATE PROCEDURE <br /> TEST_ORA_PG.P_WITH_SELECT_VARIABLE_01<br />     (p_state IN NUMBER)<br />AS<br />  l_dept_id NUMBER := 1; <br />BEGIN<br />FOR cur IN  <br />           (WITH dept_empl(id, name, surname, <br />              lastname, state, dept_id)<br />              AS<br />                  (<br />                    SELECT id, name, surname,  <br />                     lastname, state, dept_id <br />                      FROM test_ora_pg.dept_employees<br />                     WHERE state = p_state AND <br />                       dept_id = l_dept_id)<br />            SELECT id,state   <br />              FROM dept_empl<br />            ORDER BY id)  LOOP<br />  NULL;<br />END LOOP;<br /></pre>  |  <pre>CREATE PROCEDURE test_ora_pg.P_WITH_SELECT_VARIABLE_01(IN par_P_STATE DOUBLE)<br />BEGIN<br />    DECLARE var_l_dept_id DOUBLE DEFAULT 1;<br />    DECLARE var$id VARCHAR (8000);<br />    DECLARE var$state VARCHAR (8000);<br />    DECLARE done INT DEFAULT FALSE;<br />    DECLARE cur CURSOR FOR SELECT<br />        ID, STATE<br />        FROM (SELECT<br />            ID, NAME, SURNAME, LASTNAME, STATE, DEPT_ID<br />            FROM TEST_ORA_PG.DEPT_EMPLOYEES<br />            WHERE STATE = par_p_state AND DEPT_ID = var_l_dept_id) AS dept_empl<br />        ORDER BY ID;<br />    DECLARE CONTINUE HANDLER FOR NOT FOUND<br />        SET done := TRUE;<br />    OPEN cur;<br /><br />    read_label:<br />    LOOP<br />        FETCH cur INTO var$id, var$state;<br /><br />        IF done THEN<br />            LEAVE read_label;<br />        END IF;<br /><br />        BEGIN<br />        END;<br />    END LOOP;<br />    CLOSE cur;<br />END;<br /></pre>  | 
|  <pre>CREATE PROCEDURE <br /> TEST_ORA_PG.P_WITH_SELECT_REGULAR_MULT_01<br />AS    <br />BEGIN<br /><br /> FOR cur IN  (<br />               WITH dept_empl AS<br />                   (<br />                        SELECT id, name, surname, <br />                         lastname, state, dept_id <br />                          FROM test_ora_pg.dept_employees<br />                         WHERE state = 1),<br />                    dept AS <br />                   (SELECT id deptid, parent_id, <br />                      name deptname<br />                      FROM test_ora_pg.department                <br />                   )<br />                SELECT dept_empl.*,dept.*          <br />                 FROM dept_empl, dept<br />                 WHERE dept_empl.dept_id = dept.deptid<br />              ) LOOP<br />              NULL;<br />            END LOOP;<br /></pre>  |  <pre>CREATE VIEW TEST_ORA_PG.`P_WITH_SELECT_REGULAR_MULT_01$dept_empl<br /> `(id, name, surname, lastname, state, dept_id)<br />AS<br />(SELECT id, name, surname, lastname, state, dept_id <br />   FROM test_ora_pg.dept_employees<br />  WHERE state = 1);<br />  <br />CREATE VIEW TEST_ORA_PG.`P_WITH_SELECT_REGULAR_MULT_01$dept<br /> `(deptid, parent_id,deptname)<br />AS<br />(SELECT id deptid, parent_id, name deptname<br />   FROM test_ora_pg.department);  <br /><br /><br />CREATE PROCEDURE test_ora_pg.P_WITH_SELECT_REGULAR_MULT_01()<br />BEGIN<br />    DECLARE var$ID DOUBLE;<br />    DECLARE var$NAME VARCHAR (30);<br />    DECLARE var$SURNAME VARCHAR (30);<br />    DECLARE var$LASTNAME VARCHAR (30);<br />    DECLARE var$STATE DOUBLE;<br />    DECLARE var$DEPT_ID DOUBLE;<br />    DECLARE var$deptid DOUBLE;<br />    DECLARE var$PARENT_ID DOUBLE;<br />    DECLARE var$deptname VARCHAR (200);<br />    DECLARE done INT DEFAULT FALSE;<br />    DECLARE cur CURSOR FOR SELECT<br />        dept_empl.*, dept.*<br />        FROM TEST_ORA_PG.`P_WITH_SELECT_REGULAR_MULT_01$dept_empl<br />          ` AS dept_empl,<br />             TEST_ORA_PG.`P_WITH_SELECT_REGULAR_MULT_01$dept<br />          ` AS dept<br />        WHERE dept_empl.DEPT_ID = dept.DEPTID;<br />    DECLARE CONTINUE HANDLER FOR NOT FOUND<br />        SET done := TRUE;<br />    OPEN cur;<br /><br />    read_label:<br />    LOOP<br />    FETCH cur INTO var$ID, var$NAME, var$SURNAME, <br />     var$LASTNAME, var$STATE, var$DEPT_ID, var$deptid, <br />     var$PARENT_ID, var$deptname;<br /><br />        IF done THEN<br />            LEAVE read_label;<br />        END IF;<br /><br />        BEGIN<br />        END;<br />    END LOOP;<br />    CLOSE cur;<br />END;<br /><br />call test_ora_pg.P_WITH_SELECT_REGULAR_MULT_01()<br /></pre>  | 
|  <pre>CREATE PROCEDURE <br />  TEST_ORA_PG.P_WITH_SELECT_VAR_CROSS_02(p_state IN NUMBER)<br />AS    <br />   l_dept_id NUMBER := 10;<br />BEGIN<br /> FOR cur IN  (<br />               WITH emp AS              <br />                    (SELECT id, name, surname, <br />                      lastname, state, dept_id <br />                       FROM test_ora_pg.dept_employees<br />                      WHERE dept_id > 10                 <br />                    ),<br />                    active_emp AS<br />                    (<br />                      SELECT id<br />                        FROM emp<br />                       WHERE emp.state = p_state <br />                    )<br />                    <br />                SELECT *          <br />                  FROM active_emp                 <br />              ) LOOP<br />         NULL;<br />  END LOOP;<br />  <br />END;<br /></pre>  |  <pre>CREATE VIEW TEST_ORA_PG.`P_WITH_SELECT_VAR_CROSS_01$emp<br />    `(id, name, surname, lastname, state, dept_id)<br />AS<br />(SELECT<br />       id, name, surname, lastname, <br />       state, dept_id<br />  FROM TEST_ORA_PG.DEPT_EMPLOYEES<br />  WHERE DEPT_ID > 10);<br /><br /><br />CREATE PROCEDURE <br />   test_ora_pg.P_WITH_SELECT_VAR_CROSS_02(IN par_P_STATE DOUBLE)<br />BEGIN<br />    DECLARE var_l_dept_id DOUBLE DEFAULT 10;<br />    DECLARE var$ID DOUBLE;<br />    DECLARE done INT DEFAULT FALSE;<br />    DECLARE cur CURSOR FOR SELECT *<br />                             FROM (SELECT<br />                                      ID<br />                                     FROM <br />                             TEST_ORA_PG.<br />                              `P_WITH_SELECT_VAR_CROSS_01$emp` AS emp<br />                                   WHERE emp.STATE = par_p_state) <br />                                    AS active_emp;<br />    DECLARE CONTINUE HANDLER FOR NOT FOUND<br />        SET done := TRUE;<br />    OPEN cur;<br /><br />    read_label:<br />    LOOP<br />        FETCH cur INTO var$ID;<br /><br />        IF done THEN<br />            LEAVE read_label;<br />        END IF;<br /><br />        BEGIN<br />        END;<br />    END LOOP;<br />    CLOSE cur;<br />END;<br /></pre>  | 