はじめに:MERGE文を書いたら謎のエラーが出た!
Snowflakeで「UPSERT(あれば更新、なければ挿入)」を実現するために MERGE 文を書いたことはありますか?便利な構文なのですが、いざ実行すると次のようなエラーに遭遇することがあります。
100090 (42P18): Duplicate row detected during DML action
Row Values: [123, 'Alice', '2026-05-01']
「えっ、重複って何?テーブルにユニーク制約も付けてないのに……」と戸惑った方も多いはず。実はこのエラー、Snowflake特有の「MERGEの安全装置」が働いた合図なのです。この記事では、なぜこのエラーが出るのか、そしてどう直せばいいのかを、初心者の方にもわかりやすく解説していきます!

そもそも MERGE 文ってなに?
MERGE 文は、ソーステーブル(取り込みたいデータ)とターゲットテーブル(更新したいデータ)を突き合わせて、条件に応じて UPDATE/INSERT/DELETE を1回のSQLで処理できる便利な構文です。日次の差分取り込みやマスタ同期でよく使われます。
MERGE INTO target t
USING source s
ON t.id = s.id
WHEN MATCHED THEN UPDATE SET t.name = s.name, t.updated_at = s.updated_at
WHEN NOT MATCHED THEN INSERT (id, name, updated_at) VALUES (s.id, s.name, s.updated_at);
とても便利な構文ですが、ひとつだけ守らないといけないルールがあります。それは「ターゲットの1行に対して、ソース側でマッチする行は1行だけ」というものです。
「Duplicate row detected」エラーの正体
このエラーは、ソース側に同じキーを持つ行が複数あり、ターゲットの1行をどの値で更新すればいいかSnowflakeが判断できないときに発生します。
たとえばソースに次のようなデータがあったとします。
id | name | updated_at
---+-------+------------
10 | Alice | 2026-05-01
10 | Alice | 2026-05-23 ← 同じid=10 が2行ある!
ターゲットの id=10 はどっちで上書きすべきでしょう?古い方?新しい方?Snowflakeは「結果が一意に決まらない処理は危険」と判断し、デフォルトでエラーを返して止めてくれます。これが ERROR_ON_NONDETERMINISTIC_MERGE という安全装置の働きです。
ちなみに似たようなエラーで「Single-row subquery returns more than one row」もあります。こちらも「1行を期待してるのに複数返ってきた」系のエラーで、考え方は共通です。
対処法その1:ソース側で重複を排除する(推奨)
もっとも安全で推奨されるのは、MERGE する前にソース側で重複を取り除いておく方法です。「最新の1件だけ残す」ことが多いので、QUALIFY ROW_NUMBER() を使うのが定番テクニックになります。
MERGE INTO target t
USING (
SELECT id, name, updated_at
FROM source
QUALIFY ROW_NUMBER() OVER (
PARTITION BY id ORDER BY updated_at DESC
) = 1
) s
ON t.id = s.id
WHEN MATCHED THEN UPDATE SET t.name = s.name, t.updated_at = s.updated_at
WHEN NOT MATCHED THEN INSERT (id, name, updated_at) VALUES (s.id, s.name, s.updated_at);
こうすれば id ごとに updated_at が最新の1行だけが残るので、Snowflakeも安心して MERGE を実行できます。
単純な完全重複なら DISTINCT でもOK
全カラムまったく同じ値が複数ある「完全重複」だけなら、SELECT DISTINCT で済むこともあります。
USING (SELECT DISTINCT id, name, updated_at FROM source) s

対処法その2:パラメータでチェックを緩める(非推奨)
Snowflakeには ERROR_ON_NONDETERMINISTIC_MERGE というセッションパラメータがあり、これを FALSE に設定するとエラーを抑制できます。
ALTER SESSION SET ERROR_ON_NONDETERMINISTIC_MERGE = FALSE;
ただし、これは「重複があってもどれか1行を勝手に採用する」設定なので、どの値で更新されるかはSnowflakeまかせになります。「日次バッチで毎回結果が違う!」みたいなトラブルにつながるので、原則使わない方が安全です。どうしても使う場合は、データの性質上「どれが残ってもよい」と分かっている場合に限りましょう。
対処法その3:MERGE前にCOPY INTOやステージング段階で対策
外部ファイルから取り込んだ直後にMERGEを実行する場合、そもそもロード元のファイル自体に重複行が含まれていることもあります。COPY INTO の失敗チェックリストやJSONロード時のエラー対処と組み合わせて、まずは「正しくロードできているか」「ステージング段階で重複が混入していないか」も確認してみてください。
Snowsightでサクッと確認する方法
Snowsightのワークシートで、MERGEを実行する前に重複の有無をチェックしておくと安心です。
SELECT id, COUNT(*) AS cnt
FROM source
GROUP BY id
HAVING COUNT(*) > 1
ORDER BY cnt DESC;
結果が0件なら安心、1件でも出てきたら QUALIFY などで重複排除を組み込みましょう。
よくあるハマりポイント
- ON句のキーが甘い:
ON t.id = s.idだけだとマッチしすぎる場合、複合キー(id + region など)に変える - updated_at が NULL:ORDER BY で NULLが先頭/末尾に来てしまい、意図しない行が残る →
NULLS LASTを明示 - タイムゾーンの違い:updated_atが同値になり順序が不安定 →
ORDER BY updated_at DESC, source_file_name DESCなど2段で並べる
まとめ
「Duplicate row detected」は、Snowflakeが「MERGEの結果が一意に決まらないよ!」と教えてくれている親切なエラーです。対処の鉄則は次の通りです。
- 原因はほぼ100%「ソース側の重複」
- 解決は
QUALIFY ROW_NUMBER()やDISTINCTでの重複排除がベスト - パラメータでエラーを消すのは最終手段
- 事前に
GROUP BY HAVING COUNT(*) > 1でチェックする習慣をつけよう
このエラーをきっかけに「自分のデータパイプラインに重複が混入してないか」を見直すと、データ品質がぐっと上がります。ぜひ前向きにトラブルシューティングしていきましょう!
参考リンク
- MERGE | Snowflake Documentation
- ERROR_ON_NONDETERMINISTIC_MERGE パラメータ
- QUALIFY 句 | Snowflake Documentation
関連記事
- Snowflake「Single-row subquery returns more than one row」エラーの原因と修正方法 – 同じく「1行のはずが複数返る」系エラーの解説
- SnowflakeでCOPY INTOが失敗する原因と解決方法 – MERGE前段のデータロードでつまずいたときの参考に
- Snowflake「Error parsing JSON」の原因とSTRIP_OUTER_ARRAY対処法 – JSONロード時に重複や形式エラーが出たときに
- Snowflake「Numeric value is not recognized」エラー解決 – データ型まわりのエラー対策もあわせて確認しておきたい一本


