更新タイプ
このトピックでは、実際にデータを変更せずに CREATE
TABLE
ステートメントのスキーマに加えられるいくつかの変更について説明します。スキーマ更新の各タイプがレビューされ、Athena でこれらの使用が許可されるデータ形式を指定します。スキーマを更新するには、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://
DOC-EXAMPLE-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://
DOC-EXAMPLE-BUCKET
/orders_csv/';
以下のセクションでは、これらのテーブルに対する更新がどのように Athena クエリに影響するかを検証します。
テーブルの先頭または中間への列の追加
列の追加は最も頻繁なスキーマの変更の 1 つです。たとえば、新しいデータでテーブルをエンリッチ化するために、新しい列を追加することがあります。または、既存の列のソースが変更された場合に新しい列を追加し、この列の以前のバージョンを保持してそれに依存するアプリケーションを調整することもあります。
テーブルの先頭または中間に列を追加し、既存のテーブルに対してクエリを実行するには、SerDe プロパティが名前で読み取るように設定されている場合は、AVRO、JSON、および Parquet と ORC を使用します。詳細については、Parquet および ORC におけるインデックスアクセス を参照してください。
これらの形式は順序に依存するため、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://
DOC-EXAMPLE-BUCKET
/orders_json/';
テーブルの末尾への列の追加
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 クエリエディタに新しいテーブル列を表示するには、エディタのテーブルリストを手動で更新してから、テーブルをもう一度展開します。
列の削除
列に含まれるデータがなくなった場合、あるいは列に含まれているデータへのアクセスを制限する場合に、これらの列を削除する必要があることがあります。
-
名前で読み込まれている場合、JSON、Avro、および Parquet、ORC でテーブルから列を削除することができます。詳細については、Parquet および ORC におけるインデックスアクセス を参照してください。
-
既に 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://
DOC-EXAMPLE-BUCKET
/orders_parquet/';
列名の変更
綴りを修正する、列名をより分かりやすくする、または列の順序変更を回避するために、テーブルで列の名前変更が必要となる場合があります。
データを CSV および TSV に保存する場合は列の名前を変更できます。また、インデックスで読み取るように設定されている場合は、Parquet および ORC に保存できます。詳細については、Parquet および ORC におけるインデックスアクセス を参照してください。
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://
DOC-EXAMPLE-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://
DOC-EXAMPLE-BUCKET
/orders_csv/';
CSV テーブルの場合、次のクエリを実行すると、名前が変更された列を含むすべての列でデータが表示されます。
SELECT * FROM orders_csv_column_renamed;
列の順序の変更
デフォルトで名前で読み取る JSON や Parquet など、名前で読み取る形式のデータを含むテーブルの列の順序を変更できます。必要に応じて、ORC を名前で読み取ることもできます。詳細については、Parquet および ORC におけるインデックスアクセス を参照してください。
次の例では、列の順序が違う新しいテーブルを作成します。
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://
DOC-EXAMPLE-BUCKET
/orders_parquet/';
列のデータ型の変更
既存のタイプでは必要な量の情報を保持できなくなった場合は、別の列タイプを使用することをお勧めします。例えば、ID 列の値が INT
データ型のサイズを超えているため、その BIGINT
データ型を使用する必要があります。
列に別のデータ型を使用するときは、以下の点を考慮してください。
-
ほとんどの場合、列のデータ型を直接変更することはできません。代わりに、Athena テーブルを再作成し、新しいデータ型で列を定義します。
-
一部のデータ型のみを他のデータ型として読み取ることができます。扱えるデータ型については、このセクションの表を参照してください。
-
Parquet および ORC のデータでは、テーブルがパーティション分割されていない場合、列に異なるデータ型を使用することはできません。
-
Parquet および ORC のパーティション分割されたテーブルでは、パーティションの列タイプが別のパーティションの列タイプと異なる場合があり、可能な場合は、Athena が望ましいタイプに
CAST
します。詳細については、パーティションがあるテーブルに対するスキーマの不一致エラーの回避 を参照してください。 -
LazySimpleSerDE のみを使用して作成されたテーブルでは、
ALTER TABLE REPLACE COLUMNS
ステートメントを使用して既存の列を別のデータ型に置き換えることができますが、保持したい既存の列もすべてステートメントに再定義する必要があります。これを行わないと、削除されます。詳細については、「ALTER TABLE REPLACE COLUMNS」を参照してください。 -
Apache Iceberg テーブルの場合のみ、ALTER TABLE CHANGE COLUMN ステートメントを使用して列のデータ型を変更できます。
ALTER TABLE REPLACE COLUMNS
は Iceberg テーブルではサポートされていません。詳細については、「Iceberg テーブルスキーマの進化」を参照してください。
重要
データ型の変換を実行する前に、クエリをテストして検証することを強くお勧めします。Athena がターゲットのデータ型を使用できない場合、CREATE
TABLE
クエリは失敗する可能性があります。
次の表は、他のデータ型として扱われるデータ型の一覧です。
互換性のあるデータ型 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
元のデータ型 | 使用可能なターゲットデータ型 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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://
DOC-EXAMPLE-BUCKET
/orders_json';
次のクエリは、元の SELECT
クエリと同様に、データ型が変更される前に正常に実行されます。
Select * from orders_json LIMIT 10;