この節では次のことを説明します。
JSONデータを処理、生成する関数と演算子
SQL/JSONパス言語
SQL/JSON問い合わせ関数
SQL環境内のJSONデータ型にネイティブサポートを提供するために、PostgreSQLSQL/JSONデータモデルを実装しています。 このモデルは、一連の項目で構成されます。 各項目は、SQLスカラ値、追加のSQL/JSON NULL値、およびJSON配列とオブジェクトを使用する複合データ構造を保持できます。 モデルは、JSON規格RFC 7159で暗黙的に指定されているデータモデルを形式化したものです。
SQL/JSONでは、トランザクションをサポートをしながら、通常のSQLデータと一緒にJSONデータをハンドルすることができます。以下のものが含まれます:
JSONデータをデータベースにアップロードし、それを文字またはバイナリ文字列として通常のSQL列に保存します。
リレーショナルデータからJSONオブジェクトと配列を生成します。
SQL/JSON問い合わせ関数およびSQL/JSONパス言語式を使用してJSONデータを照会します。
SQL/JSON標準を更に学ぶためには、[sqltr-19075-6]をご覧ください。 PostgreSQLでサポートされているJSON型の詳細に関しては、8.14をご覧ください。
表 9.45にJSONデータ型(8.14を参照)で使用可能な演算子を示します。
加えて表 9.1で示す通常の比較演算子がjsonb
で利用できますが、json
では利用できません。
比較演算子は8.14.4で概要が示されているように示すBツリー操作用の順序付け規則にしたがいます。
レコードの値をJSONに集約するjson_agg
集約関数、値の対をJSONオブジェクトに集約するjson_object_agg
集約関数、およびそれらのjsonb
版のjsonb_agg
とjsonb_object_agg
については9.21も参照して下さい。
表9.45 json
とjsonb
演算子
演算子 説明 例 |
---|
JSON配列の
|
与えられたキーでJSONオブジェクトフィールドを取り出します。
|
JSON配列の
|
与えられたキーでJSONオブジェクトフィールドを
|
指定したパスにおけるJSONの副オブジェクトを取り出します。パス要素はフィールドキーあるいは配列のインデックスでも構いません。
|
指定したパスにおけるJSONの副オブジェクトを
|
JSON入力が要求と一致する正しい構造をしていなければ、フィールド/要素/パス抽出演算子は失敗するのではなくNULLを返します。例えばそのような要素が存在しない場合です。
ほかにjsonb
だけで利用可能な演算子もいくつか存在します。
それらを表 9.46に示します。
8.14.4には、インデックス付されたjsonb
データを効率的に検索するためにこれらの演算子をどのように利用できるかについて書いてあります。
表9.46 追加jsonb
演算子
演算子 説明 例 |
---|
最初のJSON値は二番目を含んでいるか? (包含の詳細は8.14.3を参照してください。)
|
最初のJSON値は二番目に含まれているか?
|
そのテキスト文字列はトップレベルのキーあるいは配列要素としてJSON値中に存在しているか?
|
テキスト配列中のどれかの文字列がトップレベルのキーあるいは配列要素として存在しているか?
|
テキスト配列のすべての文字列がトップレベルのキーあるいは配列要素として存在しているか?
|
2つの
一つの要素を持つとして配列を他の配列に追加するには、例のように配列の追加のレイヤ中に含めてください。
|
キー(及びその値)をJSONオブジェクトから削除します。あるいはマッチする文字列値をJSON配列から削除します。
|
左のオペランドからマッチするすべてのキーあるいは配列要素を削除します。
|
指定したインデックス(負の整数は最後から数えます)の配列要素を削除します。 JSON値が配列でなければエラーが生じます。
|
指定パスのフィールドあるいは配列要素を削除します。パス要素はフィールドキーあるいは配列インデックスが指定できます。
|
JSONパスは指定されたJSON値に対して何らかの項目を返すか?(これは標準SQLのJSONパス式でのみ有用であり、述語チェック式では有効ではありません。述語チェック式は常に値を返すからです。)
|
指定されたJSON値に対するJSONパス述語チェックの結果を返します(これは、標準SQLのJSONパス式ではなく、述部チェック式でのみ有用です。パス結果が単一のブール値でない場合は
|
jsonpath
演算子の@?
および@@
演算子は以下のエラーを抑止します。
オブジェクトフィールドあるいは配列要素の欠如、期待しないJSON要素型、日付時刻及び数値エラー。
以下に示すjsonpath
関連の関数もこれらのエラーを抑止するようにすることもできます。
この振る舞いは、異なる構造のJSON文書集合を検索する際に役に立つかも知れません。
表 9.47に、json
値およびjsonb
値を作成するために利用可能な関数を示します。
このテーブルの一部の関数は、返されるデータ型を指定するRETURNING
句を持っています。
これはjson
、jsonb
、bytea
、文字列型(text
、char
、varchar
)、あるいはjson
からその型へのキャストがある型のいずれかでなければなりません。
デフォルトではjson
型が返されます。
表9.47 JSON作成関数
関数 説明 例 |
---|
SQL値を
|
SQL配列をJSON配列に変換します。
追加の論理引数が真であるときに改行がトップレベルの配列要素の間に加えられる以外は、その振る舞いは
|
JSON配列を、一連の
|
SQL複合値をJSONオブジェクトに変換します。
追加の論理引数が真であるときに改行がトップレベルの配列要素の間に加えられる以外は、その振る舞いは
|
異なる型から構成される可能性のあるJSON配列をvariadic引数リストから作成します。
各々の引数は
|
variadic引数リストからJSONオブジェクトを作成します。
慣例により引数リストは代替キーと値が交互に並んだものです。
キー引数はテキストに強制的に変換されます。
値引数は
|
指定されたすべてのキー/値ペアのJSONオブジェクトを構築します。
キー/値ペアが指定されていない場合は、空のオブジェクトを構築します。
|
テキスト配列からJSONオブジェクトを作成します。 配列は、偶数個の要素からなる1次元(キー/値の対が交互に並んでいるものと扱われます)あるいは内側の配列が2つの要素を持つ2次元(2つの要素がキー/値のペアとして扱われます)のいずれかでなければなりません。 すべての値はJSON文字列に変換されます。
|
この形の
|
指定された
|
指定されたSQLスカラ値をJSONスカラ値に変換します。 入力がNULLの場合、SQLのNULLが返されます。 入力が数値またはブール値の場合、対応するJSONの数値またはブール値が返されます。 それ以外の場合は、JSONの文字列が返されます。
|
SQL/JSON式を文字列またはバイナリ文字列に変換します。
|
表 9.48には、JSONをテストするためのSQL/JSON機能の詳細が記載されています。
表9.48 SQL/JSONテスト用関数
表 9.49にjson
とjsonb
値を処理するのに使える関数を示します。
表9.49 JSON処理関数
関数 説明 例 |
---|
トップレベルのJSON配列をJSON値の集合に展開します。
value ----------- 1 true [2,false]
|
トップレベルのJSON配列を
value ----------- foo bar
|
トップレベルのJSON配列の要素数を返します。
|
トップレベルのJSONオブジェクトをキー/値のペアの集合に展開します。
key | value -----+------- a | "foo" b | "bar"
|
トップレベルのJSONオブジェクトをキー/値のペアの集合に展開します。
返り値の
key | value -----+------- a | foo b | bar
|
指定したパスにおけるJSONの副オブジェクトを取り出します。
(これは
|
指定したパスにおけるJSONの副オブジェクトを
|
トップレベルのJSONオブジェクト中のキーの集合を返します。
json_object_keys ------------------ f1 f2
|
トップレベルのJSONオブジェクトを JSON値を出力列のSQL型に変換する際に以下のルールが順に適用されます。
これらの関数の例ではJSON定数を使用していますが、典型的な使用法はその
a | b | c ---+-----------+------------- 1 | {2,"a b"} | (4,"a b c")
|
jsonb_populate_record_valid ----------------------------- f (1 row)
ERROR: value too long for type character(2)
jsonb_populate_record_valid ----------------------------- t (1 row)
a ---- aa (1 row)
|
トップレベルのJSONオブジェクトを
a | b ---+--- 1 | 2 3 | 4
|
トップレベルのJSONオブジェクトを
a | b | c | d | r ---+---------+---------+---+--------------- 1 | [1,2,3] | {1,2,3} | | (123,"a b c")
|
トップレベルのJSON配列を
a | b ---+----- 1 | foo 2 |
|
|
|
|
与えられたJSON値からNULLを持つオブジェクトフィールドをすべて削除します。 オブジェクトフィールドではないNULL値は変わりません。
|
JSONパスが指定したJSON値に対して項目を返すかどうかをチェックします。
(これは、述語チェック式ではなく、標準SQLのJSONパス式でのみ有用です。
なぜなら、それらは常に値を返すからです。)
|
指定したJSON値のJSONパス述語チェックの結果を返します。
(これは、パス結果が単一のブール値でない場合、失敗するか
|
指定されたJSON値のJSONパスによって戻されるすべてのJSON項目を戻します。
標準SQLのJSONパス式の場合、
jsonb_path_query ------------------ 2 3 4
|
指定されたJSON値のJSONパスによって返されるすべてのJSON項目を、JSON配列として返します。
パラメータは
|
指定されたJSON値のJSONパスによって返される最初のJSON項目を返します。
結果がない場合は
|
これらの関数は、時間帯を考慮する日時値の比較をサポートすることを除いて、上で述べた、
|
与えられたJSON値を整形されたインデント付きテキストに変換します。
[ { "f1": 1, "f2": null }, 2 ]
|
トップレベルのJSON値の型をテキスト文字列として返します。
可能な型は次のとおりです。
|
SQL/JSONパス式は、XMLコンテンツへのアクセスで使用されるXPath式同様、JSON値から取り出す項目を指定します。
PostgreSQLではパス式はjsonpath
データ型として実装されており、8.14.7で説明されているすべての要素を使うことができます。
JSON問い合わせ関数と演算子は与えられたパス式をpath engineに渡して評価します。
式が問い合わせ対象のJSONデータにマッチすれば、関連するSQL/JSON項目が返却されます。
一致しない場合、結果はNULL
、false
、または関数によって異なるエラーになります。
パス式はSQL/JSONパス言語で書かれ、算術式と関数を含むことができます。
パス式はjsonpath
データ型で認められた一連の要素からなります。
パス式は通常左から右へと評価されますが、括弧を使って演算の順序を変更することができます。
評価が成功すれば、一連のJSON項目が生成され、評価結果が指定した計算を完了したJSON問い合わせ関数に戻されます。
問い合わせ対象(context item)のJSONデータを参照するには、パス式内で$
値を使います。
パスの最初の要素は常に$
でなければなりません。
複数のアクセサ演算子をその後に記述することもできます。
この後に、JSON構造のレベルを1つずつ下ってコンテキスト項目のサブ項目を取得するアクセサ演算子を1つ以上指定することができます。
各アクセサ演算子は、前の評価ステップの結果に作用し、各入力項目から0個、1個、または複数の出力項目を生成します。
たとえば、次のようなパースしたいGPSトラッカーからのJSONデータがあるとします。
SELECT '{ "track": { "segments": [ { "location": [ 47.763, 13.4034 ], "start time": "2018-10-14 10:05:14", "HR": 73 }, { "location": [ 47.706, 13.2635 ], "start time": "2018-10-14 10:39:21", "HR": 135 } ] } }' AS json \gset
(上記の例は、psqlにコピー&ペーストして、以下の例の設定を行うことができます。
そうすると、psqlは:'json'
を適切に引用符付けされた文字列定数に展開し、JSON値を含めます。)
使用可能なトラックセグメントを取り出すには、.
アクセサ演算子を使用して、周辺のJSONオブジェクトを下っていく必要があります。
例:
key
=>
select jsonb_path_query(:'json', '$.track.segments');
jsonb_path_query ------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"HR": 73, "location": [47.763, 13.4034], "start time": "2018-10-14 10:05:14"}, {"HR": 135, "location": [47.706, 13.2635], "start time": "2018-10-14 10:39:21"}]
配列の内容を取り出すには、典型的には[*]
演算子を使います。
次の例は、使用可能なすべてのトラックセグメントの位置座標を返します。
=>
select jsonb_path_query(:'json', '$.track.segments[*].location');
jsonb_path_query ------------------- [47.763, 13.4034] [47.706, 13.2635]
ここでは、JSON入力値($
)全体から始め、.track
アクセサが"track"
オブジェクトキーに関連付けられたJSONオブジェクトを選択し、.segments
アクセサがそのオブジェクト内の"segments"
キーに関連付けられたJSON配列を選択し、[*]
アクセサがその配列の各要素を(一連の項目を生成しながら)選択し、.location
アクセサがそれらのオブジェクトのそれぞれの中の"location"
キーに関連付けられたJSON配列を選択しました。
この例では、それらのオブジェクトのそれぞれに"location"
キーがありましたが、もしそうでなければ、.location
アクセッサは単にその入力項目に対して何の出力も生成しなかったでしょう。
最初のセグメントの座標だけを返すには、[]
アクセサ演算子の中で対応する添え字を指定することができます。
JSON配列インデックスは0スタートであることに注意してください。
=>
select jsonb_path_query(:'json', '$.track.segments[0].location');
jsonb_path_query ------------------- [47.763, 13.4034]
各段階でのパス評価結果は9.16.2.3に列挙されている一つ以上のjsonpath
演算子とメソッドで処理することができます。
各々のメソッド名の前にピリオドを付けなければなりません。
たとえば配列の大きさを得ることができます。
=>
select jsonb_path_query(:'json', '$.track.segments.size()');
jsonb_path_query ------------------ 2
パス式内のjsonpath
演算子とメソッドを使用する他の例については以下の9.16.2.3を参照してください。
パスには、SQLのWHERE
句のように働くフィルタ式を含めることもできます。
フィルタ式はクェスチョンマークで始まり、カッコ内に条件を記述します。
? (condition
)
フィルタ式はそれを適用するパス評価段階の直後に指定しなければなりません。
この段階の結果は、指定した条件を満たす項目だけが含まれるようにフィルタされます。
SQL/JSONは3値論理を定義しており、条件はtrue
、false
、unknown
のどれかを生成します。
unknown
は値はSQLのNULL
と同じ役割を果たし、is unknown
述語で評価できます。
その後の評価段階ではtrue
を返すフィルタ式に対応する項目だけが使われます。
フィルタ式内で利用できる関数と演算子は表 9.51にリストされています。
フィルタ式内では、考慮する必要のある値は@
変数で示します。(つまり以前のパスステップの結果の一つです。)
コンポーネント項目を取得するためにアクセサ演算子を@
の後に記述することができます。
たとえば130より高いすべての心拍数を取り出したいとします。 これを実現するには、次のようにします。
=>
select jsonb_path_query(:'json', '$.track.segments[*].HR ? (@ > 130)');
jsonb_path_query ------------------ 135
そうした値を持つセグメントの開始時刻を得たい場合は、開始時刻を選択する前に無関係のセグメントを取り除く必要があります。 そうすることにより前の段階にフィルタ式が適用されるので、その条件で適用されるパスは異なります。
=>
select jsonb_path_query(:'json', '$.track.segments[*] ? (@.HR > 130)."start time"');
jsonb_path_query ----------------------- "2018-10-14 10:39:21"
必要なら複数のフィルタ式を順に使用することができます。 次の例では、関連する座標と高い心拍数値を持つ位置を含むすべてのセグメントの開始時間を選択します。
=>
select jsonb_path_query(:'json', '$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time"');
jsonb_path_query ----------------------- "2018-10-14 10:39:21"
異なる入れ子レベルに対してフィルタ式を適用することもできます。 次の例では、まず位置ですべてのセグメントをフィルタし、もしあれば高い心拍数値を返します。
=>
select jsonb_path_query(:'json', '$.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130)');
jsonb_path_query ------------------ 135
フィルタ式をネストして、フィルタ式を相互にネストすることもできます。 次の例では、トラックに高心拍数値のセグメントが含まれている場合はそのサイズを返し、それ以外の場合は空のシーケンスを返します。
=>
select jsonb_path_query(:'json', '$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()');
jsonb_path_query ------------------ 2
PostgreSQLのSQL/JSONパス言語の実装はSQL/JSON標準と次の点が異なります。
標準SQLの拡張として、PostgreSQLパス式はブール述語になりますが、標準SQLでは述語はフィルタ内でのみ許されます。
標準SQLのパス式は、問い合わせられたJSON値の関連する要素を返しますが、述語チェック式は述語の単一の3値結果true
、false
、unknown
を返します。
たとえば、次の標準SQLフィルタ式を記述できます。
=>
select jsonb_path_query(:'json', '$.track.segments ?(@[*].HR > 130)');
jsonb_path_query --------------------------------------------------------------------------------- {"HR": 135, "location": [47.706, 13.2635], "start time": "2018-10-14 10:39:21"}
類似述語チェック式は単にtrue
を返し、一致が存在することを示します。
=>
select jsonb_path_query(:'json', '$.track.segments[*].HR > 130');
jsonb_path_query ------------------ true
述語チェック式は@@
演算子(およびjsonb_path_match
関数)で必要であり、@?
演算子(またはjsonb_path_exists
関数)では使用すべきではありません。
JSONデータを問い合わせる際、パス式は実際のJSONデータ構造に一致しないかも知れません。 存在しないオブジェクトのメンバあるいは配列要素へのアクセスは構造上のエラーとして定義されています。 SQL/JSONパス式には構造上のエラーを扱うための2つのモードがあります。
非厳密(lax)モード(デフォルト)— パスエンジンは指定したパスを問い合わせデータに暗黙的に適合させます。 以下に説明するように修正できない構造エラーは抑制され、一致は生成されません。
厳密(strict)モード — 構造上のエラーがあるとエラーが発生します。
非厳密モードは、JSONデータが期待されるスキーマに沿わないときにJSON文書とパス式のマッチングを助けます。 あるオペランドが操作の要件に合わないときにはそれをSQL/JSON配列にまとめたり、あるいは操作を行う前にそれをSQL/JSONシーケンスに展開することもできます。 また非厳密モードにおいては、比較演算子は自動的にオペランドを展開し、SQL/JSON配列をそのまま比較することができます。 大きさ1の配列はその単独要素と同じものとして扱われます。 自動展開は以下の場合に行われません。
それぞれ配列の型、要素数を返すtype()
、size()
をパス式が含む。
問い合わせ対象のJSONデータが入れ子の配列を含む。 この場合はもっとも外側の配列のみが展開され、内側の配列は変わりません。 ですから、それぞれの評価段階において1レベルのみに暗黙的な展開が行われます。
たとえば、上述のGPSデータに問い合わせする場合、非厳密モードでは配列のセグメントを含んでいるという事実から抽出できます。
=>
select jsonb_path_query(:'json', 'lax $.track.segments.location');
jsonb_path_query ------------------- [47.763, 13.4034] [47.706, 13.2635]
厳密モードでは、指定されたパスは問い合わせ対象のJSONドキュメントの構造と正確に一致する必要があるため、このパス式を使用するとエラーが発生します。
=>
select jsonb_path_query(:'json', 'strict $.track.segments.location');
ERROR: jsonpath member accessor can only be applied to an object
非厳密モードと同じ結果を得るには、segments
配列を明示的に展開する必要があります。
=>
select jsonb_path_query(:'json', 'strict $.track.segments[*].location');
jsonb_path_query ------------------- [47.763, 13.4034] [47.706, 13.2635]
非厳密モードの展開動作は、驚くべき結果をもたらす可能性があります。
たとえば、.**
アクセサを使用する次の問い合わせは、すべてのHR
値を2回選択します。
=>
select jsonb_path_query(:'json', 'lax $.**.HR');
jsonb_path_query ------------------ 73 135 73 135
これは.**
アクセサがsegments
とその各々の要素の両方を検索するからです。
一方、.HR
アクセサは非厳密モードでは自動的に配列を展開します。
予期しない結果を避けるには、.**
アクセサを厳密モードでのみ使うことをお勧めします。
次の問い合わせはHR
の各値を一度だけ検索します。
=>
select jsonb_path_query(:'json', 'strict $.**.HR');
jsonb_path_query ------------------ 73 135
配列の展開は予期しない結果をもたらす可能性もあります。
location
配列をすべて選択する次の例を考えてみましょう。
=>
select jsonb_path_query(:'json', 'lax $.track.segments[*].location');
jsonb_path_query ------------------- [47.763, 13.4034] [47.706, 13.2635] (2 rows)
予想どおり、配列全体が返されます。 しかし、フィルタ式を適用すると、配列が展開され、各項目が評価されて、式に一致する項目のみが返されます。
=>
select jsonb_path_query(:'json', 'lax $.track.segments[*].location ?(@[*] > 15)');
jsonb_path_query ------------------ 47.763 47.706 (2 rows)
これは、完全な配列がpath式によって選択されるという事実にもかかわらずです。 厳密モードを使用して、配列の選択を復元します。
=>
select jsonb_path_query(:'json', 'strict $.track.segments[*].location ?(@[*] > 15)');
jsonb_path_query ------------------- [47.763, 13.4034] [47.706, 13.2635] (2 rows)
表 9.50にjsonpath
で利用可能な演算子とメソッドを示します。
単項演算子とメソッドは以前のパスステップから生じた複数の値に適用できますが、二項演算子(加算など)は単一の値にしか適用できないことに注意してください。
非厳密モードでは、配列に適用されるメソッドは配列内の各値に対して実行されます。
例外は.type()
と.size()
で、配列自分自身に適用されます。
表9.50 jsonpath
演算子とメソッド
演算子/メソッド 説明 例 |
---|
加算
|
単項のプラス(演算なし)。加算と違って、複数の値に渡って適用できます。
|
減算
|
負符号。減算と違って、複数の値に渡って適用できます。
|
乗算
|
除算
|
剰余(残り)
|
JSON項目の型(
|
JSON項目の大きさ(配列の要素数。配列でなければ1)
|
JSONのブール値、数値、または文字列から変換されたブール値。
|
JSONのブール値、数値、文字列、または日時から変換された文字列値。
|
JSON数値あるいは文字列から変換した概算の浮動小数点数
|
引数より大きいか等しく、与えられた数に最も近い整数
|
引数より小さいか等しく、与えられた数に最も近い整数
|
与えられた数の絶対値
|
JSONの数値または文字列から変換された大きな整数値。
|
JSONの数値または文字列から変換された丸められた10進数値(
|
JSONの数値または文字列から変換された整数値。
|
JSONの数値または文字列から変換されたNumeric値。
|
文字列から変換した日時値
|
指定の
|
文字列から変換された日付値。
|
文字列から変換した時間帯のない時刻値
|
文字列から変換された時間帯のない時間の値。分数の秒は指定された精度に調整されます。
|
文字列から変換されたタイムゾーン値を持つ時間。
|
文字列から変換された時間帯を持つ時間。分数の秒は指定された精度に調整されます。
|
文字列から変換された時間帯なしのタイムスタンプ
|
文字列から変換された時間帯なしのタイムスタンプ値。分数の秒数は指定された精度に調整されます。
|
文字列から変換された時間帯を持つタイムスタンプ。
|
文字列から変換された時間帯を持つタイムスタンプ値。分数の秒数は指定された精度に調整されます。
|
以下の3つのフィールドを含むオブジェクトの配列で表現したオブジェクトのキー/値ペア。
|
datetime()
とdatetime(
の結果型はtemplate
)date
、timetz
、time
、timestamptz
、あるいはtimestamp
です。
両方のメソッドは結果型を動的に決定します。
datetime()
メソッドは入力文字列をdate
、timetz
、time
、timestamptz
、timestamp
のISO形式に対して順にマッチを試みます。
最初にマッチした形式で停止し、関連するデータ型を出力します。
datetime(
メソッドは与えられたテンプレート文字列にあるフィールドに従って結果型を決定します。
template
)
datetime()
とdatetime(
はtemplate
)to_timestamp
SQL関数と同じ解析ルール(参照9.8)を用いますが、3つの例外があります。
一番目に、これらのメソッドは一致しないテンプレートパターンを許容しません。二番目に次の区切り文字のみを許容します。負符号、ピリオド、斜線(スラッシュ)、カンマ、アポストロフィー、セミコロン、コロン、空白、です。
三番目にテンプレート文字列中の区切り文字は正確に入力文字列と一致しなければなりません。
異なる日時型の比較が必要なら、暗黙的なキャストが適用されます。
date
値はtimestamp
あるいはtimestamptz
にキャストできます。
timestamp
はtimestamptz
に、time
はtimetz
にキャストできます。
しかし、これらの変換は最初のものを除くすべてが現在のTimeZone設定に依存します。ですから時間帯を認識するjsonpath
関数中でのみ実行可能です。
同様に、文字列を日付/時刻型に変換する他の日付/時刻関連のメソッドも、現在のTimeZone設定を含む可能性があるこのキャストを行います。
したがって、これらの変換は、timezoneを意識したjsonpath
関数内でのみ実行できます。
表 9.51に利用可能なフィルタ式要素を示します。
表9.51 jsonpath
フィルタ式要素
述語/値 説明 例 |
---|
等値比較(これと他の比較演算子はすべてのJSONスカラ値で使えます)
|
非等値比較
|
未満比較
|
以下比較
|
より大きい比較
|
以上比較
|
JSON定数
|
JSON定数
|
JSON定数
|
論理AND
|
論理OR
|
論理NOT
|
論理条件が
|
最初のオペランドが2番目のオペランドで与えられる正規表現にマッチするかどうか検査します。
オプションで
|
2番目の文字列が1番目のオペランドの最初の部分文字列かどうかを検査します。
|
パス式が少なくとも一つのSQL/JSON項目とマッチするかどうかを検査します。
パス式がエラーとなる場合は
|
SQL/JSONパス式ではlike_regex
フィルタを使ってテキストを正規表現にマッチさせることができます。
たとえば、次のSQL/JSONパス式問い合わせは、英語の母音で始まる配列内のすべての文字列に大文字小文字を無視してマッチするでしょう。
$[*] ? (@ like_regex "^[aeiou]" flag "i")
オプションのflag
文字列は一つ以上の文字を含むことができます。
i
は大文字小文字を無視したマッチ、m
は^
と$
で改行にマッチ、s
は.
が改行にマッチ、q
はパターン全体を参照します。(振る舞いを単純な部分文字列マッチとします)
SQL/JSON標準は正規表現の定義を、XQuery標準を使用するLIKE_REGEX
演算子から借りています。
PostgreSQLは今の所LIKE_REGEX
演算子をサポートしていません。
ですから、like_regex
フィルタは9.7.3で説明されているPOSIX正規表現で実装されています。
このことにより、9.7.3.8で列挙されているSQL/JSON標準の振る舞いとの小さな違いが生じます。
しかし、ここで述べているフラグ文字の非互換性はSQL/JSONには適用されないことに注意してください。SQL/JSONは、XQueryのフラグ文字をPOSIXエンジンが期待するのと一致するように解釈するからです。
like_regex
のパターン引数は8.14.7で説明されているルールにしたがって書かれたJSONパス文字列リテラルであることに注意してください。
これは、正規表現で使用するすべてのバックスラッシュを二重に書かなければならないことを意味します。
たとえば、数字のみを含むroot文書の文字列値にマッチさせるには以下のようにします。
$.* ? (@ like_regex "^\\d+$")
表 9.52で記述されたSQL/JSON関数JSON_EXISTS()
、JSON_QUERY()
、JSON_VALUE()
は、JSON文書への問い合わせに使用できます。
これらの各関数は、path_expression
(SQL/JSONパス問い合わせ)をcontext_item
(文書)に適用します。
path_expression
の内容の詳細については、9.16.2を参照してください。
path_expression
はリファレンス変数にすることもできます。その値は、各関数でサポートされているPASSING
句でそれぞれの名前で指定されます。
context_item
には、jsonb
の値、または文字の並びにキャストできるjsonb
を指定できます。
表9.52 SQL/JSON問い合わせ関数
関数の呼び出し形式 説明 例 |
---|
例:
ERROR: jsonpath array subscript is out of bounds
|
例:
ERROR: malformed array literal: "[1, 2]" DETAIL: Missing "]" after array dimensions.
|
例:
|
context_item
式は、まだjsonb
型でない場合、暗黙キャストによってjsonb
に変換されます。
ただし、その変換中に発生する解析エラーは、無条件に発生します。つまり、(指定または暗黙的な)ON ERROR
句に従って処理されません。
path_expression
がSQLnull
を返す場合、JSON_VALUE()
はSQL NULLを返します。一方、JSON_QUERY()
はJSON null
をそのまま返します。
JSON_TABLE
はJSONデータを問い合わせ、結果を通常のSQLテーブルとしてアクセスできるリレーショナルビューとして表示するSQL/JSON関数です。
JSON_TABLE
は、SELECT
、UPDATE
、またはDELETE
のFROM
句内で使用できます。また、MERGE
文のデータソースとしても使用できます。
JSONデータを入力として、JSON_TABLE
はJSONパス式を使用して、提供されたデータの一部を抽出し、構築されたビューの行パターンとして使用します。
行パターンで指定された各SQL/JSON値は、構築されたビューの別々の行のソースとして機能します。
行パターンを列に分割するために、JSON_TABLE
は作成されたビューのスキーマを定義するCOLUMNS
句を提供します。
各列に対して、個別のJSONパス式を指定して、行パターンに対して評価されるようにできます。これは、指定された出力行の特定の列の値になります。
行パターンのネストされたレベルに格納されたJSONデータは、NESTED PATH
句を使用して抽出できます。
各NESTED PATH
句は、行パターンのネストされたレベルからのデータを使用して1つ以上の列を生成するために使用できます。
これらの列は、最上位のCOLUMNS句と同様のCOLUMNS
句を使用して指定できます。
NESTED COLUMNSから構成される行は子行(child rows)と呼ばれ、親のCOLUMNS
句で指定された列から構成される行に対して結合され、最終的なビューの行が得られます。
子列自体はNESTED PATH
指定を含むことができ、任意のネストレベルにあるデータを抽出することができます。
同じレベルにある複数のNESTED PATH
によって生成された列は、互いに兄弟(siblings)と見なされ、親行と結合された後の行はUNIONを使用して結合されます。
JSON_TABLE
が生成する行は、それを生成した行に横方向に結合されるため、JSONデータを保持する元のテーブルに構築されたビューを明示的に結合する必要はありません。
構文は次のとおりです。
JSON_TABLE (context_item
,path_expression
[ ASjson_path_name
] [ PASSING {value
ASvarname
} [, ...] ] COLUMNS (json_table_column
[, ...] ) [ {ERROR
|EMPTY
[ARRAY]}ON ERROR
] ) ここでjson_table_column
は次のとおりです。name
FOR ORDINALITY |name
type
[ FORMAT JSON [ENCODINGUTF8
]] [ PATHpath_expression
] [ { WITHOUT | WITH { CONDITIONAL | [UNCONDITIONAL] } } [ ARRAY ] WRAPPER ] [ { KEEP | OMIT } QUOTES [ ON SCALAR STRING ] ] [ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULTexpression
} ON EMPTY ] [ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULTexpression
} ON ERROR ] |name
type
EXISTS [ PATHpath_expression
] [ { ERROR | TRUE | FALSE | UNKNOWN } ON ERROR ] | NESTED [ PATH ]path_expression
[ ASjson_path_name
] COLUMNS (json_table_column
[, ...] )
各構文要素について、以下でさらに詳しく説明します。
context_item
, path_expression
[ AS
json_path_name
] [ PASSING
{ value
AS
varname
} [, ...]]
context_item
は問い合わせの入力ドキュメントを指定し、path_expression
は問い合わせを定義するSQL/JSONパス式であり、json_path_name
はpath_expression
のオプションの名前です。
オプションのPASSING
句は、path_expression
で言及されている変数にデータ値を提供します。
前述の要素を使用して入力データを評価した結果はrow patternと呼ばれ、構築されたビューの行値のソースとして使用されます。
COLUMNS
( json_table_column
[, ...] )
構築されたビューのスキーマを定義するCOLUMNS
句。
この句では、各列に対して、行パターンに対してJSONパス式を適用することによって得られるSQL/JSON値を指定できます。
json_table_column
には、次の種類があります。
name
FOR ORDINALITY
1から始まる連続した行番号を提供する序数列を追加します。
各NESTED PATH
(下記参照)は、ネストされた序数列に対してそれぞれ独自のカウンタを持ちます。
name
type
[FORMAT JSON
[ENCODING UTF8
]]
[ PATH
path_expression
]
指定されたtype
に強制変換した後、ビューの出力行にpath_expression
を適用して得られたSQL/JSON値を挿入します。
FORMAT JSON
を指定すると、値が有効なjson
オブジェクトであることが明示的に指定されます。
FORMAT JSON
を指定するのは、type
がbpchar
、bytea
、character varying
、name
、json
、jsonb
、text
、またはこれらの型のドメインのいずれかである場合に限られます。
オプションで、WRAPPER
とQUOTES
句を指定して出力をフォーマットすることもできます。
引用符なしのリテラルは有効なjson
値を構成しないため、QUOTES
を指定すると、FORMAT JSON
が上書きされることに注意してください。
オプションで、ON EMPTY
とON ERROR
句を使用して、JSONパス評価の結果が空の場合と、JSONパスの評価中あるいはSQL/JSON値を指定された型に強制変換したときにエラーが発生した場合に対して、エラーを発生するか、指定された値を返すかをそれぞれ指定できます。
どちらもデフォルトはNULL
です。
この句は内部的にJSON_VALUE
またはJSON_QUERY
と同じ意味になります。
後者は、指定された型がスカラ型でない場合、またはFORMAT JSON
、WRAPPER
、またはQUOTES
句のいずれかが存在する場合です。
name
type
EXISTS
[ PATH
path_expression
]
指定されたtype
に強制変換した後、ビューの出力行にpath_expression
を適用して得られたブール値を挿入します。
この値は、PATH
式を行パターンに適用した結果、値が生成されるかどうかに対応します。
指定されたtype
はboolean
型からのキャストを持つべきです。
オプションでON ERROR
を使用して、JSONパス評価中にエラーが発生した場合、またはSQL/JSON値を指定された型に強制変換した場合に、エラーを発生するか、指定された値を返すかを指定できます。
デフォルトは、ブール値FALSE
を返します。
この句は内部的にはJSON_EXISTS
と同じ意味に変換されます。
NESTED [ PATH ]
path_expression
[ AS
json_path_name
]
COLUMNS
( json_table_column
[, ...] )
行パターンのネストされたレベルからSQL/JSON値を抽出し、COLUMNS
副句で定義された1つ以上の列を生成し、それらの列に抽出されたSQL/JSON値を挿入します。
COLUMNS
副句のjson_table_column
式は、親のCOLUMNS
句と同じ構文を使用します。
NESTED PATH
構文は再帰的です。
したがって、複数のNESTED PATH
副構文を互いに指定することで、複数のネストされたレベルを下に移動できます。
これにより、SQL文内で複数のJSON_TABLE
式を連鎖させるのではなく、単一の関数呼び出しでJSONオブジェクトと配列の階層をネスト解除できます。
上記のjson_table_column
の各種類において、PATH
句が省略された場合、パス式$.
が使用されます。
ここで、name
name
は指定された列名です。
AS
json_path_name
オプションのjson_path_name
は、指定されたpath_expression
の識別子として機能します。
名前は一意でなければならず、列名と区別する必要があります。
ERROR
| EMPTY
} ON ERROR
オプションのON ERROR
は、最上位のpath_expression
を評価する際のエラー処理方法を指定するために使用できます。
エラーを発生する場合はERROR
を使用し、空のテーブル、つまり0行を含むテーブルを返す場合はEMPTY
を使用します。
この句は、列の評価時に発生するエラーには影響しないことに注意してください。
この場合の動作は、ON ERROR
句が指定された列に対して指定されているかどうかによって異なります。
Examples
以下の例では、次の表にJSONデータを含めます。
CREATE TABLE my_films ( js jsonb ); INSERT INTO my_films VALUES ( '{ "favorites" : [ { "kind" : "comedy", "films" : [ { "title" : "Bananas", "director" : "Woody Allen"}, { "title" : "The Dinner Game", "director" : "Francis Veber" } ] }, { "kind" : "horror", "films" : [ { "title" : "Psycho", "director" : "Alfred Hitchcock" } ] }, { "kind" : "thriller", "films" : [ { "title" : "Vertigo", "director" : "Alfred Hitchcock" } ] }, { "kind" : "drama", "films" : [ { "title" : "Yojimbo", "director" : "Akira Kurosawa" } ] } ] }');
次の問い合わせは、JSON_TABLE
を使用して、my_films
テーブル内のJSONオブジェクトを、通常の列を伴って元のJSONに含まれるキーkind
、title
、およびdirector
の列を含むビューに変換する方法を示しています。
SELECT jt.* FROM my_films, JSON_TABLE (js, '$.favorites[*]' COLUMNS ( id FOR ORDINALITY, kind text PATH '$.kind', title text PATH '$.films[*].title' WITH WRAPPER, director text PATH '$.films[*].director' WITH WRAPPER)) AS jt;
id | kind | title | director ----+----------+--------------------------------+---------------------------------- 1 | comedy | ["Bananas", "The Dinner Game"] | ["Woody Allen", "Francis Veber"] 2 | horror | ["Psycho"] | ["Alfred Hitchcock"] 3 | thriller | ["Vertigo"] | ["Alfred Hitchcock"] 4 | drama | ["Yojimbo"] | ["Akira Kurosawa"] (4 rows)
上記の問い合わせを次のように変更すると、トップレベルのJSONパス式で指定されたフィルタでPASSING
引数の使用方法と、個々の列に対するさまざまなオプションが表示されます。
SELECT jt.* FROM my_films, JSON_TABLE (js, '$.favorites[*] ? (@.films[*].director == $filter)' PASSING 'Alfred Hitchcock' AS filter, 'Vertigo' AS filter2 COLUMNS ( id FOR ORDINALITY, kind text PATH '$.kind', title text FORMAT JSON PATH '$.films[*].title' OMIT QUOTES, director text PATH '$.films[*].director' KEEP QUOTES)) AS jt;
id | kind | title | director ----+----------+---------+-------------------- 1 | horror | Psycho | "Alfred Hitchcock" 2 | thriller | Vertigo | "Alfred Hitchcock" (2 rows)
以下は、タイトルとディレクターの列を生成するためにNESTED PATH
を使用する上記の問い合わせの修正版で、親の列idとkindにどのように結合されるかを示しています。
SELECT jt.* FROM my_films, JSON_TABLE ( js, '$.favorites[*] ? (@.films[*].director == $filter)' PASSING 'Alfred Hitchcock' AS filter COLUMNS ( id FOR ORDINALITY, kind text PATH '$.kind', NESTED PATH '$.films[*]' COLUMNS ( title text FORMAT JSON PATH '$.title' OMIT QUOTES, director text PATH '$.director' KEEP QUOTES))) AS jt;
id | kind | title | director ----+----------+---------+-------------------- 1 | horror | Psycho | "Alfred Hitchcock" 2 | thriller | Vertigo | "Alfred Hitchcock" (2 rows)
次の問い合わせは、ルートパスにフィルタを指定しない場合と同じです。
SELECT jt.* FROM my_films, JSON_TABLE ( js, '$.favorites[*]' COLUMNS ( id FOR ORDINALITY, kind text PATH '$.kind', NESTED PATH '$.films[*]' COLUMNS ( title text FORMAT JSON PATH '$.title' OMIT QUOTES, director text PATH '$.director' KEEP QUOTES))) AS jt;
id | kind | title | director ----+----------+-----------------+-------------------- 1 | comedy | Bananas | "Woody Allen" 1 | comedy | The Dinner Game | "Francis Veber" 2 | horror | Psycho | "Alfred Hitchcock" 3 | thriller | Vertigo | "Alfred Hitchcock" 4 | drama | Yojimbo | "Akira Kurosawa" (5 rows)
次に異なるJSON
オブジェクトを入力として使用する別の問い合わせを示します。
これは、NESTED
パスである$.movies[*]
と$.books[*]
との間のUNION”兄弟結合”(sibling join)を示しています。
また、NESTED
レベルでのFOR ORDINALITY
列(列movie_id
、book_id
、およびauthor_id
)の使用を示しています。
SELECT * FROM JSON_TABLE ( '{"favorites": {"movies": [{"name": "One", "director": "John Doe"}, {"name": "Two", "director": "Don Joe"}], "books": [{"name": "Mystery", "authors": [{"name": "Brown Dan"}]}, {"name": "Wonder", "authors": [{"name": "Jun Murakami"}, {"name":"Craig Doe"}]}] }}'::json, '$.favorites[*]' COLUMNS ( user_id FOR ORDINALITY, NESTED '$.movies[*]' COLUMNS ( movie_id FOR ORDINALITY, mname text PATH '$.name', director text), NESTED '$.books[*]' COLUMNS ( book_id FOR ORDINALITY, bname text PATH '$.name', NESTED '$.authors[*]' COLUMNS ( author_id FOR ORDINALITY, author_name text PATH '$.name'))));
user_id | movie_id | mname | director | book_id | bname | author_id | author_name ---------+----------+-------+----------+---------+---------+-----------+-------------- 1 | 1 | One | John Doe | | | | 1 | 2 | Two | Don Joe | | | | 1 | | | | 1 | Mystery | 1 | Brown Dan 1 | | | | 2 | Wonder | 1 | Jun Murakami 1 | | | | 2 | Wonder | 2 | Craig Doe (5 rows)