本節描述
處理與建立 JSON 資料的函數與運算子
SQL/JSON 路徑語言
SQL/JSON 查詢函數
為了在 SQL 環境中提供對 JSON 資料類型的原生支援,PostgreSQL 實作了SQL/JSON 資料模型。此模型包含項目序列。每個項目可以保存 SQL 純量值,以及額外的 SQL/JSON null 值,以及使用 JSON 陣列和物件的複合資料結構。該模型是 JSON 規範 RFC 7159 中隱含資料模型的形式化。
SQL/JSON 允許您處理 JSON 資料以及正規的 SQL 資料,並提供交易支援,包括
將 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 樹運算的排序規則。另請參閱 第 9.21 節,瞭解將記錄值彙總為 JSON 的彙總函數 json_agg
,將數值對彙總為 JSON 物件的彙總函數 json_object_agg
,以及它們的 jsonb
對應物 jsonb_agg
和 jsonb_object_agg
。
表 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 值中?
|
該文字字串是否存在於 JSON 值中的最上層鍵或陣列元素?
|
文字陣列中的任何字串是否存在於最上層鍵或陣列元素中?
|
文字陣列中的所有字串是否存在於最上層鍵或陣列元素中?
|
串聯兩個
若要將陣列作為單一條目附加到另一個陣列,請將其包裝在額外的陣列層中,例如
|
從 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 陣列。其行為與
|
從一系列的
|
將 SQL 複合值轉換為 JSON 物件。其行為與
|
從可變參數清單建構一個可能具有異質型別的 JSON 陣列。每個參數都會依照
|
從可變參數清單建構一個 JSON 物件。 依照慣例,參數清單由交替的鍵和值組成。 鍵參數會強制轉換為文字;值參數會依照
|
建構一個包含所有給定的鍵/值配對的 JSON 物件,如果沒有給定任何配對,則建構一個空物件。
|
從文字陣列建構一個 JSON 物件。 陣列必須只有一個維度且成員數為偶數,在這種情況下,它們會被視為交替的鍵/值配對,或者具有兩個維度,且每個內部陣列恰好有兩個元素,這些元素會被視為鍵/值配對。 所有值都會轉換為 JSON 字串。
|
此形式的
|
將指定的表示式(以 UTF8 編碼的
|
將指定的 SQL 純量值轉換為 JSON 純量值。如果輸入為 NULL,則會回傳SQLnull。如果輸入為數字或布林值,則會回傳對應的 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 值中遞迴刪除所有具有空值的物件欄位。不是物件欄位的空值保持不變。
|
檢查 JSON 路徑是否為指定的 JSON 值傳回任何項目。(這僅適用於 SQL 標準 JSON 路徑表達式,而不適用於 述詞檢查表達式,因為這些表達式始終會傳回一個值。)如果指定了
|
傳回指定 JSON 值的 JSON 路徑述詞檢查結果。(這僅適用於 述詞檢查表達式,而不適用於 SQL 標準 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 路徑表達式指定要從 JSON 值中擷取的項目,類似於用於存取 XML 內容的 XPath 表達式。在 PostgreSQL 中,路徑表達式以 jsonpath
資料類型實作,並且可以使用第 8.14.7 節中描述的任何元素。
JSON 查詢函數和運算子將提供的路徑表達式傳遞給路徑引擎以進行評估。如果表達式與查詢的 JSON 資料匹配,則會傳回對應的 JSON 項目或項目集。如果沒有匹配項,則結果將為 NULL
、false
或錯誤,具體取決於函數。路徑表達式以 SQL/JSON 路徑語言編寫,並且可以包含算術表達式和函數。
路徑表達式包含一個由 jsonpath
資料類型所允許的元素序列。路徑表達式通常從左到右求值,但您可以使用括號來更改運算順序。如果求值成功,則會產生一個 JSON 項目序列,並且求值結果會傳回給完成指定計算的 JSON 查詢函數。
若要引用正在查詢的 JSON 值(上下文項目),請在路徑表達式中使用 $
變數。路徑的第一個元素必須始終是 $
。它可以後跟一個或多個存取器運算子,這些運算子逐層下降 JSON 結構,以檢索上下文項目的子項目。每個存取器運算子都會作用於前一個求值步驟的結果,從每個輸入項目產生零個、一個或多個輸出項目。
例如,假設您有一些來自 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
以下第 9.16.2.3 節中提供了在路徑表達式中使用 jsonpath
運算子和方法的更多範例。
路徑還可以包含過濾器表達式,其工作方式類似於 SQL 中的 WHERE
子句。過濾器表達式以問號開頭,並在括號中提供一個條件:
? (condition
)
過濾器表達式必須寫在它們應用的路徑求值步驟之後。該步驟的結果會被過濾,僅包含滿足所提供條件的項目。SQL/JSON 定義了三值邏輯,因此條件可以產生 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 值的相關元素,但述詞檢查表達式會傳回述詞的單個三值結果: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
函數)一起使用。
在 第 9.16.2.4 節中描述的 like_regex
過濾器中使用的正則表達式模式的解釋存在細微差異。
當您查詢 JSON 資料時,路徑表達式可能與實際的 JSON 資料結構不符。嘗試存取物件的不存在的成員或陣列的元素被定義為結構錯誤。SQL/JSON 路徑表達式有兩種處理結構錯誤的模式:
lax (預設) — 路徑引擎會隱式地將查詢到的資料調整為指定的路徑。任何無法按照下述方式修正的結構性錯誤都會被抑制,產生不匹配的結果。
strict — 如果發生結構性錯誤,則會引發錯誤。
當 JSON 資料不符合預期 schema 時,Lax 模式有助於匹配 JSON 文件和路徑表達式。如果運算元不符合特定操作的要求,則可以將其自動包裝為 SQL/JSON 陣列,或通過將其元素轉換為 SQL/JSON 序列來解包,然後再執行操作。此外,比較運算符在 lax 模式下會自動解包其運算元,因此您可以直接比較 SQL/JSON 陣列。大小為 1 的陣列被認為等於其唯一元素。在以下情況下,不會執行自動解包:
路徑表達式包含 type()
或 size()
方法,這些方法分別傳回陣列中的類型和元素數量。
查詢的 JSON 資料包含巢狀陣列。在這種情況下,只會解包最外層的陣列,而所有內層陣列保持不變。因此,隱式解包在每個路徑評估步驟中只能向下執行一個層級。
例如,在查詢上面列出的 GPS 資料時,您可以使用 lax 模式,無需考慮它儲存的是一個 segments 陣列的事實。
=>
select jsonb_path_query(:'json', 'lax $.track.segments.location');
jsonb_path_query ------------------- [47.763, 13.4034] [47.706, 13.2635]
在 strict 模式下,指定的路徑必須完全匹配查詢的 JSON 文件的結構,因此使用此路徑表達式會導致錯誤。
=>
select jsonb_path_query(:'json', 'strict $.track.segments.location');
ERROR: jsonpath member accessor can only be applied to an object
要獲得與 lax 模式相同的結果,您必須顯式地解包 segments
陣列。
=>
select jsonb_path_query(:'json', 'strict $.track.segments[*].location');
jsonb_path_query ------------------- [47.763, 13.4034] [47.706, 13.2635]
lax 模式的解包行為可能會導致令人驚訝的結果。例如,以下使用 .**
存取器的查詢會選擇每個 HR
值兩次。
=>
select jsonb_path_query(:'json', 'lax $.**.HR');
jsonb_path_query ------------------ 73 135 73 135
發生這種情況的原因是 .**
存取器同時選擇 segments
陣列及其每個元素,而 .HR
存取器在使用 lax 模式時會自動解包陣列。為了避免令人驚訝的結果,我們建議僅在 strict 模式下使用 .**
存取器。以下查詢僅選擇每個 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)
儘管完整的陣列是由路徑表達式選定的。使用 strict 模式來恢復選擇陣列。
=>
select jsonb_path_query(:'json', 'strict $.track.segments[*].location ?(@[*] > 15)');
jsonb_path_query ------------------- [47.763, 13.4034] [47.706, 13.2635] (2 rows)
Table 9.50 顯示了 jsonpath
中可用的運算符和方法。請注意,雖然一元運算符和方法可以應用於來自先前路徑步驟的多個值,但二元運算符(加法等)只能應用於單個值。在 lax 模式下,應用於陣列的方法將對陣列中的每個值執行。例外情況是 .type()
和 .size()
,它們應用於陣列本身。
Table 9.50. jsonpath
運算符和方法
運算符/方法 描述 範例 |
---|
加法
|
一元加號(無操作);與加法不同,它可以迭代多個值
|
減法
|
否定;與減法不同,它可以迭代多個值
|
乘法
|
除法
|
模數(餘數)
|
JSON 項目的類型(請參閱
|
JSON 項目的尺寸(陣列元素的數量,如果不是陣列則為 1)
|
從 JSON 布林值、數字或字串轉換而來的布林值
|
從 JSON 布林值、數字、字串或日期時間轉換而來的字串值
|
從 JSON 數字或字串轉換而來的近似浮點數
|
大於或等於給定數字的最近整數
|
小於或等於給定數字的最近整數
|
給定數字的絕對值
|
從 JSON 數字或字串轉換而來的大整數值
|
從 JSON 數字或字串轉換而來的四捨五入小數值(
|
從 JSON 數字或字串轉換而來的整數值
|
從 JSON 數字或字串轉換而來的數值
|
從字串轉換而來的日期/時間值
|
使用指定的
|
從字串轉換而來的日期值
|
從字串轉換而來的無時區時間值
|
從字串轉換而來的無時區時間值,小數秒調整為給定的精度
|
從字串轉換而來的有時區時間值
|
從字串轉換而來的有時區時間值,小數秒調整為給定的精度
|
從字串轉換而來的無時區時間戳記值
|
從字串轉換而來的無時區時間戳記值,小數秒調整為給定的精度
|
從字串轉換而來的有時區時間戳記值
|
從字串轉換而來的有時區時間戳記值,小數秒調整為給定的精度
|
物件的鍵值對,表示為包含三個欄位的物件陣列:
|
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 節),但有三個例外。首先,這些方法不允許不匹配的樣板模式。第二,樣板字串中僅允許以下分隔符號:減號、句點、斜線(斜杠)、逗號、單引號、分號、冒號和空格。第三,樣板字串中的分隔符號必須與輸入字串完全匹配。
如果需要比較不同的日期/時間類型,會套用隱含轉換。 date
值可以轉換為 timestamp
或 timestamptz
,timestamp
可以轉換為 timestamptz
,time
可以轉換為 timetz
。然而,除了第一種轉換外,其他轉換都取決於目前的 TimeZone 設定,因此只能在感知時區的 jsonpath
函數中執行。同樣地,其他將字串轉換為日期/時間類型的方法也會進行這種轉換,這可能涉及到目前的 TimeZone 設定。因此,這些轉換也只能在感知時區的 jsonpath
函數中執行。
表 9.51 顯示了可用的過濾器運算式元素。
表 9.51. jsonpath
過濾器運算式元素
述詞/值 描述 範例 |
---|
相等比較(此運算子以及其他比較運算子適用於所有 JSON 純量值)
|
不相等比較
|
小於比較
|
小於或等於比較
|
大於比較
|
大於或等於比較
|
JSON 常數
|
JSON 常數
|
JSON 常數
|
布林 AND
|
布林 OR
|
布林 NOT
|
測試布林條件是否為
|
測試第一個運算元是否符合第二個運算元給定的正規表示式,可選擇性地使用由
|
測試第二個運算元是否為第一個運算元的初始子字串。
|
測試路徑運算式是否符合至少一個 SQL/JSON 項目。如果路徑運算式會導致錯誤,則傳回
|
SQL/JSON 路徑表達式允許使用 like_regex
篩選器將文字與正規表示式進行匹配。例如,以下 SQL/JSON 路徑查詢會以不區分大小寫的方式匹配陣列中所有以英文母音開頭的字串
$[*] ? (@ like_regex "^[aeiou]" flag "i")
可選的 flag
字串可以包含以下一個或多個字元:i
表示不區分大小寫匹配,m
允許 ^
和 $
在換行符處匹配,s
允許 .
匹配換行符,以及 q
引用整個模式(將行為簡化為簡單的子字串匹配)。
SQL/JSON 標準從 LIKE_REGEX
運算子借用了正規表示式的定義,而 LIKE_REGEX
運算子又使用了 XQuery 標準。PostgreSQL 目前不支援 LIKE_REGEX
運算子。因此,like_regex
篩選器是使用 第 9.7.3 節 中描述的 POSIX 正規表示式引擎實作的。這導致與標準 SQL/JSON 行為存在各種微小的差異,這些差異在 第 9.7.3.8 節 中進行了編目。但是請注意,那裡描述的旗標字母不相容性不適用於 SQL/JSON,因為它會轉換 XQuery 旗標字母以匹配 POSIX 引擎期望的內容。
請記住,like_regex
的 pattern 參數是一個 JSON 路徑字串常值,根據 第 8.14.7 節 中給出的規則編寫。這尤其意味著您想在正規表示式中使用的任何反斜線都必須加倍。例如,要匹配僅包含數字的根文件字串值
$.* ? (@ 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
傳回 JSON null
,則 JSON_VALUE()
會傳回 SQL NULL,而 JSON_QUERY()
會原樣傳回 JSON null
。
JSON_TABLE
是一個 SQL/JSON 函數,用於查詢JSON資料並將結果呈現為關聯式檢視,可以像存取常規 SQL 表一樣存取。您可以在 SELECT
、UPDATE
或 DELETE
的 FROM
子句中使用 JSON_TABLE
,並在 MERGE
陳述式中作為資料來源。
以 JSON 資料作為輸入,JSON_TABLE
使用 JSON 路徑運算式來提取提供的資料的一部分,以用作建構檢視的資料列模式。資料列模式給出的每個 SQL/JSON 值都充當建構檢視中單獨資料列的來源。
為了將資料列模式分割為欄位,JSON_TABLE
提供了 COLUMNS
子句,用於定義建立的檢視的綱要。對於每個欄位,可以指定單獨的 JSON 路徑運算式,以針對資料列模式進行評估,以取得一個 SQL/JSON 值,該值將成為給定輸出資料列中指定欄位的值。
可以使用 NESTED PATH
子句提取儲存在資料列模式的巢狀層級的 JSON 資料。每個 NESTED PATH
子句可用於使用資料列模式的巢狀層級的資料來產生一個或多個欄位。可以使用類似於頂層 COLUMNS 子句的 COLUMNS
子句來指定這些欄位。由 NESTED COLUMNS 建構的資料列稱為子資料列,並與從父 COLUMNS
子句中指定的欄位建構的資料列聯結,以取得最終檢視中的資料列。子欄位本身可能包含 NESTED PATH
規格,從而允許提取位於任意巢狀層級的資料。由同一層級的多個 NESTED PATH
產生的欄位被認為是彼此的同層級,並且它們在與父資料列聯結後的資料列使用 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
] ) wherejson_table_column
is: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
中提到的變數提供資料值。使用上述元素評估輸入資料的結果稱為資料列模式,該模式用作建構檢視中資料列值的來源。
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
]
將 SQL/JSON 值插入到檢視的輸出資料列中,該值是透過將 path_expression
應用於資料列模式後,強制轉換為指定的 type
而獲得的。
指定 FORMAT JSON
可以明確表示您期望該值是有效的 json
物件。僅當 type
是 bpchar
、bytea
、character varying
、name
、json
、jsonb
、text
之一,或這些類型的網域時,指定 FORMAT JSON
才是有意義的。
您可以選擇指定 WRAPPER
和 QUOTES
子句來格式化輸出。請注意,如果也指定了 OMIT QUOTES
,則會覆蓋 FORMAT JSON
,因為未加引號的文字不構成有效的 json
值。
您可以選擇使用 ON EMPTY
和 ON ERROR
子句來指定在 JSON 路徑評估的結果為空時,以及在 JSON 路徑評估期間或將 SQL/JSON 值強制轉換為指定類型時發生錯誤時,是否拋出錯誤或傳回指定的值。兩者的預設值都是傳回 NULL
值。
此子句在內部轉換為 JSON_VALUE
或 JSON_QUERY
,並具有相同的語意。如果指定的類型不是純量類型,或者存在 FORMAT JSON
、WRAPPER
或 QUOTES
子句中的任何一個,則後者是 JSON_QUERY
。
name
type
EXISTS
[ PATH
path_expression
]插入一個布林值,該值是將 path_expression
套用至列模式後,強制轉換為指定的 type
後,插入到檢視表的輸出列中。
該值對應於將 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
子句定義的一或多個欄位,並將提取的 SQL/JSON 值插入到這些欄位中。COLUMNS
子句中的 json_table_column
表達式使用與父 COLUMNS
子句中相同的語法。
NESTED PATH
語法是遞迴的,因此您可以透過在彼此之間指定多個 NESTED PATH
子句,向下移動多個巢狀層級。它允許在單個函數呼叫中解開 JSON 物件和陣列的階層,而不是在 SQL 語句中鏈接多個 JSON_TABLE
表達式。
在上面描述的每個 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
子句。
範例
在下面的範例中,將使用包含 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「同級聯結」,以及在 NESTED
層級 (欄位 movie_id
、book_id
和 author_id
) 使用 FOR ORDINALITY
欄位
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)
如果您在文件中發現任何不正確、與特定功能的體驗不符或需要進一步澄清的地方,請使用此表單來回報文件問題。