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

Hologres:INSERT ON CONFLICT (UPSERT)

最終更新日:Feb 04, 2026

このトピックでは、Hologres で INSERT ON CONFLICT 文を使用する方法について説明します。

利用シーン

INSERT ON CONFLICT コマンドは、SQL 文を使用してデータをインポートするシナリオに適しています。

Data Integration または Flink を使用してデータを書き込む場合、次の設定を構成して、重複するプライマリキーを持つ行を更新またはスキップできます。

  • DataWorks の Data Integration 機能を使用したデータのインポート

    Data Integration には、INSERT ON CONFLICT 機能が組み込まれています。この機能の仕組みの詳細については、「Hologres Writer」をご参照ください。次の設定を構成できます。

    • オフラインデータ同期の場合、[書き込み競合ポリシー][無視] または [置換] に設定します。

    • リアルタイムデータ同期の場合、[書き込み競合ポリシー][無視] または [置換] に設定できます。

    説明

    同期中にデータを更新するには、Hologres テーブルにプライマリキーを設定する必要があります。

  • Flink を使用したデータの書き込み

    Flink を使用してデータを書き込む場合、デフォルトの [書き込み競合ポリシー]InsertOrIgnore です。このポリシーでは、Hologres テーブルにプライマリキーを設定する必要があります。その後、最初のデータエントリを保持し、後続の重複するエントリはすべて無視します。ctas 構文を使用する場合、デフォルトの [書き込み競合ポリシー]InsertOrUpdate であり、既存のデータを置き換えます。

コマンドの概要

INSERT ON CONFLICT 文は、指定された列にデータの行を挿入します。重複するプライマリキーを持つ行が存在する場合、この文は既存の行を更新するか、挿入をスキップします。これにより、UPSERT (INSERT または UPDATE) 機能が提供されます。INSERT ON CONFLICT 文の構文は次のとおりです。

INSERT INTO <table_name> [ AS <alias> ] [ ( <column_name> [, ...] ) ]
    {  VALUES ( { <expression> } [, ...] ) [, ...] | <query> }
    [ ON CONFLICT [ conflict_target ] conflict_action ]

where conflict_target is pk

    ON CONSTRAINT constraint_name

and conflict_action is one of:

    DO NOTHING
    DO UPDATE SET { <column_name> = { <expression> } |
                    ( <column_name> [, ...] ) = ( { <expression> } [, ...] ) |
                  } [, ...]
              [ WHERE condition ]

次の表に各パラメーターを説明します。

パラメーター

説明

table_name

データの挿入先となるテーブルの名前。

alias

エイリアス。これは、宛先テーブルの代替名です。

column_name

宛先テーブルのターゲット列の名前。

DO NOTHING

InsertOrIgnore。指定された列に行を挿入する際に、重複するプライマリキーを持つ行が存在する場合、挿入はスキップされます。

DO UPDATE

InsertOrUpdate。指定された列に行を挿入する際に、重複するプライマリキーを持つ行が存在する場合、既存の行が更新されます。

次のケースがあります。

  • すべての列を更新:すべての列のデータが更新されます。これは全行更新です。

  • 特定の列を更新:指定された列のみが更新されます。欠落している列は更新されません。

  • 欠落している列が null 値で埋められる InsertOrReplace 操作を実装するには、値に手動で null を渡す必要があります。詳細については、このトピックの例をご参照ください。

  • 重要
    • 列にデフォルト値がある場合、DO UPDATE はその列を更新しません。これにより、パフォーマンスが低下します。

    • SQL 文 (INSERT ON CONFLICT) を使用して、欠落している列が null で埋められる InsertOrReplace 操作を実装するには、insert 値に null を渡す必要があります。Flink や Data Integration などのツールを使用し、InsertOrReplace を選択した場合、欠落している列には自動的に null 値が追加されます。

expression

対応する列に対して実行される式。PostgreSQL を参照して式を設定できます。

一般的な式には、b=excluded.b や、簡略化された (a, b, c) = ROW (excluded.*) があります。等式の左側は更新する列を指定します。右側は挿入式を指定し、これは VALUES または SELECT 句からの値です。excluded キーワードは、挿入対象として提案された行のエイリアスであり、ソーステーブルのエイリアスではありません。たとえば、column_name = excluded.column_name を考えてみましょう。column_name は宛先テーブルの列名です。column_name が宛先テーブルの N 番目の列である場合、excluded.column_name は提案された挿入行の N 番目の列を参照します。excluded.* を使用すると、提案された挿入行のすべての列が選択されます。列の順序は、宛先テーブルのデータ定義言語 (DDL) の順序と同じでなければなりません。

仕組み

INSERT ON CONFLICT 機能は、UPDATE 文と同じように機能します。詳細については、「UPDATE」をご参照ください。更新プロセスは、行指向、列指向、行列表ハイブリッドストレージなど、テーブルのストレージフォーマットによってわずかに異なります。これにより、異なるストレージフォーマットを使用するテーブルを更新する際にパフォーマンスに差が生じます。ビジネス要件に基づき、INSERT ON CONFLICT は InsertOrIgnoreInsertOrReplace、または InsertOrUpdate に分類できます。次の表にその違いを説明します。

更新モード

説明

InsertOrIgnore

書き込み中に更新を無視します。結果テーブルにプライマリキーがあり、リアルタイム書き込み中に重複するプライマリキーが検出された場合、後のデータは破棄されます。これは insert on conflict do nothing を使用して実装されます。

InsertOrUpdate

書き込み中にデータを更新します。結果テーブルにプライマリキーがあり、リアルタイム書き込み中に重複するプライマリキーが検出された場合、データはプライマリキーに基づいて更新されます。このモードには、全行更新と部分列更新が含まれます。部分列更新では、入力行にすべての列が含まれていない場合、欠落している列は更新されません。これは insert on conflict do update を使用して実装されます。

InsertOrReplace

書き込み中にデータを上書きします。結果テーブルにプライマリキーがあり、リアルタイム書き込み中に重複するプライマリキーが検出された場合、データはプライマリキーに基づいて更新されます。入力行にすべての列が含まれていない場合、欠落している列は null 値で埋められます。これは insert on conflict do update を使用し、手動で null 値を提供することで実装されます。

UPDATE 文の仕組みに基づき、異なるモードでの更新パフォーマンスは、テーブルのストレージフォーマットによって異なります。

  • 列指向テーブルの異なる書き込みモードのパフォーマンスは、次のようにランク付けされます。

    • 結果テーブルにプライマリキーがない場合、パフォーマンスは最高になります。

    • 結果テーブルにプライマリキーがある場合:InsertOrIgnore > InsertOrReplace >= InsertOrUpdate (全行) > InsertOrUpdate (部分列)

  • 行指向テーブルの異なる書き込みモードのパフォーマンスは、次のようにランク付けされます。

    InsertOrReplace = InsertOrUpdate (全行) >= InsertOrUpdate (部分列) >= InsertOrIgnore

制限事項

  • INSERT ON CONFLICT 文の条件には、すべてのプライマリキーを含める必要があります。

  • Hologres 高 QPS エンジン (HQE) が INSERT ON CONFLICT 文を実行する場合、操作の順序は保証されません。したがって、keep-first または keep-last のセマンティクスを実現することはできません。動作は keep-any です。実際には、データソースに削除する必要のある重複するプライマリキーが含まれている場合、次のコマンドを実行することで keep-last セマンティクスを使用できます。

    -- 重複行の最後を保持します。
    set hg_experimental_affect_row_multiple_times_keep_last = on;

  • INSERT ON CONFLICT 文の使用例:

    説明

    Hologres V2.1.17 以降では、サーバーレスコンピューティングがサポートされています。大規模なオフラインデータインポート、大規模な抽出、変換、ロード (ETL) ジョブ、外部テーブルに対する大量のクエリなどのシナリオでは、サーバーレスコンピューティングを使用してこれらのタスクを実行できます。この機能は、ご利用のインスタンス独自のリソースの代わりに、追加のサーバーレスリソースを使用します。インスタンスに追加の計算リソースを予約する必要はありません。これにより、インスタンスの安定性が大幅に向上し、メモリ不足 (OOM) エラーの可能性が減少し、個々のタスクに対してのみ課金されます。サーバーレスコンピューティングの詳細については、「サーバーレスコンピューティング」をご参照ください。サーバーレスコンピューティングの使用方法については、「サーバーレスコンピューティングの使用ガイド」をご参照ください。

    1. テーブルとデータの準備:

      begin ;
      create table test1 (
          a int NOT NULL PRIMARY KEY,
          b int,
          c int
      );
      commit ;
      
      insert into test1 values (1,2,3);
      
    2. さまざまなシナリオの例を表示:

      説明

      以下のシナリオ例は互いに独立しています。これらは順序どおりではなく、すべて前の手順で作成されたテーブルとデータに基づいています。

      • シナリオ 1:InsertOrIgnore 操作を実装します。重複するプライマリキーが存在する場合、行は更新されません。

        INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
        ON CONFLICT (a)
        DO NOTHING;
        
        -- 更新後の test1 テーブルのデータは次のとおりです。
        a	b	c
        1	2	3
      • シナリオ 2:全行更新のために InsertOrUpdate 操作を実装します。次のいずれかの方法を使用できます。

        • 方法 1:SET..EXCLUDED 句にすべての列をリストします。

          INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
          ON CONFLICT (a)
          DO UPDATE SET b = EXCLUDED.b, c = EXCLUDED.c;
          
          -- 更新後の test1 テーブルのデータは次のとおりです。
          a	b	c
          1	1	1
        • 方法 2:ROW(EXCLUDED.*) を使用してすべての列を更新します。

          INSERT INTO test1 (a, b, c)VALUES (1, 1, 1)
          ON CONFLICT (a)
          DO UPDATE SET (a,b,c) = ROW(EXCLUDED.*);
          
          -- 更新後の test1 テーブルのデータは次のとおりです。
          a	b	c
          1	1	1
      • シナリオ 3:部分列更新のために InsertOrUpdate 操作を実装します。指定された列のみが更新され、欠落している列は更新されません。

        -- 部分列更新を実行するには、SET の後に更新したい列をリストします。
        INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
        ON CONFLICT (a)
        DO UPDATE SET b = EXCLUDED.b;
        
        -- テーブルの列 c は更新されません。更新後の test1 テーブルのデータは次のとおりです。
        a	b	c
        1	1	3
      • シナリオ 4:InsertOrReplace 操作を実装します。これにより、行全体が上書きされます。列が欠落している場合、それらは null 値で埋められます。

        -- 欠落している列が null で埋められる InsertOrReplace 操作を実装するには、insert 値に手動で null を指定する必要があります。
        INSERT INTO test1 (a, b,c) VALUES (1, 1,null)
        ON CONFLICT (a)
        DO UPDATE SET b = EXCLUDED.b,c = EXCLUDED.c;
        
        -- 更新後の test1 テーブルのデータは次のとおりです。
        a	b	c
        1	1	\N
      • シナリオ 5:test1 テーブルのデータを別のテーブル test2 から更新します。

        -- test2 テーブルとデータを準備します。
        CREATE TABLE test2 (
            d int NOT NULL PRIMARY KEY,
            e int,
            f int
        );
        INSERT INTO test2 VALUES (1, 5, 6);
        
        
        -- test1 テーブルの行を、同じプライマリキーを持つ test2 テーブルの行で置き換えます。
        INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET
        (a,b,c) = ROW (excluded.*);
        
        -- 更新後の test1 テーブルのデータは次のとおりです。
        a	b	c
        1	5	6
        
        -- test1 テーブルの行を、同じプライマリキーを持つ test2 テーブルの行で置き換えますが、更新マッピングを調整します。test2 の列 e は列 c を更新し、test2 の列 f は列 b を更新します。
        INSERT INTO test1 (a, b, c) SELECT d,e,f FROM test2 ON CONFLICT (a) DO UPDATE SET
        (a,c,b) = ROW (excluded.*);
        -- 更新後の test1 テーブルのデータは次のとおりです。       
        a	b	c
        1	6	5
  • 行指向テーブルでの INSERT ON CONFLICT 文の最適化:

    Hologres は行指向テーブルの更新を最適化します。最高のパフォーマンスを得るには、UPDATE 句の列の順序を INSERT 句の順序と一致させ、全行更新を実行します。

    INSERT INTO test1 (a, b, c) 
    SELECT
        d,e,f
    FROM
        test2
    ON CONFLICT (a)
        DO UPDATE SET
            a = excluded.a,
            b = excluded.b,
            c = excluded.c;
            
    INSERT INTO test1 (a, b, c)
    SELECT d,e,f FROM test2
    ON CONFLICT (a)
    DO UPDATE SET(a,b,c) = ROW (excluded.*)

よくあるエラー

  • 症状

    データソースに対して INSERT ON CONFLICT 文を実行すると、次の 3 つのエラーのいずれかが発生します。

    • エラー 1:duplicate key value violates unique constraint

    • エラー 2:Update row with Key (xxx)=(yyy) multiple times

    • エラー 3 (OOM 問題):Total memory used by all existing queries exceeded memory limitation

  • 原因 1:データソースに重複データが含まれている。

    Hologres は PostgreSQL と互換性があり、標準の PostgreSQL 構文を使用します。標準の PostgreSQL セマンティクスによれば、INSERT ON CONFLICT 文を実行する際、データソースに重複データを含めることはできません。データソースに重複データが含まれている場合、上記のエラーのいずれかが発生します。

    説明

    データソース内の重複データとは、挿入されるデータに重複行が含まれていることを意味し、挿入されるデータが宛先テーブルに重複していることを意味するものではありません。

    次の例は、挿入されるデータに重複行が含まれている INSERT ON CONFLICT 文を示しています。

    INSERT INTO test1 VALUES (1, 2, 3), (1, 2, 3)
    ON CONFLICT (a) 
    DO UPDATE SET (a, b, c) = ROW (excluded.*);

    解決策:

    データソースに重複データが含まれている場合、次のパラメーターを設定して、重複行の最後を保持することができます。

    set hg_experimental_affect_row_multiple_times_keep_last = on;
  • 原因 2:生存時間 (TTL) が期限切れになったため、データソースに重複データが含まれている。

    データソースのテーブルには生存時間 (TTL) が設定されています。テーブル内の一部のデータが TTL を超えています。TTL のクリーンアップは瞬時に行われるわけではないため、期限切れのデータがすぐにクリアされない場合があります。これにより、インポート中に重複するプライマリキー (PK) データが発生し、エラーの原因となることがあります。

    解決策:

    Hologres V1.3.23 以降では、次のコマンドを使用して、期限切れの TTL によって引き起こされる重複 PK データを迅速に修正できます。このコマンドを実行すると、システムはテーブルから重複 PK データを削除します。デフォルトのクリーンアップポリシーは Keep Last で、重複の中から最後に書き込まれた行を保持し、その他を削除します。

    説明
    • 原則として、PK は重複してはなりません。したがって、このコマンドは期限切れの TTL によって引き起こされた重複 PK のみをクリーンアップします。

    • このコマンドは Hologres V1.3.23 以降でのみ利用可能です。ご利用のインスタンスがそれより前のバージョンの場合は、インスタンスをアップグレードする必要があります。

    call public.hg_remove_duplicated_pk('<schema>.<table_name>');

    例:2 つのテーブルがあるとします。tbl_1 は宛先テーブルで、tbl_2 は TTL が 300s のソーステーブルです。tbl_1tbl_2 のすべてのデータで更新したいとします。TTL が期限切れになると、tbl_2 に重複するプライマリキーが表示され、エラーが発生します。

    
    BEGIN;
    CREATE TABLE tbl_1 (
      a int NOT NULL PRIMARY KEY,
      b int,
      c int
    );
    CREATE TABLE tbl_2 (
      d int NOT NULL PRIMARY KEY,
      e int,
      f int
    );
    CALL set_table_property('tbl_2', 'time_to_live_in_seconds', '300'); 
    COMMIT;
    
    INSERT INTO tbl_1 VALUES (1, 1, 1), (2, 3, 4);
    INSERT INTO tbl_2 VALUES (1, 5, 6);
    -- 300 秒後、tbl_2 に再度データを挿入します。
    INSERT INTO tbl_2 VALUES (1, 3, 6);
    
    -- tbl_1 の行を、同じプライマリキーを持つ tbl_2 の行で置き換えます。期限切れの TTL によって引き起こされた重複 PK のため、更新は失敗します。
    INSERT INTO tbl_1 (a, b, c)
    SELECT
        d,e,f
    FROM
        tbl_2
    ON CONFLICT (a)
        DO UPDATE SET
            (a,b,c) = ROW (excluded.*);
    -- エラーの原因:ERROR: internal error: Duplicate keys detected when building hash table.
    
    -- コマンドを使用して tbl_2 の重複 PK データをクリーンアップします。ポリシーは keep last です。
    call public.hg_remove_duplicated_pk('tbl_2');
    
    -- データを再度 tbl_1 にインポートします。データは正常にインポートされます。
  • 原因 3:インスタンスのメモリリソースが不足しており、大量の書き込みタスクをサポートできない。

    解決策:

    • Hologres のサーバーレスコンピューティング機能を使用して、大量の書き込みタスクを実行します。Hologres V2.1.17 以降では、サーバーレスコンピューティングがサポートされています。この機能は、大規模なオフラインデータインポート、大規模な ETL ジョブ、外部テーブルに対する大量のクエリに使用できます。サーバーレスコンピューティングは、ご利用のインスタンス独自のリソースの代わりに、追加のサーバーレスリソースを使用してこれらのタスクを実行します。これにより、インスタンスに追加の計算リソースを予約する必要がなくなります。このアプローチにより、インスタンスの安定性が大幅に向上し、OOM エラーの可能性が減少します。個々のタスクに対してのみ課金されます。詳細については、「サーバーレスコンピューティング」および「サーバーレスコンピューティングの使用ガイド」をご参照ください。

    • 一般的な OOM エラーのトラブルシューティング」で説明されている方法に従ってください。