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_transformPASSING句を使用して$var3が設定されています。3番目のSET操作では、フィールドbが作成され、その値が変数$var1$var2および$var3の値の合計に設定されます。

代入のRHSには、JSON値(パス式、変数またはリテラルJSON値で表される)を基本算術演算子(+ (加算)、- (減算)、* (乗算)および/ (除算))を使用して結合する計算を含めることもできます。計算をネストまたはグループ化できます。

このコードでは、フィールドbonuscompensationを入力オブジェクトに追加しています。

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の値は、salarybonusの合計と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を想定している(必須とする)操作の場合は、そのパス式で複数の値のシーケンスを生成できます。(一致した単一値は、その単一値のシーケンスと同じように扱われます)。これらの操作は、APPENDPREPENDCOPYMINUSUNIONおよびINTERSECTです。

たとえば、RHSのパス式$.b[0 to 2]では、フィールドbの値である、この配列の1番目から3番目までの要素がシーケンスとして生成されます。

RHSにあるパス式で配列が対象となっている場合は、LHSの配列と組み合せる値(単一)として、その配列全体が使用されます。脚注2

ただし、RHSが配列の要素の一部またはすべてを明示的に対象とする場合、それらの要素は複数の値のシーケンスとして使用されます。これらの値は、対象となる配列全体と単一の操作で結合されます。APPENDPREPENDなど、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のパスで一致した値34が、1つの単位としてまとめられ、LHSで対象となっている配列[1,2]APPEND (追加)された場合、結果は、その配列に要素34が個別に順々に追加された場合と同じになります。結果は、どちらの場合も[1,2,3,4]です。3を追加すると、4は、34をまとめて追加することと同じになり、順番に並べられます。

しかしながら、PREPENDの場合は、34をまとめて先頭に付加すると結果は[3,4,1,2]になり、一方で、先頭に個別に順々に付加すると結果は[4,3,1,2]になります。

PREPENDの動作は次のとおりです: 値34は、その順序で、入力配列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のパスで一致した単一値(この場合は配列)を、その値のシングルトン・シーケンスであるかのように扱う場合のみです。