MERGE — テーブルの行を条件付きでINSERT、UPDATE、DELETEする
[ WITHwith_query
[, ...] ] MERGE INTO [ ONLY ]target_table_name
[ * ] [ [ AS ]target_alias
] USINGdata_source
ONjoin_condition
when_clause
[...] [ RETURNING { * |output_expression
[ [ AS ]output_name
] } [, ...] ] wheredata_source
is: { [ ONLY ]source_table_name
[ * ] | (source_query
) } [ [ AS ]source_alias
] andwhen_clause
is: { WHEN MATCHED [ ANDcondition
] THEN {merge_update
|merge_delete
| DO NOTHING } | WHEN NOT MATCHED BY SOURCE [ ANDcondition
] THEN {merge_update
|merge_delete
| DO NOTHING } | WHEN NOT MATCHED [ BY TARGET ] [ ANDcondition
] THEN {merge_insert
| DO NOTHING } } andmerge_insert
is: INSERT [(column_name
[, ...] )] [ OVERRIDING { SYSTEM | USER } VALUE ] { VALUES ( {expression
| DEFAULT } [, ...] ) | DEFAULT VALUES } andmerge_update
is: UPDATE SET {column_name
= {expression
| DEFAULT } | (column_name
[, ...] ) = [ ROW ] ( {expression
| DEFAULT } [, ...] ) | (column_name
[, ...] ) = (sub-SELECT
) } [, ...] andmerge_delete
is: DELETE
MERGE
は、data_source
を使用して、target_table_name
で指定された対象テーブルの行を変更するアクションを実行します。
MERGE
は、条件付きで行のINSERT
、UPDATE
またはDELETE
を実行できる単一のSQL文を提供します。
これがないと、複数の手続き言語文が必要になります。
最初に、MERGE
コマンドはdata_source
から対象テーブルへの結合を実行し、0以上の変更候補行を生成します。
各変更候補行に対して、MATCHED
、NOT MATCHED BY SOURCE
またはNOT MATCHED [BY TARGET]
の状態が一度だけ設定され、その後WHEN
句が指定された順序で評価されます。
各変更候補行に対して、真と評価される最初の句が実行されます。
どの変更候補行に対しても、1つのWHEN
句しか実行されません。
MERGE
アクションは、同じ名前の通常のUPDATE
、INSERT
またはDELETE
コマンドと同じ効果を持ちます。
これらのコマンドの構文は異なり、WHERE
句がなく、テーブル名が指定されていません。
すべてのアクションは対象テーブルを参照しますが、他のテーブルへの変更はトリガを使用して行うことができます。
DO NOTHING
が指定されている場合、元となる行はスキップされます。
アクションは指定された順序で評価されるため、DO NOTHING
は、より詳細な処理の前に、関心のない元となる行をスキップする場合に便利です。
オプションのRETURNING
句は、挿入、更新、削除された各行に基づいて値を計算し、返すようにMERGE
を設定します。
元となるテーブルまたは対象テーブルの列、あるいはmerge_action()
関数を使用する式が計算可能です。
INSERT
またはUPDATE
アクションが実行されると、対象テーブルの列の新しい値が使用されます。
DELETE
が実行されると、対象テーブルの列の古い値が使用されます。
RETURNING
リストの構文は、SELECT
の出力リストと同じです。
別個のMERGE
権限はありません。
更新アクションを指定する場合、SET
句で参照される対象テーブルの列に対するUPDATE
権限が必要です。
挿入アクションを指定する場合、対象テーブルに対するINSERT
権限が必要です。
削除アクションを指定する場合、対象テーブルに対するDELETE
権限が必要です。
DO NOTHING
アクションを指定する場合、対象テーブルの少なくとも1つの列に対するSELECT
権限が必要です。
また、data_source
の任意の列とcondition
(join_condition
を含む)またはexpression
で参照される対象テーブルの任意の列に対するSELECT
権限も必要です。
権限は文の開始時に一度テストされ、特定のWHEN
句が実行されるかどうかがチェックされます。
対象テーブルがマテリアライズドビュー、外部テーブルである場合、またはテーブルにルールが定義されている場合、MERGE
はサポートされません。
with_query
WITH
句を使用すると、MERGE
問い合わせで名前で参照できる1つ以上の副問い合わせを指定できます。
詳細は7.8とSELECTを参照してください。
WITH RECURSIVE
はMERGE
ではサポートされていないことに注意してください。
target_table_name
マージ先の対象テーブルもしくはビューの名前です(スキーマ修飾名も可)。
テーブル名の前にONLY
を指定すると、指定したテーブルでのみ一致する行が更新または削除されます。
ONLY
を指定しないと、指定したテーブルを継承するテーブルでも一致する行が更新または削除されます。
オプションで、テーブル名の後に*
を指定して、子孫のテーブルが含まれることを明示的に示すことができます。
ONLY
キーワードおよび*
オプションは、挿入操作には影響しません。挿入操作では、常に指定したテーブルにのみ挿入します。
target_table_name
がビューの場合、INSTEAD OF
トリガを使用せずに自動的に更新可能であるか、WHEN
句で指定されたすべてのアクション(INSERT
、UPDATE
、DELETE
)に対してINSTEAD OF
トリガを持つ必要があります。
ルール付きビューはサポートされていません。
target_alias
対象テーブルの代替名です。
別名を指定すると、テーブルの実際の名前が完全に非表示になります。
たとえば、MERGE INTO foo AS f
を指定した場合、MERGE
文の残りの部分は、このテーブルをfoo
ではなくf
として参照する必要があります。
source_table_name
元となるテーブル、ビュー、または遷移テーブルの名前(スキーマ修飾名も可)。
テーブル名の前にONLY
を指定すると、指定したテーブルのみからの一致する行が含まれます。
ONLY
を指定しないと、指定したテーブルを継承するすべてのテーブルからも一致する行が含まれます。
オプションで、テーブル名の後に*
を指定して、子孫のテーブルが含まれることを明示的に示すことができます。
source_query
対象テーブルにマージされる行を提供する問い合わせ(SELECT
文またはVALUES
文)です。
構文の説明は、SELECT文またはVALUES文を参照してください。
source_alias
データソースの代替名です。 別名を指定すると、テーブルの実際の名前や問い合わせが発行された事実が完全に隠されます。
join_condition
join_condition
はboolean
型の値を返す式です(WHERE
句に似ています)。この式は、data_source
のどの行が対象テーブルの行と一致するかを指定します。
join_condition
には、data_source
行に一致しようとする対象テーブルの列のみが表示されます。
対象テーブルの列のみを参照するjoin_condition
副式は、実行されるアクションに影響を与える可能性があり、多くの場合驚くべき方法で影響を与えます。
WHEN NOT MATCHED BY SOURCE
とWHEN NOT MATCHED [BY TARGET]
の両方の句が指定された場合、MERGE
コマンドはdata_source
と対象テーブルの間でFULL
結合を実行します。
これを機能させるには、少なくとも1つのjoin_condition
副式がハッシュ結合をサポートできる演算子を使用するか、すべての副式がマージ結合をサポートできる演算子を使用する必要があります。
when_clause
少なくとも1つのWHEN
句が必要です。
WHEN
句は、WHEN MATCHED
、WHEN NOT MATCHED BY SOURCE
またはWHEN NOT MATCHED [BY TARGET]
を指定できます。
標準SQLでは、WHEN MATCHED
とWHEN NOT MATCHED
(一致する対象行がないことを意味するものとして定義されている)のみを定義していることに注意してください。
WHEN NOT MATCHED BY SOURCE
は標準SQLの拡張です。その意味をより明確にする、WHEN NOT MATCHED
にBY TARGET
を付加するオプションも同様に拡張です。
WHEN
句でWHEN MATCHED
が指定され、変更候補行がdata_source
の行と対象テーブルの行と一致する場合、condition
が存在しないかtrue
と評価されるとWHEN
句が実行されます。
WHEN
句でWHEN NOT MATCHED BY SOURCE
が指定され、候補変更行がdata_source
の行と一致しない対象テーブルの行を表す場合、condition
が存在しないかtrue
と評価された場合にWHEN
句が実行されます。
WHEN
句でWHEN NOT MATCHED [BY TARGET]
が指定され、候補変更行がdata_source
の行を表し、その行が対象テーブルの行と一致しない場合、condition
が存在しないかtrue
と評価された場合にWHEN
句が実行されます。
condition
boolean
型の値を返す式。
WHEN
句のこの式がtrue
を返す場合、その句のアクションがその行に対して実行されます。
WHEN MATCHED
句の条件は、元となるリレーションと対象リレーションの両方の列を参照できます。
WHEN NOT MATCHED BY SOURCE
句の条件は、対象リレーションの列のみを参照できます。これは、定義上、一致する元となる行がないためです。
WHEN NOT MATCHED [BY TARGET]
句の条件は、元となるリレーションの列のみを参照できます。これは、定義上、一致する対象行がないためです。
対象テーブルのシステム属性のみにアクセスできます。
merge_insert
対象テーブルに1つの行を挿入するINSERT
アクションの指定。
対象列名は任意の順序でリストできます。
列名のリストがまったく指定されていない場合、デフォルトではテーブルのすべての列が宣言された順序になります。
明示的または暗黙的な列リストにない各列にはデフォルト値(デフォルト値が宣言されていればその値、未宣言ならばNULL)が挿入されます。
対象テーブルがパーティションテーブルの場合、各行は適切なパーティションにルーティングされ、パーティションに挿入されます。 対象テーブルがパーティションの場合、入力行がパーティション制約に違反するとエラーが発生します。
列名を複数回指定することはできません。
INSERT
アクションに副SELECTを含めることはできません。
VALUES
句は1つしか指定できません。
VALUES
句は元となるリレーションの列のみを参照できます。
これは、定義上、一致する対象行がないためです。
merge_update
対象テーブルの現在の行を更新するUPDATE
アクションの指定。
列名は2回以上指定できません。
テーブル名もWHERE
句も使用できません。
merge_delete
対象テーブルの現在の行を削除するDELETE
アクションを指定します。
DELETEコマンドで通常行うように、テーブル名やその他の句は含めないでください。
column_name
対象テーブルの列名。 列名は、必要に応じてサブフィールド名または配列の添字で修飾できます。 (複合列の一部のフィールドにのみ挿入すると、他のフィールドはNULLになります。) 対象列の指定には、テーブルの名前を含めないでください。
OVERRIDING SYSTEM VALUE
この句を使用しない場合、GENERATED ALWAYS
として定義されたID列に対して明示的な値(DEFAULT
以外)を指定するとエラーになります。
この句は、この制限を上書きします。
OVERRIDING USER VALUE
この句を指定した場合、GENERATED BY DEFAULT
として定義されたID列に提供された値は無視され、シーケンスで生成されたデフォルト値が適用されます。
DEFAULT VALUES
すべての列にデフォルト値が設定されます。
(このフォームではOVERRIDING
句は使用できません。)
expression
列に割り当てる式。
WHEN MATCHED
句で使用する場合、式は対象テーブルの元の行からの値とdata_source
行からの値を使用できます。
WHEN NOT MATCHED BY SOURCE
句で使用する場合、式は対象テーブルの元の行からの値のみを使用できます。
WHEN NOT MATCHED [BY TARGET]
句で使用する場合、式はdata_source
行からの値のみを使用できます。
DEFAULT
列をデフォルト値に設定します(特定のデフォルト式が割り当てられていない場合はNULL
になります)。
sub-SELECT
それに先行する括弧付きの列リストに列挙されている出力列と同じ数の出力列を生成するSELECT
副問い合わせ。
副問い合わせは、実行時に2行以上生成してはいけません。
行が1つ返されると、その列の値が対象列に割り当てられます。
行が返されない場合は、NULL値が対象列に割り当てられます。
WHEN MATCHED
句で使用する場合、副問い合わせは、対象テーブルの元の行からの値とdata_source
行からの値を参照できます。
WHEN NOT MATCHED BY SOURCE
句で使用する場合、副問い合わせは、対象テーブルの元の行からの値のみを参照できます。
output_expression
各行が変更(挿入、更新、削除)された後にMERGE
コマンドによって計算され、返される式です。
式には、元となるテーブルまたは対象テーブルの任意の列、あるいは実行されたアクションに関する追加情報を返すmerge_action()
関数を使用できます。
*
を指定すると、元となるテーブルのすべての列が返され、その後に対象テーブルのすべての列が返されます。
多くの場合、元となるテーブルと対象テーブルは同じ列を多く持つため、この方法では重複が多くなります。
この問題を回避するには、元となるテーブルまたは対象テーブルの名前または別名で*
を修飾します。
output_name
返される列で使用される名前です。
正常に完了すると、MERGE
コマンドは以下の形式のコマンドタグを返します。
MERGE total_count
total_count
は変更された行の合計数です(挿入、更新、または削除のいずれか)。
total_count
が0の場合、行はまったく変更されていません。
MERGE
コマンドがRETURNING
句を含む場合、結果はRETURNING
リストに定義された列と値を含むSELECT
文と同様になります。この場合、コマンドにより挿入、更新、削除された行に対して計算されます。
次のステップは、MERGE
の実行中に行われます。
WHEN
句が一致するかどうかに関係なく、指定されたすべてのアクションに対してBEFORE STATEMENT
トリガを実行します。
元となるテーブルから対象テーブルへの結合を実行します。 結果の問合せは通常どおり最適化され、一連の変更候補行が生成されます。 各変更候補行について、
各行がMATCHED
、NOT MATCHED BY SOURCE
、またはNOT MATCHED [BY TARGET]
のいずれであるかを評価します。
真が返されるまで、各WHEN
条件を指定された順序でテストします。
条件が真を返す場合は、次のアクションを実行します。
アクションのイベントタイプに対して起動するBEFORE ROW
トリガを実行します。
指定されたアクションを実行し、対象テーブルの検査制約を呼び出します。
アクションのイベントタイプに対して起動するAFTER ROW
トリガを実行します。
対象リレーションがアクションのイベントタイプに対してINSTEAD OF ROW
トリガを持つビューである場合、それらは代わりにアクションを実行するために使われます。
アクションが実際に発生するかどうかに関係なく、指定されたアクションに対してAFTER STATEMENT
トリガを実行します。
これは、行を変更しないUPDATE
文の動作に似ています。
要約するとイベントタイプの文トリガ(たとえば、INSERT
など)は、その種類のアクションを指定 するたびに起動されます。
対照的に、行レベルトリガは、実行される特定のイベントタイプに対してのみ起動されます。
したがって、MERGE
コマンドでは、UPDATE
行トリガのみが起動された場合でも、UPDATE
とINSERT
の両方に対して文トリガを起動する可能性があります。
結合では、各対象行に対して最大1つの変更候補行が生成されるようにする必要があります。
つまり、対象行は複数のデータソース行に結合できません。
結合する場合、変更候補行の1つだけが対象行の変更に使用されます。
後で行を変更しようとするとエラーが発生します。
これは、行トリガが対象テーブルを変更し、変更された行が後でMERGE
によっても変更される場合にも発生する可能性があります。
繰り返されるアクションがINSERT
の場合、一意性違反が発生しますが、UPDATE
またはDELETE
を繰り返すとカーディナリティ違反が発生します。
後者の動作は標準SQLで要求されています。
これは、PostgreSQLのUPDATE
およびDELETE
文における結合の歴史的な動作とは異なります。
この動作では、2回目以降の同じ行の変更は単純に無視されます。
WHEN
句でAND
副句が省略された場合、その句はその種類の最終到達可能句(MATCHED
、NOT MATCHED BY SOURCE
またはNOT MATCHED [BY TARGET]
)になります。
その種類の後のWHEN
句が指定された場合、到達不能である可能性があり、エラーが発生します。
いずれの種類の最終到達可能句も指定されていない場合、候補変更行に対してアクションが実行されない可能性があります。
デフォルトでは、データソースから行が生成される順序は不定です。
source_query
を使用して、必要に応じて一貫した順序を指定できます。これは、並行しているトランザクション間のデッドロックを回避するために必要になる場合があります。
MERGE
を対象テーブルを変更する他のコマンドと同時に実行すると、通常のトランザクション分離規則が適用されます。
各分離レベルでの動作の説明は13.2を参照してください。
また、INSERT ... ON CONFLICT
を代替文として使用することも検討できます。
この文は、同時INSERT
が発生した場合にUPDATE
を実行する機能を提供します。
2つの文タイプの間には様々な違いや制限があり、相互に交換することはできません。
新規recent_transactions
に基づいて、customer_accounts
のメンテナンスを実行します。
MERGE INTO customer_account ca USING recent_transactions t ON t.customer_id = ca.customer_id WHEN MATCHED THEN UPDATE SET balance = balance + transaction_value WHEN NOT MATCHED THEN INSERT (customer_id, balance) VALUES (t.customer_id, t.transaction_value);
MATCHED
の結果は実行中に変更されないため、これは次の文とまったく同じになることに注意してください。
MERGE INTO customer_account ca USING (SELECT customer_id, transaction_value FROM recent_transactions) AS t ON t.customer_id = ca.customer_id WHEN MATCHED THEN UPDATE SET balance = balance + transaction_value WHEN NOT MATCHED THEN INSERT (customer_id, balance) VALUES (t.customer_id, t.transaction_value);
在庫数量とともに新規在庫品目を挿入しようとします。 品目がすでに存在する場合は、既存品目の在庫数を更新します。 在庫数が0のエントリは許可しません。 実行されたすべての変更の詳細を返します。
MERGE INTO wines w USING wine_stock_changes s ON s.winename = w.winename WHEN NOT MATCHED AND s.stock_delta > 0 THEN INSERT VALUES(s.winename, s.stock_delta) WHEN MATCHED AND w.stock + s.stock_delta > 0 THEN UPDATE SET stock = w.stock + s.stock_delta WHEN MATCHED THEN DELETE RETURNING merge_action(), w.*;
wine_stock_changes
テーブルは、たとえば、最近データベースにロードされた一時テーブルです。
置換ワインリストに基づいてwines
を更新し、新しい在庫の行を挿入し、変更された在庫エントリを更新し、新しいリストにないワインを削除します。
MERGE INTO wines w USING new_wine_list s ON s.winename = w.winename WHEN NOT MATCHED BY TARGET THEN INSERT VALUES(s.winename, s.stock) WHEN MATCHED AND w.stock != s.stock THEN UPDATE SET stock = s.stock WHEN NOT MATCHED BY SOURCE THEN DELETE;
このコマンドは標準SQLに準拠しています。
WITH
句、WHEN NOT MATCHED
のBY SOURCE
およびBY TARGET
修飾子、DO NOTHING
アクションおよびRETURNING
句は、標準SQLの拡張です。