

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

# 将虚拟生成的列从 Oracle 迁移至 PostgreSQL
<a name="migrate-virtual-generated-columns-from-oracle-to-postgresql"></a>

*Veeranjaneyulu Grandhi、Rajesh Madiwale 和 Ramesh Pathuri，Amazon Web Services*

## Summary
<a name="migrate-virtual-generated-columns-from-oracle-to-postgresql-summary"></a>

在版本 11 及以前版本中，PostgreSQL 不提供直接等同于 Oracle 虚拟列的功能。从 Oracle 数据库迁移到 PostgreSQL 版本 11 或以前版本时，处理虚拟生成的列很困难，原因有两个： 
+ 迁移时虚拟列不可见。
+ PostgreSQL 不支持版本 12 之前的 `generate` 表达式。

但是，也有一些变通方法可模拟类似的功能。当您使用 AWS Database Migration Service (AWS DMS) 将数据从 Oracle 数据库迁移至 PostgreSQL 版本 11 及以前版本时，您可以使用触发函数在虚拟生成的列中填充值。此模式提供了可用于此目的 Oracle 数据库和 PostgreSQL 代码的示例。在 AWS 上，对于您的 PostgreSQL 数据库，您可以使用 Amazon Relational Database Service (Amazon RDS) for PostgreSQL 或 Amazon Aurora PostgreSQL-Compatible Edition。

从 PostgreSQL 版本 12 开始支持生成的列。生成的列可以按其他列值即时计算，也可以计算和存储。[PostgreSQL 生成列](https://www.postgresql.org/docs/12/ddl-generated-columns.html)与 Oracle 虚拟列类似。

## 先决条件和限制
<a name="migrate-virtual-generated-columns-from-oracle-to-postgresql-prereqs"></a>

**先决条件**
+ 一个有效的 Amazon Web Services account
+ 源 Oracle 数据库 
+ 目标 PostgreSQL 数据库（在 Amazon RDS for PostgreSQL 或 Aurora PostgreSQL-Compatible 上）
+ [PL/pgSQL](https://www.postgresql.org/docs/current/plpgsql.html) 编码专业知识

**限制**
+ 仅适用于 12 之前的 PostgreSQL 版本。 
+ 适用于 Oracle 数据库版本 11g 或更高版本。
+ 数据迁移工具不支持虚拟列。
+ 仅适用于同一表中定义的列。
+ 如果虚拟生成的列引用确定性的用户定义函数，则其不能将其用作分区键列。
+ 表达式输出必须是标量值。它无法返回 Oracle 提供的数据类型、用户定义的类型 `LOB` 或 `LONG RAW`。
+ 针对虚拟列定义的索引，等同于 PostgreSQL 中基于函数的索引。
+ 必须收集表格的统计信息。

## 工具
<a name="migrate-virtual-generated-columns-from-oracle-to-postgresql-tools"></a>
+ [pgAdmin 4](https://www.pgadmin.org/) 是一种适用于 PostgreSQL 的开源管理工具。该工具提供了图形界面，可简化数据库对象的创建、维护和使用。
+ [Oracle SQL Developer](https://www.oracle.com/database/sqldeveloper/) 是免费的集成开发环境，用于在传统部署和云部署中在 Oracle 数据库中使用 SQL。 

## 操作说明
<a name="migrate-virtual-generated-columns-from-oracle-to-postgresql-epics"></a>

### 创建源数据库和目标数据库表
<a name="create-source-and-target-database-tables"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建源 Oracle 数据库表。 | 在 Oracle 数据库，使用以下语句创建包含虚拟生成的列的表。<pre>CREATE TABLE test.generated_column<br />( CODE NUMBER,<br />STATUS VARCHAR2(12) DEFAULT 'PreOpen',<br />FLAG CHAR(1) GENERATED ALWAYS AS (CASE UPPER(STATUS) WHEN 'OPEN' THEN 'N' ELSE 'Y' END) VIRTUAL VISIBLE<br />);</pre>在此源表，`STATUS` 列中的数据通过 AWS DMS 迁移到目标数据库。但是，`FLAG` 列是使用 `generate by` 功能填充的，因此 AWS DMS 在迁移期间看不到此列。要实现 `generated by` 功能，您必须使用目标数据库中的触发器和函数填充 `FLAG` 列中的值，如下一个操作说明所示。 | 数据库管理员，应用程序开发人员 | 
| 在 AWS 创建目标 PostgreSQL 表。 | 使用以下语句在 AWS 上创建一个 PostgreSQL 表。<pre>CREATE TABLE test.generated_column<br />(<br />    code integer not null,<br />    status character varying(12) not null ,<br />    flag character(1)<br />);</pre>在此表中，`status` 列是标准列。`flag` 列将是根据该列中的数据生成的 `status` 列。 | 数据库管理员，应用程序开发人员 | 

### 创建触发函数来处理 PostgreSQL 中的虚拟列
<a name="create-a-trigger-function-to-handle-the-virtual-column-in-postgresql"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建 PostgreSQL 触发器。 | 在 PostgreSQL 中创建触发器。<pre>CREATE TRIGGER tgr_gen_column<br />AFTER INSERT OR UPDATE OF status ON test.generated_column<br />FOR EACH ROW <br />EXECUTE FUNCTION test.tgf_gen_column();</pre> | 数据库管理员，应用程序开发人员 | 
| 创建 PostgreSQL 触发器函数。 | 在 PostgreSQL 中，为触发器创建函数。此函数填充由应用程序或 AWS DMS 插入或更新虚拟列，并验证数据。<pre>CREATE OR REPLACE FUNCTION test.tgf_gen_column() RETURNS trigger AS $VIRTUAL_COL$<br />BEGIN<br />IF (TG_OP = 'INSERT') THEN<br />IF (NEW.flag IS NOT NULL) THEN<br />RAISE EXCEPTION 'ERROR: cannot insert into column "flag"' USING DETAIL = 'Column "flag" is a generated column.';<br />END IF;<br />END IF;<br />IF (TG_OP = 'UPDATE') THEN<br />IF (NEW.flag::VARCHAR != OLD.flag::varchar) THEN<br />RAISE EXCEPTION 'ERROR: cannot update column "flag"' USING DETAIL = 'Column "flag" is a generated column.';<br />END IF;<br />END IF;<br />IF TG_OP IN ('INSERT','UPDATE') THEN<br />IF (old.flag is NULL) OR (coalesce(old.status,'') != coalesce(new.status,'')) THEN<br />UPDATE test.generated_column<br />SET flag = (CASE UPPER(status) WHEN 'OPEN' THEN 'N' ELSE 'Y' END)<br />WHERE code = new.code;<br />END IF;<br />END IF;<br />RETURN NEW;<br />END<br />$VIRTUAL_COL$ LANGUAGE plpgsql;</pre> | 数据库管理员，应用程序开发人员 | 

### 使用 AWS DMS 测试数据迁移
<a name="test-data-migration-by-using-aws-dms"></a>


| Task | 说明 | 所需技能 | 
| --- | --- | --- | 
| 创建复制实例。 | 要创建复制实例，请按照 AWS DMS 文档中的[说明](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.Creating.html)进行操作。复制实例应与源数据库和目标数据库位于同一虚拟私有云（VPC）中。 | 数据库管理员，应用程序开发人员 | 
| 创建源和目标端点。 | 要创建端点，请按照 AWS DMS 文档中的[说明](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Endpoints.Creating.html)进行操作。 | 数据库管理员，应用程序开发人员 | 
| 测试端点连接。 | 您可以通过指定 VPC 和复制实例并选择**运行测试**来测试端点连接。 | 数据库管理员，应用程序开发人员 | 
| 创建和启动满载任务。 | 有关说明，请参阅 AWS DMS 文档中的[创建任务](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.Creating.html)和[满载任务设置](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Tasks.CustomizingTasks.TaskSettings.FullLoad.html)。 | 数据库管理员，应用程序开发人员 | 
| 验证虚拟列数据。 | 比较源数据库和目标数据库中虚拟列数据。您可手动验证数据，也可以为此步骤编写脚本。 | 数据库管理员，应用程序开发人员 | 

## 相关资源
<a name="migrate-virtual-generated-columns-from-oracle-to-postgresql-resources"></a>
+ [AWS Database Migration Service 入门](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_GettingStarted.html)（AWS DMS 文档）
+ [使用 Oracle 数据库作为 AWS DMS 的来源](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.Oracle.html)（AWS DMS 文档）
+ [使用 PostgreSQL 数据库作为 AWS DMS 的目标](https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.PostgreSQL.html)（AWS DMS 文档）
+ [在 PostgreSQL 中生成列](https://www.postgresql.org/docs/12/ddl-generated-columns.html)（PostgreSQL 文档）
+ [触发器函数](https://www.postgresql.org/docs/12/plpgsql-trigger.html)（PostgreSQL 文档）
+ Oracle 数据库中的[虚拟列](https://docs.oracle.com/database/121/SQLRF/statements_7002.htm#SQLRF01402)（Oracle 文档）