mergedJSONPatch
Introduit dans : v26.8.0 Agrège des valeurs JSON en les fusionnant selon une sémantique « last-write-wins » (la dernière écriture l’emporte), en implémentant au niveau du path le comportement de fusion de base de la RFC 7396 JSON Merge Patch. La fonction d’agrégation stocke son état sous forme de triplets (key, value, sorting_key), où chaque clé (chemin JSON) ne conserve que le dernier enregistrement effectif selon sorting_key. Les écritures d’objets sont aplaties en chemins descendants pour les chemins que le typeJSON stocke comme feuilles scalaires dynamiques. Les écritures
autres que des objets sur un ancêtre masquent les descendants en conflit.
Chaque chemin explicitement typé (déclaré avec JSON(a Map(...)), JSON(a Tuple(...)),
JSON(a Variant(...)), JSON(a Dynamic), etc.) est traité comme une valeur atomique : la valeur du chemin est intégralement
remplacée par le patch le plus récent au lieu d’être fusionnée en profondeur. Seuls les chemins scalaires non typés (dynamiques) suivent
la sémantique de fusion profonde de la RFC 7396.
Le sort_key détermine quelle valeur l’emporte pour chaque chemin JSON. La ligne ayant le sort_key le plus élevé est
conservée. Si deux patchs en conflit ont des clés de tri identiques, le résultat dépend de l’ordre : le patch
traité en dernier l’emporte. Ne comptez pas sur ORDER BY pour départager les égalités de manière déterministe.
LIMITATIONS (héritées de ColumnObject)\u00a0:
-
Suppression par null : un patch
{"key": null}ne supprime pas la clé.ColumnObjectsupprime les membres de valeur null lors de l’insertion ; la fonction ne peut donc pas distinguer “clé absente” de “clé à null”. -
Remplacement par un objet vide : un patch
{"a": {}}ne peut pas remplacer une ancienne valeur scalaire ou un ancien tableau au chemina.ColumnObjectsupprime silencieusement les chemins dont la valeur est un objet vide{}; le patch le plus récent n’apporte donc rien et l’ancienne valeur est conservée. -
Absence d’un chemin typé non Nullable : lorsqu’une colonne
JSONdéclare un chemin typé avec un type non nullable (par exemple,JSON(a UInt32)), une ligne qui ometaest stockée avec la valeur par défaut du type (par exemple,0). L’agrégat ne peut pas distinguer “absent” de “explicitement écrit avec la valeur par défaut” : un patch plus récent qui ometaefface donc silencieusement une ancienne valeur non nulle. Pour éviter cela, déclarez les chemins typés commeNullable(par exemple,JSON(a Nullable(UInt32))). Un null dans un chemin typé nullable est traité comme “chemin absent” et correctement ignoré. -
Tous les chemins typés sont atomiques : chaque chemin typé (
Map(K,V),JSON,Dynamic,Tuple(…),Variant(…),Array(…)ou tout autre type déclaré) est stocké sous forme de valeur unique. L’agrégat remplace la valeur entière de manière atomique au lieu de fusionner son contenu en profondeur. Seuls les chemins dynamiques (non typés, scalaires) sont fusionnés en profondeur, chemin par chemin. -
Ambiguïté des points dans les clés : le type
JSONreprésente{"a":{"b":1}}et{"a.b":1}avec le même chemin internea.b. Une même ligne peut donc exposer à la foisaeta.bcomme des chemins homologues indépendants. Lorsqu’un patch plus récent écrit uniquementa, la règle de conflit ancêtre/descendant effacea.b; lorsqu’il écrit uniquementa.b, la même règle effacea. Pour éviter cela, définissezjson_type_escape_dots_in_keys = 1. Avec ce paramètre, les points littéraux dans les clés JSON sont encodés en pourcentage (par exemple,a.bdevienta%2Eb), ce qui les distingue des chemins imbriqués et élimine le faux conflit.
json— Colonne JSON à agréger.JSONsort_key— Colonne comparable qui détermine quelle écriture l’emporte pour chaque path. La ligne dont la valeur de sort_key est la plus élevée est conservée.
JSON
Exemples
Utilisation de base avec une clé de tri
Query
Response