SQL> SELECT JSON_VALUE(j.data,'$.a.b.c[0].d[1][0]') FROM json_data j;
JSON_VALUE(J.DATA,'$.A.B.C[0].D[1][0]')
--------------------------------------------------------------------------------
Slicing - JMESPath Tutorial
Slicing - JMESPath Tutorial
スライスは、配列のインデックス値の範囲を指定して、配列の一部を取得する操作です。
JMESPathパス式では、配列のインデックス値の範囲は、[0:4]のように指定します。
"k" :
↓[0:5]
データを準備します。すでに確認したように、Oracle Database JSONのドット表記法ではトップレベルが配列であるJSONから要素を得ることはできないようなので、トップレベルをオブジェクトにし、その中に配列を入れています。
SQL> UPDATE json_data SET data ='{"k": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}';
1 row updated.
パス表記法: インデックス値の範囲指定は [0:4]ではなく [0 to 4]ですが、うまくスライスできています。
SQL> SELECT j.data.k[0 to 4] FROM json_data j;
--------------------------------------------------------------------------------
[0,1,2,3,4]
次にJSON_xxxファンクションを試しますが、返される値がスカラー値ではないため、JSON_VALUEは使えません。代わりにJSON_QUERYを使用します。
パス表記法のときと同様に、インデックス値の範囲指定は [0:4]ではなく [0 to 4]で指定します。
ただし、以下のようにJSON_QUERYの引数にデータとパス式のみを指定すると、値が得られません。
SQL> SELECT JSON_QUERY(j.data, '$.k[0 to 4]') FROM json_data j;
JSON_QUERY(J.DATA,'$.K[0TO4]')
--------------------------------------------------------------------------------
その理由は、 ERROR ON ERRORを指定するとわかります。
SQL> SELECT JSON_QUERY(j.data, '$.k[0 to 4]' ERROR ON ERROR) FROM json_data j;
SELECT JSON_QUERY(j.data, '$.k[0 to 4]' ERROR ON ERROR) FROM json_data j
ERROR at line 1:
ORA-40480: result cannot be returned without array wrapper
エラーメッセージの通り、返される値が複数の場合には、配列ラッパーを指定して、複数の値を配列に変換する必要があります。
JSON_QUERY()にWITH CONDITIONAL WRAPPERを指定して、配列ラッパーを適用すると、返される複数の値を配列化した値が得られます。
SQL> SELECT JSON_QUERY(j.data, '$.k[0 to 4]' WITH CONDITIONAL WRAPPER ERROR ON ERROR) FROM json_data j;
JSON_QUERY(J.DATA,'$.K[0TO4]'WITHCONDITIONALWRAPPERERRORONERROR)
--------------------------------------------------------------------------------
[0,1,2,3,4]
別のパターンのスライス
開始インデックス値、終了インデックス値を変えたパターンですが、パス表記法、JSON_QUERY+パス式の両方で処理できます。
SQL> SELECT j.data.k[5 to 9] FROM json_data j;
--------------------------------------------------------------------------------
[5,6,7,8,9]
SQL> SELECT JSON_QUERY(j.data, '$.k[5 to 9]' WITH CONDITIONAL WRAPPER ERROR ON ERROR) FROM json_data j;
JSON_QUERY(J.DATA,'$.K[5TO9]'WITHCONDITIONALWRAPPERERRORONERROR)
--------------------------------------------------------------------------------
[5,6,7,8,9]
開始インデックス値を省略したスライス
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
│[:5]
[0, 1, 2, 3, 4]
Oracle Database JSONでは、スライスで開始インデックス値を省略できません。
SQL> SELECT j.data.k[ to 4] FROM json_data j;
SELECT j.data.k[ to 4] FROM json_data j
ERROR at line 1:
ORA-00900: invalid SQL statement
開始インデックス値は明示的に指定する必要があるようです。先頭のインデックス値として、0を指定すれば、想定した値が得られます。
SQL> SELECT j.data.k[0 to 4] FROM json_data j;
--------------------------------------------------------------------------------
[0,1,2,3,4]
SQL> SELECT JSON_QUERY(j.data, '$.k[0 to 4]' WITH CONDITIONAL WRAPPER) FROM json_data j;
JSON_QUERY(J.DATA,'$.K[0TO4]'WITHCONDITIONALWRAPPER)
--------------------------------------------------------------------------------
[0,1,2,3,4]
Projections - JMESPath Tutorial
JMESPATHのプロジェクションは、複数のデータ(コレクション)を内包するJSONを、「串刺し」するようにして配列データを得る操作です。
List and Slice Projections
List and Slice Projections - JMESPath Tutorial
List Projections
List Projectionsは、配列を対象にしたプロジェクションです。
"people" :
"first" : "James",←★
"last" : "d"
"first" : "Jacob",←★
"last" : "e"
"first" : "Jayden",←★
"last" : "f"
"missing" : "different"
"foo" :
"bar" : "baz"
│people[*].first
"James",
"Jacob",
"Jayden"
データを準備します。
SQL> UPDATE json_data SET data ='
3 "people": [
4 {"first": "James", "last": "d"},
5 {"first": "Jacob", "last": "e"},
6 {"first": "Jayden", "last": "f"},
7 {"missing": "different"}
8 ],
9 "foo": {"bar": "baz"}
10 }
11 ';
1 row updated.
ドット表記法ではList Projectionが可能です。
SQL> SELECT d.data.people[*].first FROM json_documents d;
PEOPLE
--------------------------------------------------------------------------------
["James","Jacob","Jayden"]
JSON_QUERY()ファンクション+パス式でもList Projectionが可能です。ただし、WITH CONDITIONAL WRAPPER の指定が必要です。
SQL> SELECT JSON_QUERY(j.data, '$.people[*].first' WITH CONDITIONAL WRAPPER ERROR ON ERROR ) FROM json_data j;
JSON_QUERY(J.DATA,'$.PEOPLE[*].FIRST'WITHCONDITIONALWRAPPERERRORONERROR)
--------------------------------------------------------------------------------
["James","Jacob","Jayden"]
WITH CONDITIONAL WRAPPER を指定しないとエラーになります。
SQL> SELECT JSON_QUERY(j.data, '$.people[*].first' ERROR ON ERROR ) FROM json_data j;
SELECT JSON_QUERY(j.data, '$.people[*].first' ERROR ON ERROR ) FROM json_data j
ERROR at line 1:
ORA-40480: result cannot be returned without array wrapper
Oracle SQL関数JSON_QUERYおよびJSON_TABLEのラッパー句
Slice Projections
スライスプロジェクションは、配列を対象にし、スライスするプロジェクションです。
(JMESPath Tutorialの例が良くないので、スライスのインデックス値を変えています)
"people" :
"first" : "James",←★
"last" : "d"
"first" : "Jacob",←★
"last" : "e"
"first" : "Jayden",
"last" : "f"
"missing" : "different"
"foo" :
"bar" : "baz"
│people[:2].first
"James",
"Jacob"
データを準備します。
SQL> UPDATE json_data SET data ='
3 "people": [
4 {"first": "James", "last": "d"},
5 {"first": "Jacob", "last": "e"},
6 {"first": "Jayden", "last": "f"},
7 {"missing": "different"}
8 ],
9 "foo": {"bar": "baz"}
10 }
11 ';
1 row updated.
ドット表記法でも処理可能です。配列範囲の終了インデックス値が-1となることに気をつけてください。
SQL> SELECT j.data.people[0 to 1].first FROM json_data j;
PEOPLE
--------------------------------------------------------------------------------
["James","Jacob"]
JSON_QUERYファンクション+パス式でも同様に処理可能です。
SQL> SELECT JSON_QUERY(j.data, '$.people[0 to 1].first' WITH CONDITIONAL WRAPPER ERROR ON ERROR) FROM json_data j;
JSON_QUERY(J.DATA,'$.PEOPLE[0TO1].FIRST'WITHCONDITIONALWRAPPERERRORONERROR)
--------------------------------------------------------------------------------
["James","Jacob"]
なお、ドット表記法において、返される要素数が1つになるようにインデックス値を変えると、返されるデータの型が配列ではなくなります。
SQL> SELECT j.data.people[0 to 0].first FROM json_data j;
PEOPLE
--------------------------------------------------------------------------------
James
SQL> SELECT j.data.people[0].first FROM json_data j;
PEOPLE
--------------------------------------------------------------------------------
James
返される要素数に応じて、返される型が変わるのはドット表記法独特の動作です。詳細は以下を参照してください。
JSONデータに対する単純なドット表記法アクセス - OracleR Database JSON開発者ガイド 12c リリース2 (12.2) E85247-02
なお、WITH CONDITIONAL WRAPPERを指定したJSON_QUERYでは、返される要素数が1でも配列として返されます。
SQL> SELECT JSON_QUERY(j.data, '$.people[0 to 0].first' WITH CONDITIONAL WRAPPER ERROR ON ERROR) FROM json_data j;
JSON_QUERY(J.DATA,'$.PEOPLE[0TO0].FIRST'WITHCONDITIONALWRAPPERERRORONERROR)
--------------------------------------------------------------------------------
["James"]
SQL> SELECT JSON_QUERY(j.data, '$.people[0].first' WITH CONDITIONAL WRAPPER ERROR ON ERROR) FROM json_data j;
JSON_QUERY(J.DATA,'$.PEOPLE[0].FIRST'WITHCONDITIONALWRAPPERERRORONERROR)
--------------------------------------------------------------------------------
["James"]
Object Projections
Object Projections - JMESPath Tutorial
Object Projectionsは、オブジェクトを対象にするプロジェクションです。
"ops" :
"functionA" :
"numArgs" : 2←★
"functionB" :
"numArgs" : 3←★
"functionC" :
"variadic" : true
│ops.*.numArgs
データを準備します。
SQL> UPDATE json_data SET data ='
3 "ops": {
4 "functionA": {"numArgs": 2},
5 "functionB": {"numArgs": 3},
6 "functionC": {"variadic": true}
7 }
9 ';
1 row updated.
ドット表記法では、キー箇所に'*'を指定できないため、Object Projectionができません。
SQL> SELECT j.data.ops.*.numArgs FROM json_data j;
SELECT j.data.ops.*.numArgs FROM json_data j
ERROR at line 1:
ORA-01747: invalid user.table.column, table.column, or column specification
JSON_QUERYファンクション+パス式では、キー箇所に'*'を指定でき、Object Projectionを実行できます。
SQL> SELECT JSON_QUERY(j.data, '$.ops.*.numArgs' WITH CONDITIONAL WRAPPER ) FROM json_data j;
JSON_QUERY(J.DATA,'$.OPS.*.NUMARGS'WITHCONDITIONALWRAPPER)
--------------------------------------------------------------------------------
[2,3]
Flatten Projections - JMESPath Tutorial
Flatten Projections - JMESPath Tutorial
フラット化プロジェクションは、プロジェクション結果が配列の入れ子になっている場合、それをフラットにするプロジェクションです。
Oracle Database JSONでは相当する機能が無いようです。
Pipe Expressions - JMESPath Tutorial
Pipe Expressions - JMESPath Tutorial
パイプ相当の処理は、複数回JSON_xxxファンクションを適用することで一応実現できます(読みづらいですが)。
SQL> SELECT JSON_VALUE(JSON_QUERY(j.data, '$.people[*].first' WITH CONDITIONAL WRAPPER ERROR ON ERROR ), '$[0]' ERROR ON ERROR ) FROM json_data j;
JSON_VALUE(JSON_QUERY(J.DATA,'$.PEOPLE[*].FIRST'WITHCONDITIONALWRAPPERERRORONERR
--------------------------------------------------------------------------------
James
MultiSelect - JMESPath Tutorial
JMESPATHのマルチセレクトは、JSON結果から、配列やオブジェクトを生成する処理です。
"people": [
"name": "a",
"state": {"name": "up"}
"name": "b",
"state": {"name": "down"}
"name": "c",
"state": {"name": "up"}
を入力にして、people[].[name, state.name] というパス式を指定することで、以下のように配列の配列が得られます。
│ people[].[name, state.name]
[ "a", "up" ],
[ "b", "down" ],
[ "c", "up" ]
また、people[].{Name: name, State: state.name} というパス式を指定することで、以下のようにオブジェクトの配列が得られます。
│ people[].{Name: name, State: state.name}
{ "Name": "a", "State": "up" },
{ "Name": "b", "State": "down" },
{ "Name": "c", "State": "up" }
このようにJMESPATHのマルチセレクトは、JSONの構造(形式)を変換するときに有用です。
また、変換における配列生成、オブジェクト生成の処理をパス式に組み込む形で記述できるため、非常にスマートに指定できます。
なお、Oracle Database JSONでは、JSONデータの生成はファンクションとして提供されており、パス式に組み込むことができないため、
JMESPATHのマルチセレクト類似の処理は実現できません。
ただ、そもそも、Oracle Databaseにおいて、JSON→JSONの変換処理を実現する必要性が高いかというと、微妙な気がします。(言い訳気味ですが)
むしろ、JSON→表の変換処理の方がありそうな気がしませんか?(強引)
というわけで、JSON_TABLEファンクションの紹介を兼ねて、JSON→表の変換処理を行ってみたいと思います。
JSON_TABLEファンクションを用いたJSON→表の変換
データを準備します。
SQL> UPDATE json_data SET data ='
3 "people": [
4 {
5 "name": "a",
6 "state": {"name": "up"}
7 },
8 {
9 "name": "b",
10 "state": {"name": "down"}
11 },
12 {
13 "name": "c",
14 "state": {"name": "up"}
15 }
16 ]
17 }
18 ';
1 row updated.
JSON_TABLEファンクションを使い、表形式でデータを得ます。
JSON_TABLEファンクション内のCOLUMNS句で、得られる表の列について、データ型やパス式を指定しています。
SQL> SELECT x.* FROM json_data j, JSON_TABLE(j.data, '$.people[*]' ERROR ON ERROR
2 COLUMNS (
3 name VARCHAR2(32) PATH '$.name',
4 state VARCHAR2(32) PATH '$.state.name')) x;
NAME STATE
-------------------------------- --------------------------------
a up
b down
c up
それぞれのデータについて型の指定ができるため、ひらたく言うと「お行儀がイイ感じ」で表形式のデータを得られます。
JSON形式で得たデータを、表形式でデータベースで永続する場合に重宝しそうです。
SQL/JSONファンクションJSON_TABLE - OracleR Database JSON開発者ガイド 12c リリース2 (12.2) E85247-02
Oracle Database JSON Tips
本文で記載した内容と一部重複しますが、最後にOracle Database JSONのTipsをまとめておきます。
JSON_xxxファンクションを試すときは ERROR ON ERRORを指定したほうが良い
ERROR ON ERRORを指定しないと、パス式がうまくマッチしなくてもNULLを返すだけで、Oracle Databaseは何も教えてくれません。
SQL> SELECT JSON_QUERY(j.data, '$.k[0 to 4]') FROM json_data j;
JSON_QUERY(J.DATA,'$.K[0TO4]')
--------------------------------------------------------------------------------
ERROR ON ERRORを指定すると、原因の特定に有用な情報を出力してくれます。
SQL> SELECT JSON_QUERY(j.data, '$.k[0 to 4]' ERROR ON ERROR) FROM json_data j;
SELECT JSON_QUERY(j.data, '$.k[0 to 4]' ERROR ON ERROR) FROM json_data j
ERROR at line 1:
ORA-40480: result cannot be returned without array wrapper
13.3 SQL/JSON問合せファンクションおよび条件で使用されるエラー句 - OracleR Database JSON開発者ガイド 12c リリース2 (12.2) E85247-02
ドット表記法を使う場合はJSONとして参照する列にIS JSON制約を設定する必要がある
設定しないと、ORA-00904が発生します。エラーメッセージがあまり親切でないので要注意です!
SQL> SELECT j.data1.a FROM json_data2 j;
SELECT j.data1.a FROM json_data2 j
ERROR at line 1:
ORA-00904: "J"."DATA1"."A": invalid identifier
SQL/JSON条件IS JSONおよびIS NOT JSON - OracleR Database JSON開発者ガイド 12c リリース2 (12.2) E85247-02
JSON_xxxファンクションでは、返される値の種類に応じてファンクションを使い分ける必要がある。
Oracle Database JSONでは、返される値の種類に応じてファンクションを使い分ける必要があります。
具体的には以下のとおりです。
返される値 JSON_xxxファンクション
--------------------------- ------------
スカラー値 JSON_VALUE
JSON(配列、オブジェクト) JSON_QUERY
JSON_QUERYが複数の値を返す場合、配列にラップする必要がある。
List Projectionの説明の箇所で取り上げた実行例ですが、JSON_QUERYが複数の値を返す場合、配列にラップしないと、エラーORA-40480が発生します。
SQL> SELECT JSON_QUERY(j.data, '$.people[*].first' ERROR ON ERROR ) FROM json_data j;
SELECT JSON_QUERY(j.data, '$.people[*].first' ERROR ON ERROR ) FROM json_data j
ERROR at line 1:
ORA-40480: result cannot be returned without array wrapper
WITH CONDITIONAL WRAPPER などを指定すれば、複数の値をラップした配列が返されます。
SQL> SELECT JSON_QUERY(j.data, '$.people[*].first' WITH CONDITIONAL WRAPPER ERROR ON ERROR ) FROM json_data j;
JSON_QUERY(J.DATA,'$.PEOPLE[*].FIRST'WITHCONDITIONALWRAPPERERRORONERROR)
--------------------------------------------------------------------------------
["James","Jacob","Jayden"]
Oracle SQL関数JSON_QUERYおよびJSON_TABLEのラッパー句
JSON_QUERYで、パス式の評価結果がスカラー値になる場合があるならWITH CONDITIONAL WRAPPERを指定する
JSON_QUERYファンクションはスカラー値を返せません。パス式の評価結果が常にスカラー値になるとわかっているのなら、JSON_VALUEを使えばよいのですが、
対象のJSONドキュメントに応じて、評価結果がJSON(の一部)になったり、スカラー値になったりする場合はどうすればよいのでしょうか?
WITH CONDITIONAL WRAPPERを指定しておくと、評価結果がスカラー値になった場合にみ配列でラップしてくれます。なかなか気が利いています。
表13-1 JSON_QUERYラッパー句の例 - OracleR Database JSON開発者ガイド 12c リリース2 (12.2) E85247-02
WITH CONDITIONAL WRAPPERがデフォルトの動作でもよい気がしますが、なにか理由があるのでしょうかねぇ・・・?
Oracle Database Connect 2017に出演?します
Oracle Database Connect 2017ご参加ありがとうございました+tweetまとめ
JPOUG「Oracle Databaseを中心とした座談会’19」@ Oracle Code Tokyo 2019 の内容がPDFに!
ORACLE MASTER 2019新資格体系とは – 18c/19c対応
・Oracle ACE
・AWS Certified Solutions Architect - Associate
・ORACLE MASTER Platinum Oracle Database 11g, 12c 他多数
カテゴリー
Aegis Wall(2) AWS(11) CData Sync(3) CO-Sol Canada(3) D'amo(2) Dbvisit Standby(54) DBセキュリティ(2) DBパフォーマンス(12) DBレプリケーション(49) DB移行(7) Delphix(6) IBM Db2(5) JPOUG(85) Linux(7) MaxGauge(2) Microsoft SQL Server(31) MySQL(34) Nutanix(1) ODA / Oracle Database Appliance(1) Oracle ACE(17) Oracle Autonomous Database(10) Oracle AVDF(3) Oracle Cloud(55) Oracle Cloud Infrastructure(40) Oracle Data Guard(5) Oracle Database(327) Oracle Database 10g(2) Oracle Database 11g(12) Oracle Database 12c R1(70) Oracle Database 12c R2(34) Oracle Database 18c(25) Oracle Database 19c(54) Oracle Database 20c(5) Oracle Database 21c(10) Oracle Database 23c(5) Oracle Database Express Edition(2) Oracle Database Standard Edition 2(43) Oracle Enterprise Manager(5) Oracle Exadata(6) Oracle Fail Safe(1) Oracle GoldenGate(17) Oracle Linux Virtualization Manager(1) ORACLE MASTER(71) ORACLE MASTER Bronze DBA(14) ORACLE MASTER Gold DBA(11) ORACLE MASTER Platinum(17) ORACLE MASTER Silver DBA(16) ORACLE MASTER Silver SQL(11) Oracle OpenWorld/CloudWorld(31) Oracle Restart(3) Oracle SEHA(12) Oracle SQL Developer(1) Oracle VM(25) Oracle VM VirtualBox(3) PISO(2) PostgreSQL(42) Qlik Replicate / Attunity Replicate(28) SharePlex(30) SIOS LifeKeeper(19) Snowflake(1) SolarWinds DPA(22) SQLチューニング(16) Standby Express(7) Sybase SAP ASE(6) Toad(13) VMware(7) Zabbix(12) お知らせ(1) キャリア・教育(32) コーソル(6) コーソル福岡オフィス(3) セミナー紹介(2) データベース運用(14) 主要RDBMS製品の比較(10) 対外講演(0) 対外講演おしらせ(31) 対外講演まとめ(14) 書籍紹介(7) 未分類(8) 論理レプリケーション(19) 資料公開(7) 非常駐型DBAサービス(1) 高可用性/DR/災害対策(57)
アーカイブ
2024年