

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

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

要在转换后的 MySQL 代码中模拟 Oracle 数据库函数，请使用 AWS SCT中的 Oracle 到 MySQL 扩展包。有关扩展包的更多信息，请参阅[将扩展包与 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
+ REFERENCES ON \$1.\$1
+ SELECT ON \$1.\$1
+ CREATE VIEW ON \$1.\$1
+ SHOW VIEW ON \$1.\$1
+ TRIGGER ON \$1.\$1
+ CREATE ROUTINE ON \$1.\$1
+ ALTER ROUTINE ON \$1.\$1
+ EXECUTE ON \$1.\$1
+ CREATE TEMPORARY TABLES ON \$1.\$1
+ AWS\$1LAMBDA\$1ACCESS
+ 插入，在 AWS\$1ORACLE \$1EXT 上更新。 \$1
+ 在 AWS\$1ORACLE \$1EXT\$1DATA 上插入、更新、删除。 \$1

如果您使用 MySQL 数据库版本 5.7 或更低版本作为目标，请授予 INVOKE LAMBDA \$1.\$1 权限，而不是 \$1ACCESS。 AWS\$1LAMBDA对于 8.0 及更高版本的 MySQL 数据库，请授予 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*替换为安全密码。

如果使用版本 5.7 或更低版本的 MySQL 数据库作为目标，请使用 `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，然后选择 Or** **acle — MySQL**。 AWS SCT 显示了 Oracle 到 MySQL 转换的所有可用设置。

中的 Oracle 到 MySQL 的转换设置 AWS SCT 包括以下各项的选项：
+ 限制转换后的代码中操作项的注释数量。

  对于在**转换后的代码中为所选严重性及更高的措施项添加注释**，请选择措施项的严重性。 AWS SCT 在转换后的代码中为选定严重性及更高的措施项添加注释。

  例如，要最大限度地减少转换后的代码中的注释数量，请选择**仅错误**。要在转换后的代码中包含所有操作项的注释，请选择**所有消息**。
+ 为了解决这个问题，你的源 Oracle 数据库可以使用`ROWID`伪列，但是 MySQL 不支持类似的功能。 AWS SCT 可以在转换后的代码中模拟`ROWID`伪列。为此，请为**生成行 ID？**选择**生成为身份** 。

  如果源 Oracle 代码不使用 `ROWID` 伪列，请为**生成行 ID？**选择**不生成**。在这种情况下，转换后的代码运行更快。
+ 在 Oracle 源代码中包含带有 MySQL 不支持的参数的 `TO_CHAR`、`TO_DATE` 和 `TO_NUMBER` 函数时使用该代码。默认情况下， 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` 语句和标签。将跳过 `GOTO` 语句后的任何 PL/SQL 语句并从标签位置继续处理。可在过程、批处理或语句块中的任意位置使用 `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）分配到子查询块。然后，您可以通过指定查询名称来引用查询中的子查询块多位置。如果子查询块不包含链接或参数（本地、过程、函数、包），则 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>  | 