すべてのプロダクト
Search
ドキュメントセンター

MaxCompute:データの挿入または上書き (INSERT INTO | INSERT OVERWRITE)

最終更新日:Aug 22, 2026

MaxCompute では、INSERT INTO または INSERT OVERWRITE を使用して、ターゲットテーブルまたは静的パーティションにデータを挿入または上書きできます。

このトピックのコマンドは、次のプラットフォームで実行できます:

前提条件

INSERT INTO および INSERT OVERWRITE 操作を実行するには、ターゲットテーブルに対する Update 権限と、ソーステーブルに対する Select 権限が必要です。権限の付与に関する詳細については、「MaxCompute 権限」をご参照ください。

概要

MaxCompute SQL でデータを処理する場合、INSERT INTO または INSERT OVERWRITE 文を使用して、SELECT クエリの結果をターゲットテーブルに保存できます。違いは次のとおりです:

  • INSERT INTO:テーブルまたは静的パーティションにデータを追記します。INSERT 文でパーティション値を指定して、特定のパーティションにデータを挿入できます。少量のテストデータを挿入するには、この文を VALUES とともに使用します。

  • INSERT OVERWRITE:テーブルまたは静的パーティションの既存のデータをクリアしてから、新しいデータを挿入します。

    説明
    • MaxCompute の INSERT 構文は、MySQL や Oracle の INSERT 構文とは異なります。INSERT INTOINSERT OVERWRITE の両方の文で TABLE キーワードを省略できます。

    • 同じパーティションに対して INSERT OVERWRITE 操作を繰り返し実行すると、DESC コマンドによって返されるパーティションの Size が異なる場合があります。これは、パーティションからデータを SELECT し、そのデータを INSERT OVERWRITE を使用して同じパーティションに書き戻す際に、ファイル分割ロジックが変更されるためです。その結果、データの Size も変化します。INSERT OVERWRITE 操作の前後で合計データ長は同じままであり、追加のストレージ料金は発生しません。

動的パーティションへのデータ挿入方法については、「動的パーティションへのデータの挿入または上書き (DYNAMIC PARTITION)」をご参照ください。

制限事項

  • INSERT INTO および INSERT OVERWRITE を使用してテーブルまたは静的パーティションのデータを更新する場合、次の制限事項があります:

    • INSERT INTO:クラスター化テーブルにデータを追記することはできません。

    • INSERT OVERWRITE:挿入する列の指定はサポートされていません。列を指定するには、INSERT INTO を使用します。たとえば、CREATE TABLE t(a STRING, b STRING); INSERT INTO t(a) VALUES ('1'); という文は、列 a に '1' を挿入し、列 b を NULL またはそのデフォルト値に設定します。

    • MaxCompute はテーブルロックを実装していません。同じテーブルに対して INSERT INTO または INSERT OVERWRITE 操作を同時に実行しないでください。

  • Delta テーブルには、次の制限事項があります。

    • INSERT OVERWRITE を使用して Delta テーブルにデータを書き込む際、同じ PK 値を持つ複数の行は、書き込み前に重複排除されます。最初の行のみが書き込まれます。最終的な結果は、計算プロセス中のレコードの順序に依存し、手動で指定することはできません。この操作はデータセット全体を書き込むため、このデフォルトの重複排除はプライマリキーの一意性を保証するのに役立ちます。

    • INSERT INTO を使用して Delta テーブルにデータを書き込む場合、デフォルトでは、同じ主キー (PK) 値を持つ複数の行は重複排除されず、すべてがテーブルに書き込まれます。ただし、set odps.sql.insert.acidtable.deduplicate.enable = true を設定した場合、データはテーブルに書き込まれる前に重複排除されます。

構文

INSERT {INTO|OVERWRITE} TABLE <table_name> [PARTITION (<pt_spec>)] [(<col_name> [,<col_name> ...)]]
<select_statement>
FROM <from_statement>
[ZORDER BY <zcol_name> [, <zcol_name> ...]];

次の表で各パラメーターについて説明します。

パラメーター

必須

説明

table_name

はい

データを挿入するターゲットテーブルの名前。

pt_spec

いいえ

データを挿入するパーティション。定数を指定する必要があります。関数や式は使用できません。

形式は (partition_col1 = partition_col_value1, partition_col2 = partition_col_value2, ...) です。

col_name

いいえ

データを挿入するターゲットテーブルの列名。

INSERT OVERWRITE[(<col_name> [,<col_name> ...)] の指定をサポートしていません。

select_statement

はい

ソーステーブルから挿入するデータをクエリする SELECT 句。SELECT 文の詳細については、「SELECT 構文」をご参照ください。

説明
  • ソーステーブルとターゲットテーブル間のマッピングは、列名ではなく、SELECT 句の列の順序に依存します。

  • 静的パーティションにデータを挿入する場合、パーティション列を SELECT 句に含めることはできません。

from_statement

はい

ソーステーブル名などのデータソースを指定する FROM 句。

ZORDER BY <zcol_name> [, <zcol_name> ...]

いいえ

テーブルまたはパーティションにデータを書き込む際に、1 つ以上の指定された列 (select_statement に対応するテーブル内の列) でデータをソートすることで、類似したデータを持つ行をグループ化できます。これにより、クエリのフィルタリングパフォーマンスが向上し、ストレージコストを削減できます。ORDER BY x, y はデータをまず x で、次に y で厳密にソートしますが、ZORDER BY x, y は類似した <x, y> のペアをグループ化します。SQL クエリのフィルター条件にソート列が含まれている場合、ORDER BY でソートされたデータは x を含む式に対してのみ効果的なフィルタリングを提供します。対照的に、ZORDER BY でソートされたデータは x または x と y の両方を含む式に対して効果的なフィルタリングを提供し、より高い列圧縮率を実現します。

ZORDER BYSORT BY の違いは次のとおりです:

  • ZORDER BY には、ローカル zorder とグローバル zorder の 2 つのモードがあります。デフォルトモードは local zorder です。ローカルモードは、個々のファイル内でのみデータを Z オーダーでソートし、データをグローバルに再配布しません。そのため、データが複数のファイルに分散している場合、データのクラスタリングが低くなり、効果的なデータスキップが妨げられる可能性があります。この問題に対処するため、新しいバージョンでは global zorder がサポートされています。global zorder モードを使用するには、次のパラメーターを設定します:SET odps.sql.default.zorder.type=global;

    ZORDER BY には、次の 制限事項 があります:

    • パーティションテーブルの場合、一度に 1 つのパーティションに対してのみ ZORDER BY ソートを実行できます。

    • ZORDER BY の列数は 2 から 4 の間でなければなりません。

    • ターゲットテーブルがクラスター化テーブルの場合、ZORDER BY 句はサポートされていません。

    • ZORDER BYDISTRIBUTE BY と併用できますが ORDER BYCLUSTER BY、または SORT BY とは併用できません。

    説明

    ZORDER BY 句を使用してデータを書き込む場合、操作はソートしない場合よりも多くのリソースを消費し、時間がかかります。

  • SORT BY 文は、単一ファイル内でデータがどのようにソートされるかを指定するために使用されます。SORT BY を指定しない場合、単一ファイル内のデータは local zorder でソートされます。

例:通常のテーブル

  • 例 1:INSERT INTO コマンドを実行して、非パーティション化テーブル websites にデータを追記します。コマンドは次のとおりです:

    -- websites という名前の非パーティション化テーブルを作成します。
    CREATE TABLE IF NOT EXISTS websites
    (id INT,
     name STRING,
     url STRING
    );
    -- apps という名前の非パーティション化テーブルを作成します。
    CREATE TABLE IF NOT EXISTS apps
    (id INT,
     app_name STRING,
     url STRING
    );
    -- apps テーブルにデータを追記します。`INSERT INTO TABLE ` の TABLE キーワードは省略可能です。
    INSERT INTO apps (id,app_name,url) VALUES 
    (1,'Aliyun','https://www.aliyun.com');
    -- apps テーブルからデータをコピーし、websites テーブルに追記します。
    INSERT INTO websites (id,name,url) SELECT id,app_name,url
    FROM apps;
    -- SELECT 文を実行して websites テーブルのデータを表示します。
    SELECT * FROM websites;

    次の結果が返されます:

    -- 結果
    +------------+------------+------------+
    | id         | name       | url        |
    +------------+------------+------------+
    | 1          | Aliyun     | https://www.aliyun.com |
    +------------+------------+------------+
  • 例 2:INSERT INTO コマンドを実行して、パーティションテーブル sale_detail にデータを追記します。コマンドの例を次に示します:

    -- sale_detail という名前のパーティションテーブルを作成します。
    CREATE TABLE IF NOT EXISTS sale_detail
    (
    shop_name     STRING,
    customer_id   STRING,
    total_price   DOUBLE
    )
    PARTITIONED BY (sale_date STRING, region STRING);
    
    -- ソーステーブルにパーティションを追加します。この手順は任意です。パーティションが存在しない場合は、データ書き込み時に自動的に作成されます。
    ALTER TABLE sale_detail ADD PARTITION (sale_date='2013', region='china');
    
    -- ソーステーブルにデータを追記します。INSERT INTO および INSERT OVERWRITE の後の TABLE キーワードは省略可能です。
    INSERT INTO sale_detail PARTITION (sale_date='2013', region='china') VALUES ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);
    
    -- 現在のセッションでのみフルテーブルスキャンを有効にします。SELECT 文を実行して sale_detail テーブルのデータを表示します。
    SET odps.sql.allow.fullscan=true; 
    SELECT * FROM sale_detail;

    次の結果が返されます:

    +------------+-------------+-------------+------------+------------+
    | shop_name  | customer_id | total_price | sale_date  | region     |
    +------------+-------------+-------------+------------+------------+
    | s1         | c1          | 100.1       | 2013       | china      |
    | s2         | c2          | 100.2       | 2013       | china      |
    | s3         | c3          | 100.3       | 2013       | china      |
    +------------+-------------+-------------+------------+------------+
  • 例 3:INSERT OVERWRITE コマンドを実行して、sale_detail_insert テーブルのデータを上書きします。コマンドの例を次に示します:

    -- sale_detail と同じスキーマを持つターゲットテーブル sale_detail_insert を作成します。
    CREATE TABLE sale_detail_insert LIKE sale_detail;
    
    -- ターゲットテーブルにパーティションを追加します。この手順は任意です。パーティションが存在しない場合は、データ書き込み時に自動的に作成されます。
    ALTER TABLE sale_detail_insert ADD PARTITION (sale_date='2013', region='china');
    
    -- 静的パーティションを上書きします。静的パーティションの場合、パーティション列は PARTITION() 句で指定され、SELECT リストに含めることはできません。SELECT リストの列は、位置に基づいてターゲットテーブルの列にマッピングされます。
    SET odps.sql.allow.fullscan=true;
    INSERT OVERWRITE TABLE sale_detail_insert PARTITION (sale_date='2013', region='china')
      SELECT 
      shop_name, 
      customer_id,
      total_price 
      FROM sale_detail
      ZORDER BY customer_id, total_price;
    
    -- 現在のセッションでのみフルテーブルスキャンを有効にします。SELECT 文を実行して sale_detail_insert テーブルのデータを表示します。
    SET odps.sql.allow.fullscan=true;
    SELECT * FROM sale_detail_insert;

    次の結果が返されます:

    +------------+-------------+-------------+------------+------------+
    | shop_name  | customer_id | total_price | sale_date  | region     |
    +------------+-------------+-------------+------------+------------+
    | s1         | c1          | 100.1       | 2013       | china      |
    | s2         | c2          | 100.2       | 2013       | china      |
    | s3         | c3          | 100.3       | 2013       | china      |
    +------------+-------------+-------------+------------+------------+
  • 例 4:INSERT OVERWRITE コマンドを実行して、sale_detail_insert テーブルのデータを上書きし、SELECT 句の列の順序を変更します。ソーステーブルとターゲットテーブルのマッピングは、列名ではなく SELECT 句の列の順序に基づいています。コマンドは次のとおりです:

    SET odps.sql.allow.fullscan=true;
    INSERT OVERWRITE TABLE sale_detail_insert PARTITION (sale_date='2013', region='china')
        SELECT customer_id, shop_name, total_price FROM sale_detail;    
    
    SET odps.sql.allow.fullscan=true;
    SELECT * FROM sale_detail_insert;                  

    次の結果が返されます:

    +------------+-------------+-------------+------------+------------+
    | shop_name  | customer_id | total_price | sale_date  | region     |
    +------------+-------------+-------------+------------+------------+
    | c1         | s1          | 100.1       | 2013       | china      |
    | c2         | s2          | 100.2       | 2013       | china      |
    | c3         | s3          | 100.3       | 2013       | china      |
    +------------+-------------+-------------+------------+------------+

    sale_detail_insert テーブルが作成されたときの列の順序は次のとおりでした:

    +-------------------+--------------------+-------------------+
    | shop_name STRING  | customer_id  STRING| total_price DOUBLE| 
    +-------------------+--------------------+-------------------+

    sale_detail から sale_detail_insert へのデータ挿入の順序は次のとおりです:

    +---------------------+--------------------+-------------------+
    | customer_id  STRING | shop_name STRING   | total_price DOUBLE| 
    +---------------------+--------------------+-------------------+

    この場合、sale_detail.customer_id のデータは sale_detail_insert.shop_name に挿入され、sale_detail.shop_name のデータは sale_detail_insert.customer_id に挿入されます。

  • 例 5:パーティションにデータを挿入する場合、パーティション列は SELECT 句に含めることはできません。次の文はエラーを返します。なぜなら、sale_dateregion はパーティション列であり、静的パーティションの SELECT 句では許可されていないためです。不正なコマンドの例を次に示します:

    INSERT OVERWRITE TABLE sale_detail_insert PARTITION (sale_date='2013', region='china')
       SELECT shop_name, customer_id, total_price, sale_date, region FROM sale_detail;
  • 例 6:PARTITION の値は定数のみ可能で、式は使用できません。不正なコマンドの例を次に示します:

    INSERT OVERWRITE TABLE sale_detail_insert PARTITION (sale_date=datepart('2016-09-18 01:10:00', 'yyyy') , region='china')
       SELECT shop_name, customer_id, total_price FROM sale_detail;
  • 例 7:INSERT OVERWRITE コマンドを実行して mf_srcmf_zorder_src テーブルのデータを上書きし、mf_zorder_src テーブルをグローバル Z オーダーモードでソートします。コマンドの例を次に示します:

    -- ターゲットテーブル mf_src を作成します。
    CREATE TABLE mf_src (key STRING, value STRING);
    
    INSERT OVERWRITE TABLE mf_src
    SELECT a, b FROM VALUES ('1', '1'),('3', '3'),('2', '2')
    AS t(a, b);
    
    SELECT * FROM mf_src;
    
    -- 次の結果が返されます。
    +-----+-------+
    | key | value |
    +-----+-------+
    | 1   | 1     |
    | 3   | 3     |
    | 2   | 2     |
    +-----+-------+
    
    -- mf_src と同じスキーマを持つターゲットテーブル mf_zorder_src を作成します。
    CREATE TABLE mf_zorder_src LIKE mf_src;
    
    -- ソートにグローバル Z オーダーモードを使用します。
    SET odps.sql.default.zorder.type=global;
    INSERT OVERWRITE TABLE mf_zorder_src
    SELECT key, value FROM mf_src 
    ZORDER BY key, value;
    
    SELECT * FROM mf_zorder_src;

    次の結果が返されます:

    +-----+-------+
    | key | value |
    +-----+-------+
    | 1   | 1     |
    | 2   | 2     |
    | 3   | 3     |
    +-----+-------+
  • 例 8:INSERT OVERWRITE コマンドを実行して、既存の target テーブルのデータを上書きします。コマンドは次のとおりです:

    -- 'target' テーブルは既存のテーブルです。
    SET odps.sql.default.zorder.type=global;
    INSERT OVERWRITE TABLE target
    SELECT key, value FROM target 
    ZORDER BY key, value;

例:Delta テーブル

例:Delta テーブル mf_dt を作成し、INSERT コマンドを実行してデータを挿入および上書きします。

-- mf_dt という名前の Delta テーブルを作成します。
CREATE TABLE IF NOT EXISTS mf_dt (pk BIGINT NOT NULL PRIMARY KEY, 
                  val BIGINT NOT NULL) 
                  PARTITIONED BY (dd STRING, hh STRING) 
                  tblproperties ("transactional"="true");
                  
-- mf_dt テーブルの dd='01' かつ hh='01' のパーティションにテストデータを挿入します。
INSERT OVERWRITE TABLE mf_dt PARTITION (dd='01', hh='01') 
                 VALUES (1, 1), (2, 2), (3, 3);

-- mf_dt テーブルのターゲットパーティションのデータをクエリします。                
SELECT * FROM mf_dt WHERE dd='01' AND hh='01';
-- 次の結果が返されます。
+------------+------------+----+----+
| pk         | val        | dd | hh |
+------------+------------+----+----+
| 1          | 1          | 01 | 01 |
| 3          | 3          | 01 | 01 |
| 2          | 2          | 01 | 01 |
+------------+------------+----+----+

-- 'INSERT INTO' を使用して mf_dt テーブルのターゲットパーティションにデータを追記します。
INSERT INTO TABLE mf_dt PARTITION(dd='01', hh='01') 
            VALUES (3, 30), (4, 4), (5, 5);
            
SELECT * FROM mf_dt WHERE dd='01' AND hh='01';
-- 次の結果が返されます。
+------------+------------+----+----+
| pk         | val        | dd | hh |
+------------+------------+----+----+
| 1          | 1          | 01 | 01 |
| 3          | 30         | 01 | 01 |
| 4          | 4          | 01 | 01 |
| 5          | 5          | 01 | 01 |
| 2          | 2          | 01 | 01 |
+------------+------------+----+----+

-- 'INSERT OVERWRITE' を使用して mf_dt テーブルのターゲットパーティションのデータを上書きします。
INSERT OVERWRITE TABLE mf_dt PARTITION (dd='01', hh='01') 
                 VALUES (1, 1), (2, 2), (3, 3);
SELECT * FROM mf_dt WHERE dd='01' AND hh='01';
-- 次の結果が返されます。
+------------+------------+----+----+
| pk         | val        | dd | hh |
+------------+------------+----+----+
| 1          | 1          | 01 | 01 |
| 3          | 3          | 01 | 01 |
| 2          | 2          | 01 | 01 |
+------------+------------+----+----+

-- 'INSERT OVERWRITE' を使用して mf_dt テーブルの dd='01' かつ hh='02' のパーティションにデータを書き込みます。
INSERT OVERWRITE TABLE mf_dt PARTITION (dd='01', hh='02') 
                 VALUES (1, 11), (2, 22), (3, 32);
SELECT * FROM mf_dt WHERE dd='01' AND hh='02';
-- 次の結果が返されます。
+------------+------------+----+----+
| pk         | val        | dd | hh |
+------------+------------+----+----+
| 1          | 11         | 01 | 02 |
| 3          | 32         | 01 | 02 |
| 2          | 22         | 01 | 02 |
+------------+------------+----+----+

-- 現在のセッションでのみフルテーブルスキャンを有効にします。SELECT 文を実行して mf_dt テーブルのデータを表示します。
SET odps.sql.allow.fullscan=true;
SELECT * FROM mf_dt;
-- 次の結果が返されます。
+------------+------------+----+----+
| pk         | val        | dd | hh |
+------------+------------+----+----+
| 1          | 11         | 01 | 02 |
| 3          | 32         | 01 | 02 |
| 2          | 22         | 01 | 02 |
| 1          | 1          | 01 | 01 |
| 3          | 3          | 01 | 01 |
| 2          | 2          | 01 | 01 |
+------------+------------+----+----+

ベストプラクティス

Z オーダーはすべてのシナリオに適しているわけではありません。ユースケースで実験して、ストレージとクエリパフォーマンスの利点が、Z オーダーデータを書き込むための追加の計算コストを正当化するかどうかを判断する必要がある場合があります。以下のセクションでは、一般的な推奨事項を説明します。

Zオーダーよりもクラスター化インデックスを選択する場合

  • フィルター条件が通常、列のプレフィックス (例: aa and b、または a and b and c) に基づいている場合、クラスター化インデックス (例: ORDER BY a, b, c) を使用する方が効果的です。この場合、ZORDER BY は使用しないでください。これは、ORDER BY が最初の列に対して優れたソートを提供し、後続の列への影響が少ないためです。対照的に、ZORDER BY は指定されたすべての列に均等な重みを与えるため、いずれか 1 つの列でのソートは、ORDER BY 句の最初の列でのソートよりも効率が低くなります。

  • 特定の列が JOIN キーに頻繁に現れる場合は、ハッシュクラスタリングまたはレンジクラスタリングがより適しています。MaxCompute の Z オーダー実装はファイル内でのみデータをソートし、SQL エンジンは Z オーダーのデータ分布を認識しません。しかし、SQL エンジンはクラスター化インデックスを認識し、クエリプランフェーズで JOIN パフォーマンスをより効果的に最適化できます。

  • 特定の列に対して GROUP BY および ORDER BY 操作を頻繁に実行する場合、クラスター化インデックスを使用するとパフォーマンスが向上することがあります。

Zオーダーの推奨事項

  • フィルター条件に頻繁に現れる列、特に一緒によくフィルタリングされる列を選択します。

  • ZORDER BY に含める列が多いほど、個々の列に対するソートの効果は低くなります。したがって、4 列を超えて指定しないでください。列が 1 つしかない場合は、Z オーダーではなくクラスター化インデックスを使用してください。

  • バランスの取れたカーディナリティ (個別値の数) を持つ列を選択します。性別列のような低カーディナリティの列は、ソートの利点が最小限です。ほとんどが一意の値を持つ高カーディナリティの列は、ソートコストを増加させます。なぜなら、MaxCompute の Z オーダー実装は、Z 値を計算するためにすべての個別値をメモリにキャッシュする必要があるためです。

  • テーブルサイズは小さすぎても大きすぎてもいけません。データ量が少なすぎる場合、Z オーダーの利点は明らかではありません。データ量が多すぎる場合、Z オーダーデータを生成するコストが高くなる可能性があり、ベースラインタスクの完了時間に大きな影響を与える可能性があります。