> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-detect-table-modification.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> JSON Merge Patch のセマンティクス（後勝ち方式）に従って JSON 値を集約します。

# mergedJSONPatch

<h2 id="mergedJSONPatch">
  mergedJSONPatch
</h2>

導入バージョン: v26.8.0

JSON 値を後勝ち (last-write-wins) のセマンティクスでマージして集約し、RFC 7396 JSON Merge Patch の中核となるマージ動作を
パス単位で実装します。

この集約関数は、ステートを三つ組 (key, value, sorting\_key) として保持します。各キー (JSON パス) については、sorting\_key に基づく最新の有効なレコードのみが保持されます。`JSON` 型が動的なスカラーのリーフとして格納するパスでは、オブジェクトの書き込みは子孫パスへフラット化されます。祖先パスへのオブジェクト以外の書き込みは、競合する子孫パスをシャドウ (上書き) します。

明示的に型が宣言されたパス (`JSON(a Map(...))`、`JSON(a Tuple(...))`、
`JSON(a Variant(...))`、`JSON(a Dynamic)` などで宣言されたもの) は、すべてアトミックな値として扱われます。つまり、パスの値全体が
ディープマージされることはなく、新しいパッチの値で丸ごと置き換えられます。RFC 7396 のディープマージのセマンティクスに従うのは、
型が宣言されていない (動的な) スカラーパスのみです。

sort\_key は、各 JSON パスについてどの値が採用されるかを決定します。sort\_key が最大の行が
保持されます。競合する 2 つのパッチのソートキーが等しい場合、結果は処理順序に依存し、後から
処理されたパッチが優先されます。同値の場合の優先順位を決定論的に定めるために `ORDER BY` を当てにしないでください。

制限事項 (`ColumnObject` から継承) ：

1. null による削除: パッチ `{"key": null}` ではキーは削除されません。`ColumnObject` は挿入時に
   値が null のメンバーを破棄するため、この関数は "キーが存在しない" 場合と
   "キーの値が null である" 場合を区別できません。

2. 空オブジェクトによる置換: パッチ `{"a": {}}` では、パス `a` にある古いスカラー値や配列を
   置き換えることはできません。`ColumnObject` は値が空オブジェクト `{}` のパスを暗黙的に破棄するため、
   新しいパッチは何の効果も持たず、古い値がそのまま残ります。

3. 非 Nullable な型付きパスの欠落: `JSON` カラムで非 Nullable 型の型付きパスを宣言している場合
   (例: `JSON(a UInt32)`)、`a` を省略した行はその型のデフォルト値 (例: `0`) で
   保存されます。集約関数は "存在しない" 場合と "デフォルト値が明示的に
   書き込まれた" 場合を区別できないため、`a` を省略した新しいパッチによって、古い
   0 以外の値が暗黙的に消去されてしまいます。これを避けるには、型付きパスを `Nullable` として宣言してください
   (例: `JSON(a Nullable(UInt32))`)。Nullable な型付きパスの null は
   "パスが存在しない" ものとして扱われ、正しくスキップされます。

4. 型付きパスはすべてアトミック: すべての型付きパス (`Map(K,V)`、`JSON`、`Dynamic`、`Tuple(…)`、
   `Variant(…)`、`Array(…)`、その他宣言された任意の型) は単一の値として保存されます。
   集約関数はその内容をディープマージせず、値全体をアトミックに置き換えます。
   パス単位でディープマージされるのは、動的な (型指定のないスカラー) パスのみです。

5. キー内のドットによる曖昧さ: `JSON` 型では、`{"a":{"b":1}}` と `{"a.b":1}` がどちらも
   同じ内部パス `a.b` で表現されます。そのため、1 つの行で `a` と `a.b` の両方が
   独立したピアとして現れることがあります。新しいパッチが `a` のみを書き込むと、祖先/子孫間の競合
   ルールによって `a.b` が消去され、`a.b` のみを書き込むと、同じルールによって `a` が消去されます。これを避けるには、
   `json_type_escape_dots_in_keys = 1` を設定してください。この設定を有効にすると、JSON キー内のリテラルのドットは
   パーセントエンコードされ (例: `a.b` は `a%2Eb` になります)、ネストされた
   パスと区別されるため、誤った競合が発生しなくなります。

**構文**

```sql theme={null}
mergedJSONPatch(json, sort_key)
```

**引数**

* `json` — 集約対象の JSON カラム。[`JSON`](/ja/reference/data-types/newjson)
* `sort_key` — パスごとにどの書き込みを採用するかを決定する、比較可能なカラム。sort\_key の値が最大の行が保持されます。

**戻り値**

入力されたすべての JSON オブジェクトをマージした結果を、単一の JSON オブジェクトとして返します。 [`JSON`](/ja/reference/data-types/newjson)

**例**

**ソートキーを使用した基本的な使い方**

```sql title=Query theme={null}
SELECT mergedJSONPatch(json, sort_key) FROM
(
    SELECT '{"a":1}'::JSON AS json, 1 AS sort_key
    UNION ALL
    SELECT '{"b":2}'::JSON, 2
    UNION ALL
    SELECT '{"a":3, "c":4}'::JSON, 3
);
```

```response title=Response theme={null}
┌─mergedJSONPatch(json, sort_key)─┐
│ {"a":3,"b":2,"c":4}             │
└─────────────────────────────────┘
```
