

 Amazon Redshift は、パッチ 198 以降、新しい Python UDF の作成をサポートしなくなります。既存の Python UDF は、2026 年 6 月 30 日まで引き続き機能します。詳細については、[ブログ記事](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)を参照してください。

# DML コマンドによるテーブルのロード
<a name="t_Updating_tables_with_DML_commands"></a>

Amazon Redshift は、テーブルの行の変更に利用できる標準のデータ操作言語 (DML) コマンド (INSERT、UPDATE、DELETE) をサポートします。TRUNCATE コマンドを使用し、高速一括削除を実行することもできます。

**注記**  
大量のデータをロードする場合は [COPY](r_COPY.md) コマンドを使用することを強くお勧めします。個々に INSERT ステートメントを使ってテーブルにデータを入力すると著しく時間がかかる場合があります。または、他の Amazon Redshift データベーステーブルにデータが既に存在する場合、パフォーマンスを向上させるには INSERT INTO ... SELECT FROM または CREATE TABLE AS を使用します。詳細については、「[INSERT](r_INSERT_30.md)」または「[CREATE TABLE AS](r_CREATE_TABLE_AS.md)」を参照してください。

テーブルで行を挿入、更新、削除するとき、それが変更前と比較して相当な数になる場合、完了時にテーブルに ANALYZE および VACUUM コマンドを実行します。アプリケーションの小さな変更の数が時間とともに累積される場合、定期的に ANALYZE および VACUUM コマンドを実行するように日程を計画することもできます。詳細については、「[テーブルを分析する](t_Analyzing_tables.md)」および「[テーブルのバキューム処理](t_Reclaiming_storage_space202.md)」を参照してください。

**Topics**
+ [新しいデータの更新と挿入](t_updating-inserting-using-staging-tables-.md)

# 新しいデータの更新と挿入
<a name="t_updating-inserting-using-staging-tables-"></a>

MERGE コマンドを使用すると、既存のテーブルに新しいデータを効率的に追加できます。マージ操作を実行するには、ステージングテーブルを作成し、このセクションで説明している方法のいずれかを使用して、ステージングテーブルからターゲットテーブルを更新します。MERGE コマンドの詳細については、「[MERGE](r_MERGE.md)」を参照してください。

[マージの例](merge-examples.md) は、Amazon Redshift 用のサンプルデータセット (TICKIT データセット) を使用します。前提条件として、「[一般的なデータベースタスクの開始方法](https://docs.aws.amazon.com/redshift/latest/gsg/database-tasks.html)」に記載されている手順に従って、TICKIT テーブルとデータを設定できます。サンプルデータセットの詳細については、「[サンプルデータベース](https://docs.aws.amazon.com/redshift/latest/dg/c_sampledb.html)」を参照してください。

## マージ方法 1: 既存の行を置き換える
<a name="merge-method-replace-existing-rows"></a>

ターゲットテーブルのすべての列を上書きする場合、マージを実行する最速の方法は、既存の行を置き換えることです。これは、内部結合を使用して更新される行を削除するため、ターゲットテーブルを 1 回だけスキャンします。行は削除されると、1 回の挿入オペレーションによってステージングテーブルの新しい行と置き換えられます。

この方法は、以下の条件のすべてに該当する場合に使用してください。
+ ターゲットテーブルとステージングテーブルに同じ列が含まれる。
+ ターゲットテーブルの列のデータをすべて、ステージングテーブルの列で置き換えることを予定している。
+ マージでステージングテーブルの行をすべて使用する。

ここに挙げた条件のなかに当てはまらないものがあった場合は、次のセクションで説明する「マージ方法 2: MERGE を使用せずに列リストを指定する」を使用します。

ステージングテーブルの行すべてを使用するわけではない場合には、DELETE ステートメントおよび INSERT ステートメントに WHERE 句を使用して、変更がない行を除外します。ただし、マージでステージングテーブルの行の大部分を使用しない場合には、このセクションで後ほど説明するように UPDATE と INSERT を別個に実行する方法を推奨しています。

## マージ方法 2: MERGE を使用せずに列リストを指定する
<a name="merge-method-specify-column-list"></a>

行全体を上書きするのではなく、テーブルの特定の列を更新する場合には、この方法を使用します。この方法では、更新のステップを追加する必要があり、MERGE コマンドを使用しないため、前の方法よりも時間がかかります。このため、以下の条件のいずれかに該当する場合にこの方法を使用してください。
+ テーブルの列すべてを更新するわけではない。
+ 更新でステージングテーブルの行のほとんどを使用しない。

**Topics**
+ [マージ方法 1: 既存の行を置き換える](#merge-method-replace-existing-rows)
+ [マージ方法 2: MERGE を使用せずに列リストを指定する](#merge-method-specify-column-list)
+ [一時的に使用するステージングテーブルを作成する](merge-create-staging-table.md)
+ [既存の行を置き換えてマージ操作を実現する](merge-replacing-existing-rows.md)
+ [MERGE コマンドを使用せずに列リストを指定してマージ操作を実行する](merge-specify-a-column-list.md)
+ [マージの例](merge-examples.md)

# 一時的に使用するステージングテーブルを作成する
<a name="merge-create-staging-table"></a>

*ステージングテーブル*は、*ターゲットテーブル*を変更 (更新、挿入含む) する際に使用するデータすべてを一時的に保持するためのテーブルです。

マージ操作では、ステージングテーブルとターゲットテーブルを結合する必要があります。結合する列をコロケーションするには、ステージングテーブルの分散キーを、ターゲットテーブルの分散キーと同じ列に設定する必要があります。例えば、ターゲットテーブルが分散キー列に外部キーを使用している場合には、ステージングテーブルの分散キーと同じ列を使用する必要があります。[CREATE TABLE LIKE](r_CREATE_TABLE_NEW.md#create-table-like) ステートメントを使用してステージングテーブルを作成すると、ステージングテーブルが親テーブルから分散キーを継承します。CREATE TABLE AS ステートメントを使用する場合、新しいテーブルは分散キーを継承しません。詳細については、「[クエリ最適化のためのデータのディストリビューション](t_Distributing_data.md)」を参照してください。

分散キーがプライマリキーと異なり、マージ操作の一環として分散キーが更新されない場合には、分散キー列の冗長結合述語を追加し、コロケーテッド結合を実現します。次に例を示します。

```
where target.primarykey = stage.primarykey 
and target.distkey = stage.distkey
```

クエリでコロケーテッド結合を使用するかどうかを確認するには、[EXPLAIN](r_EXPLAIN.md) を使用してクエリを実行し、結合すべてに DS\$1DIST\$1NONE があるかどうかを確認します。詳細については、「[クエリプランの評価](c_data_redistribution.md)」を参照してください。

# 既存の行を置き換えてマージ操作を実現する
<a name="merge-replacing-existing-rows"></a>

手順で説明しているマージオペレーションを実行するときは、一時的なステージングテーブルの作成と削除のステップを除き、すべてのステップを 1 つのトランザクションにまとめます。いずれかのステップが失敗した場合でも、トランザクションはロールバックされます。トランザクションを 1 つにすると、他にもコミットの回数が減るため、時間とリソースの節約になります。

**既存の行を置き換えてマージ操作を実現するには、以下の手順を実行します。**

1. 次の疑似コードに示すように、ステージングテーブルを作成し、マージの対象となるデータを移します。

   ```
   CREATE temp table stage (like target); 
   
   INSERT INTO stage 
   SELECT * FROM source 
   WHERE source.filter = 'filter_expression';
   ```

1.  MERGE を使用してステージングテーブルとの内部結合を実行し、ステージングテーブルと一致するターゲットテーブルの行を更新します。次に、ステージングテーブルと一致しない残りのすべての行をターゲットテーブルに挿入します。

    更新と挿入の操作は 1 つの MERGE コマンドで実行することをお勧めします。

   ```
   MERGE INTO target 
   USING stage [optional alias] on (target.primary_key = stage.primary_key)
   WHEN MATCHED THEN 
   UPDATE SET col_name1 = stage.col_name1 , col_name2= stage.col_name2, col_name3 = {expr}
   WHEN NOT MATCHED THEN
   INSERT (col_name1 , col_name2, col_name3) VALUES (stage.col_name1, stage.col_name2, {expr});
   ```

1. ステージングテーブルを削除 (Drop) します。

   ```
   DROP TABLE stage;
   ```

# MERGE コマンドを使用せずに列リストを指定してマージ操作を実行する
<a name="merge-specify-a-column-list"></a>

手順で説明しているマージオペレーションを実行するときは、すべてのステップを 1 つのトランザクションにまとめます。いずれかのステップが失敗した場合でも、トランザクションはロールバックされます。トランザクションを 1 つにすると、他にもコミットの回数が減るため、時間とリソースの節約になります。

**列リストを指定してマージ操作を実行するには、以下の手順を実行します。**

1. 操作全体を 1 つのトランザクションブロックにまとめます。

   ```
   BEGIN transaction;
   … 
   END transaction;
   ```

1. 次の疑似コードに示すように、ステージングテーブルを作成し、マージの対象となるデータを移します。

   ```
   create temp table stage (like target); 
   insert into stage 
   select * from source 
   where source.filter = 'filter_expression';
   ```

1. ステージングテーブルで内部結合を使用して、ターゲットテーブルを更新します。
   + UPDATE 句で、更新の対象となる列を明示的にリストします。
   + ステージングテーブルで内部結合を実行します。
   + 分散キーがプライマリキーと異なり、分散キーが更新の対象でない場合は、冗長結合を分散キーに追加します。クエリでコロケーテッド結合を使用するかどうかを確認するには、[EXPLAIN](r_EXPLAIN.md) を使用してクエリを実行し、結合すべてに DS\$1DIST\$1NONE があるかどうかを確認します。詳細については、「[クエリプランの評価](c_data_redistribution.md)」を参照してください。
   + ターゲットテーブルがタイムスタンプでソートされる場合、述語を追加し、ターゲットテーブルの範囲限定スキャンを活用します。詳細については、「[Amazon Redshift クエリの設計のベストプラクティス](c_designing-queries-best-practices.md)」を参照してください。
   + マージですべての行を使用しない場合は、句を追加して、変更する行をフィルタリングします。例えば、1 つ以上の列に不等フィルタを追加して、変更されていない列を除外します。
   + 問題が発生した場合に全体をロールバックできるよう、更新操作、削除操作、挿入操作を単一のトランザクションにまとめます。

    次に例を示します。

   ```
   begin transaction;
   
   update target 
   set col1 = stage.col1, 
   col2 = stage.col2, 
   col3 = 'expression' 
   from stage 
   where target.primarykey = stage.primarykey 
   and target.distkey = stage.distkey 
   and target.col3 > 'last_update_time' 
   and (target.col1 != stage.col1 
   or target.col2 != stage.col2 
   or target.col3 = 'filter_expression');
   ```

1. ターゲットテーブルで内部結合を使用して、ステージングテーブルから不要になった行を削除します。ターゲットテーブルの一部の行はすでにステージングテーブルの対応する行に一致し、その他は前のステップで更新されました。どちらの場合も、挿入のために必要ありません。

   ```
   delete from stage 
   using target 
   where stage.primarykey = target.primarykey;
   ```

1. ステージングテーブルから残りの行を挿入します。ステップ 2 の UPDATE ステートメントで使用した列リストと同じものを VALUES 句内で使用します。

   ```
   insert into target
   (select col1, col2, 'expression'
   from stage);
   
   end transaction;
   ```

1. ステージングテーブルを削除 (Drop) します。

   ```
   drop table stage;
   ```

# マージの例
<a name="merge-examples"></a>

以下の例では、マージを実行して SALES テーブルを更新します。最初の例では、ターゲットテーブルから削除した後でステージングテーブルからすべての行を挿入する、よりシンプルな方法を使用しています。2 番目の例では、ターゲットテーブル内の選択した列の更新が必要であるため、追加の更新ステップが含まれています。

[マージの例](#merge-examples) は、Amazon Redshift 用のサンプルデータセット (TICKIT データセット) を使用します。前提条件として、「[一般的なデータベースタスクの開始方法](https://docs.aws.amazon.com/redshift/latest/gsg/database-tasks.html)」ガイドの手順に従って、TICKIT テーブルとデータを設定できます。サンプルデータセットの詳細については、「[サンプルデータベース](https://docs.aws.amazon.com/redshift/latest/dg/c_sampledb.html)」を参照してください。

**マージデータソースのサンプル**

このセクションの例では、更新と挿入を両方とも含んでいるサンプル データソースが必要です。これらの例では、SALES テーブルからのデータを使用する SALES\$1UPDATE というサンプルテーブルを作成します。12 月の新しい販売アクティビティを表すランダムデータを新しいテーブルに入力します。SALES\$1UPDATE サンプルテーブルを使用して、ステージングテーブルを以下の例で作成します。

```
-- Create a sample table as a copy of the SALES table.

create table tickit.sales_update as
select * from tickit.sales;

-- Change every fifth row to have updates.

update tickit.sales_update
set qtysold = qtysold*2,
pricepaid = pricepaid*0.8,
commission = commission*1.1
where saletime > '2008-11-30'
and mod(sellerid, 5) = 0;

-- Add some new rows to have inserts.
-- This example creates a duplicate of every fourth row.

insert into tickit.sales_update
select (salesid + 172456) as salesid, listid, sellerid, buyerid, eventid, dateid, qtysold, pricepaid, commission, getdate() as saletime
from tickit.sales_update
where saletime > '2008-11-30'
and mod(sellerid, 4) = 0;
```

**マッチングキーに基づいて既存の行を置き換えるマージの例**

以下のスクリプトでは、SALES\$1UPDATE テーブルを使用して、12 月の販売アクティビティの新しいデータによる SALES テーブルでのマージ操作を実行します。この例では、SALES テーブルの更新がある行を置き換えます。この例では、qtysold 列と pricepaid 列を更新しますが、commission と saletime は変更しません。

```
MERGE into tickit.sales 
USING tickit.sales_update sales_update  
on ( sales.salesid = sales_update.salesid
and sales.listid = sales_update.listid
and sales_update.saletime > '2008-11-30'
and (sales.qtysold != sales_update.qtysold 
or sales.pricepaid != sales_update.pricepaid))
WHEN MATCHED THEN
update SET qtysold = sales_update.qtysold,
pricepaid = sales_update.pricepaid
WHEN NOT MATCHED THEN 
INSERT (salesid, listid, sellerid, buyerid, eventid, dateid, qtysold , pricepaid, commission, saletime)
values (sales_update.salesid, sales_update.listid, sales_update.sellerid, sales_update.buyerid, sales_update.eventid, 
sales_update.dateid, sales_update.qtysold , sales_update.pricepaid, sales_update.commission, sales_update.saletime);

-- Drop the staging table.
drop table tickit.sales_update;

-- Test to see that commission and salestime were not impacted.
SELECT sales.salesid, sales.commission, sales.salestime, sales_update.commission, sales_update.salestime 
FROM tickit.sales 
INNER JOIN tickit.sales_update sales_update  
ON 
sales.salesid = sales_update.salesid
AND sales.listid = sales_update.listid
AND sales_update.saletime > '2008-11-30'
AND (sales.commission != sales_update.commission 
OR sales.salestime != sales_update.salestime);
```

**MERGE を使用せずに列リストを指定するマージの例**

以下の例では、12 月の販売アクティビティの新しいデータで SALES を更新するマージ操作を実行します。更新と挿入の両方を含み、変更されていない行を含む、サンプルデータが必要です。この例では、QTYSOLD および PRICEPAID 列を更新し、COMMISSION および SALETIME は変更しません。以下のスクリプトでは、SALES\$1UPDATE テーブルを使用して、SALES テーブルでのマージ操作を実行しています。

```
-- Create a staging table and populate it with rows from SALES_UPDATE for Dec
create temp table stagesales as select * from sales_update
where saletime > '2008-11-30';

-- Start a new transaction
begin transaction;

-- Update the target table using an inner join with the staging table
-- The join includes a redundant predicate to collocate on the distribution key –- A filter on saletime enables a range-restricted scan on SALES

update sales
set qtysold = stagesales.qtysold,
pricepaid = stagesales.pricepaid
from stagesales
where sales.salesid = stagesales.salesid
and sales.listid = stagesales.listid
and stagesales.saletime > '2008-11-30'
and (sales.qtysold != stagesales.qtysold 
or sales.pricepaid != stagesales.pricepaid);
 
-- Delete matching rows from the staging table 
-- using an inner join with the target table

delete from stagesales
using sales
where sales.salesid = stagesales.salesid
and sales.listid = stagesales.listid;

-- Insert the remaining rows from the staging table into the target table
insert into sales
select * from stagesales;

-- End transaction and commit
end transaction;

-- Drop the staging table
drop table stagesales;
```