22.4 JSON_TABLEとJSON配列の使用
JSON値は、1つの配列にすることも、1つ以上の配列を含めることも可能であり、他のJSON配列またはオブジェクト内の任意の数のレベルにネストしてもかまいません。NESTED PATH
句にjson_table
を使用すると、配列の特定の要素を投影できます。
例22-6では、JSONデータ内の要求者および関連する電話番号を列data
内に投影します。JSON配列Phone
全体がJSONデータph_arr
の列として投影されています。このJSONデータをVARCHAR2
列としてフォーマットするには、JSONデータがJSON
データ型ではない場合、キーワードFORMAT JSON
が必要となります(型がJSON
データの場合、このキーワードはエラーになります)。
JSON配列Phone
全体ではなく、配列の個別要素のみを投影する場合はどうすればよいでしょうか。例22-7は、これを行う方法の1つを示しています。この方法は、投影する必要があるデータが配列要素のみである場合に使用できます。
要求者および関連する電話データの両方を投影する場合、例22-7の行パス式($.Phone[*]
)は適切ではありません。この式は、配列Phone
の(電話オブジェクト)要素のみを対象としています。
例22-8は、両方を対象にする方法の1つを示しています。ここでは、名前と電話配列全体の両方を対象にする行パス式を使用するとともに、個別電話オブジェクトのフィールドtype
およびnumber
を対象にする列パス式を使用しています。
例22-8では例22-6のように、JSONデータがJSON
データ型でない場合にはキーワードFORMAT JSON
が必要になります。これは、結果のVARCHAR2
列にJSONデータ(つまり、電話ごとに1つの配列要素という形式の電話の種類または電話番号の配列)が含まれるためです。また、例22-6の事例とは異なり、列phone_type
およびphone_num
にはラッパー句が必要になりますが、これは、配列Phone
にフィールドtype
およびnumber
を持つオブジェクトが複数含まれるためです。
場合によっては、例22-8の効果が必要ないことがあります。たとえば、電話番号のJSON配列が含まれる列(特定の発注書のすべての番号に対して1つの行)ではなく、単一の電話番号が含まれるリレーショナル列(番号当たり1つの行)が必要な場合があります。
この結果を得るために、配列に対してjson_table
のNESTED
パス句を使用することにより、配列要素を投影するようjson_table
に命令を出す必要があります。NESTED
パス句は実質的に、追加の行ソース(行パターン)として機能します。例22-9に、これを示します。
キーワードNESTED
は1回のjson_table
の呼出しで何回でも使用できます。
例22-9では、外部のCOLUMNS
句は、ネストした(内部の) COLUMNS
句の親になります。定義されている仮想表は外部結合を使用して結合されますが、この場合、親句によって定義される表が結合における外部表になります。
(同じ親の下で直接ネストされた2番目の列の句がある場合、これら2つのネストした句は兄弟のCOLUMNS
句になります。)
例22-6 JSON配列全体のJSONデータとしての投影
SELECT jt.*
FROM j_purchaseorder,
json_table(data, '$'
COLUMNS (requestor VARCHAR2(32 CHAR) PATH '$.Requestor',
ph_arr VARCHAR2(100 CHAR) FORMAT JSON
PATH '$.ShippingInstructions.Phone')
) AS "JT";
例22-7 JSON配列の要素の投影
SELECT jt.*
FROM j_purchaseorder,
json_table(data, '$.ShippingInstructions.Phone[*]'
COLUMNS (phone_type VARCHAR2(10) PATH '$.type',
phone_num VARCHAR2(20) PATH '$.number')) AS "JT";
PHONE_TYPE PHONE_NUM
---------- ---------
Office 909-555-7307
Mobile 415-555-1234
例22-8 JSON配列の要素と他のデータの投影
SELECT jt.*
FROM j_purchaseorder,
json_table(data, '$'
COLUMNS (
requestor VARCHAR2(32 CHAR) PATH '$.Requestor',
phone_type VARCHAR2(50 CHAR) FORMAT JSON WITH WRAPPER
PATH '$.ShippingInstructions.Phone[*].type',
phone_num VARCHAR2(50 CHAR) FORMAT JSON WITH WRAPPER
PATH '$.ShippingInstructions.Phone[*].number')) AS "JT";
REQUESTOR PHONE_TYPE PHONE_NUM
--------- ---------- ---------
Alexis Bull ["Office", "Mobile"] ["909-555-7307", "415-555-1234"]
例22-9 JSON_TABLE: NESTEDを使用した配列要素の投影
この例では、配列要素を投影する2つの等価の問合せを示しています。最初の問合せでは、行および列データを対象とする式に単純なドット表記法構文を使用します。2番目の問合せでは、完全な構文を使用します。
SQL識別子が引用符で囲まれている列number
を除いて("number"
)、実際のSQL列名は大文字です。(列number
は小文字です。)
最初の問合せでは、列名の記述は、大/小文字の区別を含め、対象となるフィールド前と完全に同じです。引用符で囲まれるかどうかに関係なく、これらは、適切なパスを設定するために大/小文字を区別して解釈されます。
2番目の問合せには次のものが含まれています。
-
JSON列式およびSQL/JSON行パス式の別々の引数
-
VARCHAR2(4000)
の明示的な列データ型 -
投影されるオブジェクト・フィールドを対象とするための、明示的な
PATH
句およびSQL/JSON列パス式
SELECT jt.*
FROM j_purchaseorder po,
json_table(po.data
COLUMNS (Requestor,
NESTED ShippingInstructions.Phone[*]
COLUMNS (type, "number"))) AS "JT";
SELECT jt.*
FROM j_purchaseorder po,
json_table(po.data, '$'
COLUMNS (Requestor VARCHAR2(4000) PATH '$.Requestor',
NESTED
PATH '$.ShippingInstructions.Phone[*]'
COLUMNS (type VARCHAR2(4000) PATH '$.type',
"number" VARCHAR2(4000) PATH '$.number'))
) AS "JT";