Snowflake「Duplicate row detected」エラーの原因とMERGE文での対処方法

SnowflakeのMERGE文実行時に発生する「Duplicate row detected during DML action」エラー画面と原因・対処方法の解説イメージ Snowflake
この記事をシェアする𝕏B!FacebookLINEPocket

はじめに:MERGE文を書いたら謎のエラーが出た!

Snowflakeで「UPSERT(あれば更新、なければ挿入)」を実現するために MERGE 文を書いたことはありますか?便利な構文なのですが、いざ実行すると次のようなエラーに遭遇することがあります。

100090 (42P18): Duplicate row detected during DML action
Row Values: [123, 'Alice', '2026-05-01']

「えっ、重複って何?テーブルにユニーク制約も付けてないのに……」と戸惑った方も多いはず。実はこのエラー、Snowflake特有の「MERGEの安全装置」が働いた合図なのです。この記事では、なぜこのエラーが出るのか、そしてどう直せばいいのかを、初心者の方にもわかりやすく解説していきます!

Snowflakeで発生する「Duplicate row detected during DML action」エラーとMERGE文の安全装置を示すアイキャッチ図解。重複行検出の仕組みとUPDATE/INSERT処理時の対処方法を初心者向けに整理したビジュアル

そもそも 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
図解イメージ。SnowflakeのMERGE文で発生するDuplicate row detectedエラー対策として、QUALIFY ROW_NUMBERやSELECT DISTINCTでソース側の重複を事前に排除し、idごとに最新のupdated_atを1行だけ残す方針を示すイラスト

対処法その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 でチェックする習慣をつけよう

このエラーをきっかけに「自分のデータパイプラインに重複が混入してないか」を見直すと、データ品質がぐっと上がります。ぜひ前向きにトラブルシューティングしていきましょう!

参考リンク

関連記事

この記事をシェアする𝕏B!FacebookLINEPocket