

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

# 將 Teradata NORMALIZE 暫時功能轉換為 Amazon Redshift SQL
<a name="convert-the-teradata-normalize-temporal-feature-to-amazon-redshift-sql"></a>

*Po Hong，Amazon Web Services*

## 總結
<a name="convert-the-teradata-normalize-temporal-feature-to-amazon-redshift-sql-summary"></a>

**NORMALIZE** 是 ANSI SQL 標準的 Teradata 擴充功能。當 SQL 資料表包含具有 **PERIOD** 資料類型的資料欄時，**NORMALIZE** 會結合在該資料欄中符合或重疊的值，以形成單一期間來合併多個個別期間值。若要使用 **NORMALIZE**，SQL **SELECT** 清單中至少有一個資料欄必須是 Teradata 的暫時 **PERIOD** 資料類型。如需 **NORMALIZE** 的詳細資訊，請參閱 [Teradata 文件](https://docs.teradata.com/reader/2_MC9vCtAJRlKle2Rpb0mA/MIGI5UMEwgERC3Un7tEZ6g)。 

Amazon Redshift 不支援 **NORMALIZE**，但您可以在 Amazon Redshift 中使用原生 SQL 語法和 **LAG** 視窗函數來實作此功能。此模式著重於搭配 **ON MEETS 或 OVERLAPS **條件使用 Teradata **NORMALIZE** 延伸模組，這是最受歡迎的格式。它說明此功能如何在 Teradata 中運作，以及如何將其轉換為 Amazon Redshift 原生 SQL 語法。

## 先決條件和限制
<a name="convert-the-teradata-normalize-temporal-feature-to-amazon-redshift-sql-prereqs"></a>

**先決條件**
+ 基本 Teradata SQL 知識和經驗
+ Amazon Redshift 知識和經驗

## Architecture
<a name="convert-the-teradata-normalize-temporal-feature-to-amazon-redshift-sql-architecture"></a>

**來源技術堆疊**
+ Teradata 資料倉儲

**目標技術堆疊**
+ Amazon Redshift

**目標架構**

如需將 Teradata 資料庫遷移至 Amazon Redshift 的高階架構，請參閱[使用 AWS SCT 資料擷取代理程式將 Teradata 資料庫遷移至 Amazon Redshift](https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/migrate-a-teradata-database-to-amazon-redshift-using-aws-sct-data-extraction-agents.html) 的模式。遷移不會自動將 Teradata **NORMALIZE** 片語轉換為 Amazon Redshift SQL。您可以遵循此模式中的準則來轉換此 Teradata 延伸。

## 工具
<a name="convert-the-teradata-normalize-temporal-feature-to-amazon-redshift-sql-tools"></a>

**Code**

若要說明 **NORMALIZE** 的概念和功能，請考慮 Teradata 中的下列資料表定義：

```
CREATE TABLE systest.project
     (    emp_id        INTEGER,
          project_name  VARCHAR(20),
          dept_id       INTEGER,
          duration      PERIOD(DATE)
     );
```

執行下列 SQL 程式碼，將範例資料插入資料表：

```
BEGIN TRANSACTION;

INSERT INTO systest.project VALUES (10, 'First Phase', 1000,  PERIOD(DATE '2010-01-10', DATE '2010-03-20') );
INSERT INTO systest.project VALUES (10, 'First Phase', 2000,  PERIOD(DATE '2010-03-20', DATE '2010-07-15') );

INSERT INTO systest.project VALUES (10, 'Second Phase', 2000,  PERIOD(DATE '2010-06-15', DATE '2010-08-18') );
INSERT INTO systest.project VALUES (20, 'First Phase', 2000,  PERIOD(DATE '2010-03-10', DATE '2010-07-20') );

INSERT INTO systest.project VALUES (20, 'Second Phase', 1000,  PERIOD(DATE '2020-05-10', DATE '2020-09-20') );

END TRANSACTION;
```

結果：

```
select * from systest.project order by 1,2,3;
 
 *** Query completed. 4 rows found. 4 columns returned.
 *** Total elapsed time was 1 second.
 
     emp_id  project_name              dept_id  duration
-----------  --------------------  -----------  ------------------------
         10  First Phase                  1000  ('10/01/10', '10/03/20')        
         10  First Phase                  2000  ('10/03/20', '10/07/15')
         10  Second Phase                 2000  ('10/06/15', '10/08/18')
         20  First Phase                  2000  ('10/03/10', '10/07/20')
         20  Second Phase                 1000  ('20/05/10', '20/09/20')
```

*Teradata NORMALIZE 使用案例*

現在將 Teradata **NORMALIZE** SQL 子句新增至 **SELECT** 陳述式：

```
SELECT NORMALIZE ON MEETS OR OVERLAPS emp_id, duration 
FROM systest.project 
ORDER BY 1,2;
```

此 **NORMALIZE** 操作會在單一資料欄 () 上執行`emp_id`。對於 `emp_id=10`，持續時間中的三個重疊期間值會合併為單一期間值，如下所示： 

```
     emp_id  duration
-----------  ------------------------
         10  ('10/01/10', '10/08/18')
         20  ('10/03/10', '10/07/20')
         20  ('20/05/10', '20/09/20')
```

下列 **SELECT** 陳述式會在 `project_name`和 上執行 **NORMALIZE** 操作`dept_id`。請注意，**SELECT** 清單只包含一個 **PERIOD** 資料欄 `duration`。

```
SELECT NORMALIZE project_name, dept_id, duration 
FROM systest.project;
```

輸出：

```
project_name              dept_id  duration
--------------------  -----------  ------------------------
First Phase                  1000  ('10/01/10', '10/03/20')
Second Phase                 1000  ('20/05/10', '20/09/20')
First Phase                  2000  ('10/03/10', '10/07/20')
Second Phase                 2000  ('10/06/15', '10/08/18')
```

*Amazon Redshift 對等 SQL*

Amazon Redshift 目前不支援資料表中的 **PERIOD** 資料類型。相反地，您需要將 Teradata **PERIOD** 資料欄位分成兩個部分：`start_date, end_date`，如下所示： 

```
CREATE TABLE systest.project
     (    emp_id        INTEGER,
          project_name  VARCHAR(20),
          dept_id       INTEGER,
          start_date  DATE,
          end_date    DATE
     );
```

將範例資料插入資料表：

```
BEGIN TRANSACTION;
 
INSERT INTO systest.project VALUES (10, 'First Phase', 1000,  DATE '2010-01-10', DATE '2010-03-20' );
INSERT INTO systest.project VALUES (10, 'First Phase', 2000,  DATE '2010-03-20', DATE '2010-07-15');
 
INSERT INTO systest.project VALUES (10, 'Second Phase', 2000,  DATE '2010-06-15', DATE '2010-08-18' );
INSERT INTO systest.project VALUES (20, 'First Phase', 2000,  DATE '2010-03-10', DATE '2010-07-20' );
 
INSERT INTO systest.project VALUES (20, 'Second Phase', 1000,  DATE '2020-05-10', DATE '2020-09-20' );
 
END TRANSACTION;
```

輸出：

```
 emp_id | project_name | dept_id | start_date |  end_date
--------+--------------+---------+------------+------------
     10 | First Phase  |    1000 | 2010-01-10 | 2010-03-20
     10 | First Phase  |    2000 | 2010-03-20 | 2010-07-15
     10 | Second Phase |    2000 | 2010-06-15 | 2010-08-18
     20 | First Phase  |    2000 | 2010-03-10 | 2010-07-20
     20 | Second Phase |    1000 | 2020-05-10 | 2020-09-20
(5 rows)
```

若要重寫 Teradata 的 **NORMALIZE** 子句，您可以在 Amazon Redshift 中使用 [LAG 視窗函數](https://docs.aws.amazon.com/redshift/latest/dg/r_WF_LAG.html)。此函數會傳回分割區中目前資料列上方 （之前） 指定位移的資料列值。

您可以使用 **LAG** 函數來識別開始新期間的每個資料列，方法是判斷期間是否符合或與前一個期間重疊 (0 表示是，1 表示否）。當此旗標累積加總時，會提供群組識別符，可用於外部 **Group By** 子句，以到達 Amazon Redshift 中所需的結果。 

以下是使用 **LAG()** 的 Amazon Redshift SQL 陳述式範例：

```
SELECT emp_id, start_date, end_date, 
            (CASE WHEN start_date <= LAG(end_date) OVER (PARTITION BY emp_id ORDER BY start_date, end_date) THEN 0 ELSE 1 END) AS GroupStartFlag
FROM systest.project 
ORDER BY 1,2;
```

輸出：

```
 emp_id | start_date |  end_date  | groupstartflag
--------+------------+------------+----------------
     10 | 2010-01-10 | 2010-03-20 |              1
     10 | 2010-03-20 | 2010-07-15 |              0
     10 | 2010-06-15 | 2010-08-18 |              0
     20 | 2010-03-10 | 2010-07-20 |              1
     20 | 2020-05-10 | 2020-09-20 |              1
(5 rows)
```

下列 Amazon Redshift SQL 陳述式只會在 `emp_id` 欄上標準化：

```
SELECT T2.emp_id, MIN(T2.start_date) as new_start_date, MAX(T2.end_date) as new_end_date
FROM 
( SELECT T1.*, SUM(GroupStartFlag) OVER (PARTITION BY emp_id ORDER BY start_date ROWS UNBOUNDED PRECEDING) As GroupID
FROM ( SELECT emp_id, start_date, end_date, 
            (CASE WHEN start_date <= LAG(end_date) OVER (PARTITION BY emp_id ORDER BY start_date, end_date) THEN 0 ELSE 1 END) AS GroupStartFlag
FROM systest.project ) T1
) T2
GROUP BY T2.emp_id, T2.GroupID
ORDER BY 1,2;
```

輸出： 

```
 emp_id | new_start_date | new_end_date
--------+----------------+------------------------------------
     10 | 2010-01-10     | 2010-08-18
     20 | 2010-03-10     | 2010-07-20
     20 | 2020-05-10     | 2020-09-20
(3 rows)
```

** **

下列 Amazon Redshift SQL 陳述式會在 `project_name`和 `dept_id`資料欄上標準化：

```
SELECT T2.project_name, T2.dept_id, MIN(T2.start_date) as new_start_date, MAX(T2.end_date) as new_end_date
FROM 
( SELECT T1.*, SUM(GroupStartFlag) OVER (PARTITION BY project_name, dept_id ORDER BY start_date ROWS UNBOUNDED PRECEDING) As GroupID
FROM ( SELECT project_name, dept_id, start_date, end_date, 
            (CASE WHEN start_date <= LAG(end_date) OVER (PARTITION BY project_name, dept_id ORDER BY start_date, end_date) THEN 0 ELSE 1 END) AS GroupStartFlag
FROM systest.project ) T1
) T2
GROUP BY T2.project_name, T2.dept_id, T2.GroupID
ORDER BY 1,2,3;
```

輸出：

```
 project_name | dept_id | new_start_date | new_end_date
--------------+---------+----------------+--------------
 First Phase  |    1000 | 2010-01-10     | 2010-03-20
 First Phase  |    2000 | 2010-03-10     | 2010-07-20
 Second Phase |    1000 | 2020-05-10     | 2020-09-20
 Second Phase |    2000 | 2010-06-15     | 2010-08-18
(4 rows)
```

## 史詩
<a name="convert-the-teradata-normalize-temporal-feature-to-amazon-redshift-sql-epics"></a>

### 將 NORMALIZE 轉換為 Amazon Redshift SQL
<a name="convert-normalize-to-amazon-redshift-sql"></a>


| 任務 | Description | 所需的技能 | 
| --- | --- | --- | 
| 建立 Teradata SQL 程式碼。 | 根據您的需求使用 NORMALIZE 片語。 | SQL Developer | 
| 將程式碼轉換為 Amazon Redshift SQL。 | 若要轉換您的程式碼，請遵循此模式的「工具」區段中的準則。 | SQL Developer | 
| 在 Amazon Redshift 中執行程式碼。 | 建立資料表、將資料載入資料表，並在 Amazon Redshift 中執行程式碼。 | SQL Developer | 

## 相關資源
<a name="convert-the-teradata-normalize-temporal-feature-to-amazon-redshift-sql-resources"></a>

**參考**
+ [Teradata NORMALIZE 暫時功能](https://docs.teradata.com/reader/2_MC9vCtAJRlKle2Rpb0mA/MIGI5UMEwgERC3Un7tEZ6g) (Teradata 文件）
+ [LAG 視窗函數](https://docs.aws.amazon.com/redshift/latest/dg/r_WF_LAG.html) (Amazon Redshift 文件）
+ [遷移至 Amazon Redshift](https://aws.amazon.com/redshift/data-warehouse-migration/) (AWS 網站）
+ [使用 AWS SCT 資料擷取代理程式將 Teradata 資料庫遷移至 Amazon Redshift](https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/migrate-a-teradata-database-to-amazon-redshift-using-aws-sct-data-extraction-agents.html) (AWS 方案指引）
+ [將 Teradata RESET WHEN 功能轉換為 Amazon Redshift SQL](https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/convert-the-teradata-reset-when-feature-to-amazon-redshift-sql.html) (AWS 方案指引）

**工具**
+ [AWS Schema Conversion Tool (AWS SCT)](https://aws.amazon.com/dms/schema-conversion-tool/)

**合作夥伴**
+ [AWS 遷移能力合作夥伴](https://aws.amazon.com/migration/partner-solutions/#delivery)