

# スキーマを更新する
<a name="make-schema-updates"></a>

このトピックでは、実際にデータを変更せずに `CREATE TABLE` ステートメントのスキーマに加えられるいくつかの変更について説明します。スキーマを更新するには、`ALTER TABLE` コマンドを使用できる場合もあれば、既存のテーブルを実際に変更しない場合もあります。代わりに、元の `CREATE TABLE` テートメントで使用したスキーマを変更する新しい名前のテーブルを作成します。

期待されるスキーマの進化方法に応じて、Athena クエリの使用を継続するために互換性のあるデータ形式を選択します。

CSV および Parquet の 2 つの形式で存在する `orders` テーブルからの注文情報を読み取るアプリケーションを考えます。

以下の例では、Parquet でテーブルを作成します。

```
CREATE EXTERNAL TABLE orders_parquet (
   `orderkey` int, 
   `orderstatus` string, 
   `totalprice` double, 
   `orderdate` string, 
   `orderpriority` string, 
   `clerk` string, 
   `shippriority` int
) STORED AS PARQUET
LOCATION 's3://amzn-s3-demo-bucket/orders_ parquet/';
```

以下の例では、CSV で同じテーブルを作成します。

```
CREATE EXTERNAL TABLE orders_csv (
   `orderkey` int, 
   `orderstatus` string, 
   `totalprice` double, 
   `orderdate` string, 
   `orderpriority` string, 
   `clerk` string, 
   `shippriority` int
) 
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION 's3://amzn-s3-demo-bucket/orders_csv/';
```

次のトピックでは、これらのテーブルの更新が Athena クエリにどのように影響するかを示します。

**Topics**
+ [テーブルの先頭または中間に列を追加する](updates-add-columns-beginning-middle-of-table.md)
+ [テーブルの末尾に列を追加する](updates-add-columns-end-of-table.md)
+ [列の削除](updates-removing-columns.md)
+ [列の名前変更](updates-renaming-columns.md)
+ [列の順序変更](updates-reordering-columns.md)
+ [列のデータ型を変更する](updates-changing-column-type.md)

# テーブルの先頭または中間に列を追加する
<a name="updates-add-columns-beginning-middle-of-table"></a>

列の追加は最も頻繁なスキーマの変更の 1 つです。たとえば、新しいデータでテーブルをエンリッチ化するために、新しい列を追加することがあります。または、既存の列のソースが変更された場合に新しい列を追加し、この列の以前のバージョンを保持してそれに依存するアプリケーションを調整することもあります。

テーブルの先頭または中間に列を追加し、既存のテーブルに対してクエリを実行するには、SerDe プロパティが名前で読み取るように設定されている場合は、AVRO、JSON、および Parquet と ORC を使用します。詳細については、「[Apache ORC と Apache Parquet のインデックスアクセスを理解する](handling-schema-updates-chapter.md#index-access)」を参照してください。

これらの形式は順序に依存するため、CSV および TSV のテーブルの先頭または中間に列を追加しないでください。このような場合に列を追加すると、パーティションのスキーマが変更されたときにスキーマの不一致エラーが発生します。

 次の例では、JSON データに基づいてテーブルの中央に `o_comment` 列を追加する新しいテーブルを作成します。

```
CREATE EXTERNAL TABLE orders_json_column_addition (
   `o_orderkey` int, 
   `o_custkey` int, 
   `o_orderstatus` string, 
   `o_comment` string, 
   `o_totalprice` double, 
   `o_orderdate` string, 
   `o_orderpriority` string, 
   `o_clerk` string, 
   `o_shippriority` int, 
) 
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://amzn-s3-demo-bucket/orders_json/';
```

# テーブルの末尾に列を追加する
<a name="updates-add-columns-end-of-table"></a>

Parquet、ORC、Avro、JSON、CSV、および TSV などの Athena がサポートする形式のいずれかでテーブルを作成する場合は、`ALTER TABLE ADD COLUMNS` ステートメントを使用して、既存の列の後、かつパーティション列の前の位置に列を追加できます。

次の例では、パーティション `comment` 列の前の `orders_parquet` テーブルの末尾に列を追加します。

```
ALTER TABLE orders_parquet ADD COLUMNS (comment string)
```

**注記**  
`ALTER TABLE ADD COLUMNS` を実行した後で Athena クエリエディタに新しいテーブル列を表示するには、エディタのテーブルリストを手動で更新してから、テーブルをもう一度展開します。

# 列の削除
<a name="updates-removing-columns"></a>

列に含まれるデータがなくなった場合、あるいは列に含まれているデータへのアクセスを制限する場合に、これらの列を削除する必要があることがあります。
+ 名前で読み込まれている場合、JSON、Avro、および Parquet、ORC でテーブルから列を削除することができます。詳細については、「[Apache ORC と Apache Parquet のインデックスアクセスを理解する](handling-schema-updates-chapter.md#index-access)」を参照してください。
+ 既に Athena で作成したテーブルを保持する場合は、CSV および TSV のテーブルから列を削除することは推奨されません。列を削除するとスキーマが壊れ、削除された列がない状態でテーブルを再作成しなければならなくなります。

この例では、Parquet のテーブルから ``totalprice`` 列を削除して、クエリを実行します。Athena では、デフォルトで Parquet の読み取りが名前で行われます。名前での読み取りを指定する SERDEPROPERTIES 設定が省略されているのはこのためです。スキーマを変更しても、次のクエリは成功することに注意してください。

```
CREATE EXTERNAL TABLE orders_parquet_column_removed (
   `o_orderkey` int, 
   `o_custkey` int, 
   `o_orderstatus` string, 
   `o_orderdate` string, 
   `o_orderpriority` string, 
   `o_clerk` string, 
   `o_shippriority` int, 
   `o_comment` string
) 
STORED AS PARQUET
LOCATION 's3://amzn-s3-demo-bucket/orders_parquet/';
```

# 列の名前変更
<a name="updates-renaming-columns"></a>

綴りを修正する、列名をより分かりやすくする、または列の順序変更を回避するために、テーブルで列の名前変更が必要となる場合があります。

データを CSV および TSV に保存する場合は列の名前を変更できます。また、インデックスで読み取るように設定されている場合は、Parquet および ORC に保存できます。詳細については、「[Apache ORC と Apache Parquet のインデックスアクセスを理解する](handling-schema-updates-chapter.md#index-access)」を参照してください。

Athena は CSV と TSV のデータをスキーマの列順に読み取り、それらを同じ順序で返します。Athena は、列にデータをマップするために列名を使用しません。Athena クエリを破損することなく CSV または TSV で列名を変更できるのはこのためです。

列名を変更する戦略の 1 つは、同じ基盤データに基づく新しいテーブルを、新しい列名を使用して作成することです。以下の例は、`orders_parquet_column_renamed` という名前の新しい `orders_parquet` テーブルを作成します。この例は、列 ``o_totalprice`` の名前を ``o_total_price`` に変更してから、Athena でクエリを実行します。

```
CREATE EXTERNAL TABLE orders_parquet_column_renamed (
   `o_orderkey` int, 
   `o_custkey` int, 
   `o_orderstatus` string, 
   `o_total_price` double, 
   `o_orderdate` string, 
   `o_orderpriority` string, 
   `o_clerk` string, 
   `o_shippriority` int, 
   `o_comment` string
) 
STORED AS PARQUET
LOCATION 's3://amzn-s3-demo-bucket/orders_parquet/';
```

Parquet テーブルの場合、次のクエリは実行されますが、列がインデックスではなく名前でアクセスされているため (Parquet のデフォルト)、名前が変更された列にはデータが表示されません。

```
SELECT * 
FROM orders_parquet_column_renamed;
```

CSV のテーブルでのクエリも類似しています。

```
CREATE EXTERNAL TABLE orders_csv_column_renamed (
   `o_orderkey` int, 
   `o_custkey` int, 
   `o_orderstatus` string, 
   `o_total_price` double, 
   `o_orderdate` string, 
   `o_orderpriority` string, 
   `o_clerk` string, 
   `o_shippriority` int, 
   `o_comment` string
) 
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION 's3://amzn-s3-demo-bucket/orders_csv/';
```

CSV テーブルの場合、次のクエリを実行すると、名前が変更された列を含むすべての列でデータが表示されます。

```
SELECT * 
FROM orders_csv_column_renamed;
```

# 列の順序変更
<a name="updates-reordering-columns"></a>

デフォルトで名前で読み取る JSON や Parquet など、名前で読み取る形式のデータを含むテーブルの列の順序を変更できます。必要に応じて、ORC を名前で読み取ることもできます。詳細については、「[Apache ORC と Apache Parquet のインデックスアクセスを理解する](handling-schema-updates-chapter.md#index-access)」を参照してください。

次の例では、列の順序が違う新しいテーブルを作成します。

```
CREATE EXTERNAL TABLE orders_parquet_columns_reordered (
   `o_comment` string,
   `o_orderkey` int, 
   `o_custkey` int, 
   `o_orderpriority` string, 
   `o_orderstatus` string, 
   `o_clerk` string, 
   `o_shippriority` int, 
   `o_orderdate` string
) 
STORED AS PARQUET
LOCATION 's3://amzn-s3-demo-bucket/orders_parquet/';
```

# 列のデータ型を変更する
<a name="updates-changing-column-type"></a>

既存のタイプでは必要な量の情報を保持できなくなった場合は、別の列タイプを使用することをお勧めします。例えば、ID 列の値が `INT` データ型のサイズを超えているため、その `BIGINT` データ型を使用する必要があります。

## 考慮事項
<a name="updates-changing-column-type-considerations"></a>

列に別のデータ型を使用するときは、以下の点を考慮してください。
+ ほとんどの場合、列のデータ型を直接変更することはできません。代わりに、Athena テーブルを再作成し、新しいデータ型で列を定義します。
+ 一部のデータ型のみを他のデータ型として読み取ることができます。扱えるデータ型については、このセクションの表を参照してください。
+ Parquet および ORC のデータでは、テーブルがパーティション分割されていない場合、列に異なるデータ型を使用することはできません。
+ Parquet および ORC のパーティション分割されたテーブルでは、パーティションの列タイプが別のパーティションの列タイプと異なる場合があり、可能な場合は、Athena が望ましいタイプに `CAST` します。詳細については、「[パーティションがあるテーブルについて、スキーマ不一致エラーを回避する](updates-and-partitions.md#partitions-dealing-with-schema-mismatch-errors)」を参照してください。
+ [LazySimpleSerDE](lazy-simple-serde.md) のみを使用して作成されたテーブルでは、`ALTER TABLE REPLACE COLUMNS` ステートメントを使用して既存の列を別のデータ型に置き換えることができますが、保持したい既存の列もすべてステートメントに再定義する必要があります。これを行わないと、削除されます。詳細については、「[ALTER TABLE REPLACE COLUMNS](alter-table-replace-columns.md)」を参照してください。
+ Apache Iceberg テーブルの場合のみ、[ALTER TABLE CHANGE COLUMN](querying-iceberg-alter-table-change-column.md) ステートメントを使用して列のデータ型を変更できます。 `ALTER TABLE REPLACE COLUMNS` は Iceberg テーブルではサポートされていません。詳細については、「[Iceberg テーブルスキーマを進化させる](querying-iceberg-evolving-table-schema.md)」を参照してください。

**重要**  
データ型の変換を実行する前に、クエリをテストして検証することを強くお勧めします。Athena がターゲットのデータ型を使用できない場合、`CREATE TABLE` クエリは失敗する可能性があります。

## 互換性のあるデータ型を使用する
<a name="updates-changing-column-type-use-compatible-data-types"></a>

可能な場合は常に、互換性のあるデータ型を使用します。次の表は、他のデータ型として扱うことができるデータ型の一覧です。


| 元のデータ型 | 使用可能なターゲットデータ型 | 
| --- | --- | 
| STRING | BYTE, TINYINT, SMALLINT, INT, BIGINT | 
| BYTE | TINYINT, SMALLINT, INT, BIGINT | 
| TINYINT | SMALLINT, INT, BIGINT | 
| SMALLINT | INT, BIGINT | 
| INT | BIGINT | 
| FLOAT | DOUBLE | 

次の例では、元の `orders_json` テーブルの `CREATE TABLE` ステートメントを使用して、`orders_json_bigint` という新しいテーブルを作成します。新しいテーブルでは、``o_shippriority`` 列のデータ型として `INT` の代わりに `BIGINT` が使用されます。

```
CREATE EXTERNAL TABLE orders_json_bigint (
   `o_orderkey` int, 
   `o_custkey` int, 
   `o_orderstatus` string, 
   `o_totalprice` double, 
   `o_orderdate` string, 
   `o_orderpriority` string, 
   `o_clerk` string, 
   `o_shippriority` BIGINT
) 
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://amzn-s3-demo-bucket/orders_json';
```

次のクエリは、元の `SELECT` クエリと同様に、データ型が変更される前に正常に実行されます。

```
Select * from orders_json 
LIMIT 10;
```