13.21 JSON_TRANSFORMの右辺(RHS)のパス式
json_transform
の右辺(RHS)のパス式は、その他の場所で使用できるパス式よりも一般的です。その構文と動作について詳しく説明します。
ノート:
このトピックでは、SQL/JSONパス式である場合の、json_transform
代入操作のRHSについて詳しく説明します。このトピックを読む前に、トピック「JSON_TRANSFORM操作(代入など)」をお読みください。
ノート:
代入のRHS (右辺)は、次のいずれかです:
-
SQL式 — その値が使用されます。例13-37を参照してください。
-
キーワード
PATH
の後に、一重引用符('
)で囲まれたSQL/JSONパス式が続きます。脚注1 その対象となっているデータが、使用される値です。
json_transform
操作の結果は、必ずJSONデータです。RHSがSQL式である場合、その値は、「SQL/JSON生成関数の入力値の処理」で示すように、暗黙的にJSON値に変換されます。
最も単純なのは、RHSのパス式で1つのフィールドが対象となっているケースです。次のコードでは、フィールドb
を入力オブジェクト{"a":[ 1,2,3 ]}
に追加し、b
の値を要素フィールドa
の合計に設定します。
SELECT json_transform('{"a":[ 1,2,3 ]}',
SET '$.b' = PATH '$.a[*].sum()');
結果 — 変更された入力データ:
{"a":[ 1,2,3 ], "b":6}
json_transform
のRHSのパス式には、通常は、JSONデータに対して作用するその他のSQLファンクションで使用されるパス式の構文とセマンティクスがあります。これには、SQL/JSON変数の使用を含めることができます。次に例を示します:
SELECT json_transform('{"a":1}',
SET '$var1' = 2,
SET '$var2' = PATH '$.a',
SET '$.b' = PATH '$var1 + $var2 + $var3'
PASSING 5 AS "var3");
結果 — 変更された入力データ:
{"a":1, b:8}
このコードでは、json_transform
の最初のSET
操作で変数$var1
が設定され、2番目のSET
操作で$var2
が設定され、json_transform
のPASSING
句を使用して$var3
が設定されています。3番目のSET
操作では、フィールドb
が作成され、その値が変数$var1
、$var2
および$var3
の値の合計に設定されます。
代入のRHSには、JSON値(パス式、変数またはリテラルJSON値で表される)を基本算術演算子(+
(加算)、-
(減算)、*
(乗算)および/
(除算))を使用して結合する計算を含めることもできます。計算をネストまたはグループ化できます。
このコードでは、フィールドbonus
とcompensation
を入力オブジェクトに追加しています。
SELECT json_transform('{"salary":1000, "commission":150}',
SET '$.bonus' = PATH '$.salary * $bonusFactor',
SET '$.compensation' = PATH '($.salary + $.bonus)
+ $.commission'
PASSING 0.05 AS "bonusFactor");
結果 — 変更された入力データ:
{"salary":1000, "commission":150, "bonus":50, "compensation":1200}
bonus
は給与とボーナス係数の積として算出され、その値は変数$bonusFactor
として渡されます。compensation
の値は、salary
とbonus
の合計とcommission
の積として算出されます。
計算は述語では許可されていません — 次のコードではエラーが発生します:
SET'$.c' = PATH '$.a?( @.x == (@.y + 4) ).b - 2'
次の例では、ネストしたパスを使用して、配列内のすべての要素を反復処理しています。これは、各要素の価格を算出し、それを変数$priceVar
(ゼロに初期化されている)の値に追加しています。末尾(ネストしたパスの外側)に、フィールドtotalPrice
を作成し、それに変数$priceVar
の値が与えられています。
SELECT json_transform('{"items":[ {"quantity":2, "unitPrice":3},
{"quantity":2, "unitPrice":7} ]}',
SET '$priceVar' = PATH '0.00',
NESTED PATH '$.items[*]'
(SET '$priceVar' =
PATH '$priceVar + (@.unitPrice * @.quantity)'),
SET '$.totalPrice' = PATH '$priceVar');
結果 — 変更された入力データ:
{"items":[ {"quantity":2, "unitPrice":3},
{"quantity":2, "unitPrice":7} ],
"totalPrice":20}
(ここでの最初のRHSは、PATH '0.00'
ではなくSQL式(リテラル) 0.00
であっても同様です。その場合は、SQL数値0.00
が暗黙的にJSON数値0.00
として解釈されます。)
このアットマーク(@
)文字は、最も内側のNESTED PATH
コンテキストによって定義されている現在のノードを示しています。RHSにある$
は、最上位コンテキストの現在のノードを示しています。内側のNESTED PATH
コンテキストが存在しない場合、@
は、RHSのパス式での$
と同じです。「JSON_TRANSFORMの演算子NESTED PATH」を参照してください。
次の例では、配列値変数$var
を使用して、その要素を順番に、JackとJillのtravelの入力approval
配列に追加します。これは、コンストラクタJSON
を使用して、SQL文字列'[ 2025, 2026 ]'
を解析し、JSON配列[ 2025, 2026 ]
を返しています。
SELECT json_transform('{travel:[ {"name":"Jack", "approval":[ 2023, 2024 ]},
{"name":"Jill", "approval":[ 2024 ]} ]}',
SET '$var' = JSON('[ 2025,2026 ]'),
APPEND '$.travel.approval' = PATH '$var[*]');
結果 — 変更された入力データ:
{"travel":[ {"name":"Jack", "approval":[ 2023, 2024, 2025, 2026 ]},
{"name":"Jill", "approval":[ 2024, 2025, 2026 ]} ]}
(APPEND
に渡されたパスが$var[*]
ではなく$var
のみだった場合、結果は、入力approval配列に要素[ 2025, 2026 ]
が追加されたものになります。Jillのapproval値は[ 2024, [ 2025, 2026 ] ]
になり、目的とする値ではありません。)
ほとんどの操作では、RHSのパス式で、単一のJSON値が対象となっている必要があります。ただし、そのような単一値は、複数の値を集計した結果($.a[*].sum()
など)にすることもできます。
配列が対象となっている、RHSのパス式を受け入れるLHSを想定している(必須とする)操作の場合は、そのパス式で複数の値のシーケンスを生成できます。(一致した単一値は、その単一値のシーケンスと同じように扱われます)。これらの操作は、APPEND
、PREPEND
、COPY
、MINUS
、UNION
およびINTERSECT
です。
たとえば、RHSのパス式$.b[0 to 2]
では、フィールドb
の値である、この配列の1番目から3番目までの要素がシーケンスとして生成されます。
RHSにあるパス式で配列が対象となっている場合は、LHSの配列と組み合せる値(単一)として、その配列全体が使用されます。脚注2
ただし、RHSが配列の要素の一部またはすべてを明示的に対象とする場合、それらの要素は複数の値のシーケンスとして使用されます。これらの値は、対象となる配列全体と単一の操作で結合されます。APPEND
やPREPEND
など、RHSシーケンス値をLHS配列に追加する操作では、結果として得られる配列にシーケンス値の順序が保持されます。
たとえば、配列a
の値が[30,20]
で、配列b
の値が[2,4,6,8]
であるとします。
-
この操作は、配列
b
を、単一の要素としてa
の先頭に付加しています:PREPEND '$.a' = PATH '$.b'
配列
a
が値[[2,4,6,8],30,20]
に設定されます。 -
この操作は、配列
b
の2番目と4番目の要素を配列a
に付加します。PREPEND '$.a' = PATH '$.b[2,4]'
RHSパス式に一致する複数の値は、配列
a
togetherの前に付加され、個別には付加されません(1つの動作ですべての先頭に付加されます)。したがって、シーケンスの順序は結果の配列に反映されます。配列a
は、[4,8,30,20]
に設定されます。[8,4,30,20]
ではありません。 -
この操作は、配列
b
のすべての要素を配列a
にまとめて付加します。PREPEND '$.a' = PATH '$.b[*]'
配列
a
が[[2,4,6,8],30,20]
に設定されます。
ノート:
PREPEND
およびINTERSECT
は、RHSパス式に一致する複数の値が個別に処理されるのではなく、ブロックとして完全に処理されることが本当に重要な唯一のLHS配列対象操作です。
たとえば、RHSのパスで一致した値3
と4
が、1つの単位としてまとめられ、LHSで対象となっている配列[1,2]
にAPPEND
(追加)された場合、結果は、その配列に要素3
と4
が個別に順々に追加された場合と同じになります。結果は、どちらの場合も[1,2,3,4]
です。3
を追加すると、4
は、3
と4
をまとめて追加することと同じになり、順番に並べられます。
しかしながら、PREPEND
の場合は、3
と4
をまとめて先頭に付加すると結果は[3,4,1,2]
になり、一方で、先頭に個別に順々に付加すると結果は[4,3,1,2]
になります。
PREPEND
の動作は次のとおりです: 値3
と4
は、その順序で、入力配列a
([ 1,2 ]
)の先頭にまとめて付加されます。
SELECT json_transform('{"a":[ 1,2 ], b:[ {c:3}, {c:4} ]}',
PREPEND '$.a' = PATH '$.b[*].c')
結果:
{"a":[ 3,4,1,2 ], "b":[ {"c":3}, {"c":4} ]}}
UNION
と比較すると、INTERSECT
には同じ考慮事項があります。複数のRHS値(少なくとも、異なる2つの値がある)がINTERSECT
によって個別に処理された場合、結果は必ず、空の配列[]
になります。実際には、シーケンス内の最初の値を処理した後、結果の交差はその値を持つ単一の配列になります。シーケンス内の次の値を処理すると、結果は空の論理積になります。
たとえば、[1,2,3,4]
に対して、複数の値を個別に指定して(3
、次に4
)論理積を実行すると、まず[3]
が生成され(3
を除くすべてが削除される)、次に[]
が生成されます(4
を除くすべてが削除される)。
関連トピック
脚注の凡例
脚注1: RHSにSQL式とパス式が両方含まれている場合は、エラーが発生します。脚注2: これは、実際には、RHSのパスで一致した単一値(この場合は配列)を、その値のシングルトン・シーケンスであるかのように扱う場合のみです。