本節描述
處理和建立 JSON 資料的函式和運算子
SQL/JSON 路徑語言
SQL/JSON 查詢函式
為了在 SQL 環境中提供對 JSON 資料型別的原生支援,PostgreSQL 實現了SQL/JSON 資料模型。該模型包含一系列項。每個項可以儲存 SQL 標量值,以及一個附加的 SQL/JSON 空值,以及使用 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.47 顯示了可用於 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.47。json 和 jsonb 運算子
|
運算子 描述 示例 |
|---|
|
提取 JSON 陣列的第
|
|
提取具有給定鍵的 JSON 物件欄位。
|
|
提取 JSON 陣列的第
|
|
提取具有給定鍵的 JSON 物件欄位,作為
|
|
在指定路徑提取 JSON 子物件,其中路徑元素可以是欄位鍵或陣列索引。
|
|
將指定路徑的 JSON 子物件提取為
|
如果 JSON 輸入不具有與請求匹配的正確結構,例如不存在此類鍵或陣列元素,則欄位/元素/路徑提取運算子返回 NULL,而不是失敗。
如 表 9.48 所示,還有一些運算子僅適用於 jsonb。第 8.14.4 節 描述瞭如何使用這些運算子有效地搜尋索引的 jsonb 資料。
表 9.48。附加 jsonb 運算子
|
運算子 描述 示例 |
|---|
|
第一個 JSON 值是否包含第二個?(有關包含的詳細資訊,請參閱 第 8.14.3 節。)
|
|
第一個 JSON 值是否包含在第二個中?
|
|
文字字串作為頂層鍵或陣列元素是否存在於 JSON 值中?
|
|
文字陣列中的任何字串作為頂層鍵或陣列元素是否存在?
|
|
文字陣列中的所有字串作為頂層鍵或陣列元素是否存在?
|
|
連線兩個
要將一個數組作為單個條目附加到另一個數組,請將其包裝在額外的陣列層中,例如
|
|
從 JSON 物件中刪除一個鍵(及其值),或從 JSON 陣列中刪除匹配的字串值。
|
|
從左運算元中刪除所有匹配的鍵或陣列元素。
|
|
刪除具有指定索引的陣列元素(負整數從末尾開始計數)。如果 JSON 值不是陣列,則丟擲錯誤。
|
|
刪除指定路徑處的欄位或陣列元素,其中路徑元素可以是欄位鍵或陣列索引。
|
|
JSON 路徑是否為指定的 JSON 值返回任何項?(這僅對 SQL 標準 JSON 路徑表示式有用,對謂詞檢查表示式無效,因為它們總是返回一個值。)
|
|
返回指定 JSON 值的 JSON 路徑謂詞檢查結果。(這僅對謂詞檢查表示式有用,對 SQL 標準 JSON 路徑表示式無效,因為如果路徑結果不是單個布林值,它將返回
|
jsonpath 運算子 @? 和 @@ 抑制以下錯誤:缺少物件欄位或陣列元素、意外的 JSON 項型別、日期時間或數字錯誤。下面描述的 jsonpath 相關函式也可以被告知抑制這些型別的錯誤。這種行為在搜尋結構不同的 JSON 文件集合時可能會有所幫助。
表 9.49 顯示了可用於構造 json 和 jsonb 值的函式。此表中的某些函式具有 RETURNING 子句,該子句指定返回的資料型別。它必須是 json、jsonb、bytea、字元字串型別(text、char 或 varchar),或可以轉換為 json 的型別之一。預設情況下,返回 json 型別。
表 9.49。JSON 建立函式
|
函式 描述 示例 |
|---|
|
將任何 SQL 值轉換為
|
|
將 SQL 陣列轉換為 JSON 陣列。行為與
|
|
從一系列
|
|
將 SQL 複合值轉換為 JSON 物件。行為與
|
|
從可變引數列表構建一個可能異構型別的 JSON 陣列。每個引數都按照
|
|
從可變引數列表構建一個 JSON 物件。按照慣例,引數列表由交替的鍵和值組成。鍵引數被強制轉換為文字;值引數按照
|
|
構造一個包含所有給定鍵/值對的 JSON 物件,如果沒有給定則為空物件。
|
|
從文字陣列構建 JSON 物件。陣列必須具有恰好一個維度且成員數為偶數,在這種情況下,它們被視為交替的鍵/值對,或者兩個維度,使得每個內部陣列恰好有兩個元素,它們被視為鍵/值對。所有值都轉換為 JSON 字串。
|
|
此形式的
|
|
將指定為
|
|
將給定的 SQL 標量值轉換為 JSON 標量值。如果輸入為 NULL,則返回一個SQLnull。如果輸入是數字或布林值,則返回相應的 JSON 數字或布林值。對於任何其他值,返回 JSON 字串。
|
|
將 SQL/JSON 表示式轉換為字元或二進位制字串。
|
表 9.50 詳細介紹了用於測試 JSON 的 SQL/JSON 工具。
表 9.50。SQL/JSON 測試函式
表 9.51 顯示了可用於處理 json 和 jsonb 值的函式。
表 9.51。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 值的物件欄位。如果
|
|
檢查 JSON 路徑是否為指定的 JSON 值返回任何項。(這僅對 SQL 標準 JSON 路徑表示式有用,對謂詞檢查表示式無效,因為它們總是返回一個值。)如果指定了
|
|
返回指定 JSON 值的 JSON 路徑謂詞檢查的 SQL 布林結果。(這僅對謂詞檢查表示式有用,對 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
有關在路徑表示式中使用 jsonpath 運算子和方法的更多示例,請參見下面的 第 9.16.2.3 節。
路徑還可以包含篩選表示式,其工作方式類似於 SQL 中的 WHERE 子句。篩選表示式以問號開頭,並在括號中提供條件
? (condition)
篩選表示式必須緊接在其應應用的路徑評估步驟之後編寫。該步驟的結果將經過篩選,只包含滿足所提供條件的項。SQL/JSON 定義了三值邏輯,因此條件可以生成 true、false 或 unknown。unknown 值的作用與 SQL NULL 相同,可以使用 is unknown 謂詞進行測試。進一步的路徑評估步驟只使用篩選表示式返回 true 的那些項。
可在篩選表示式中使用的函式和運算子列在 表 9.53 中。在篩選表示式中,@ 變量表示正在考慮的值(即,前一個路徑步驟的一個結果)。您可以在 @ 之後編寫訪問器運算子以檢索元件項。
例如,假設您想檢索所有高於 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 值中的相關元素,而謂詞檢查表示式返回謂詞的單個三值 jsonb 結果:true、false 或 null。例如,我們可以這樣編寫 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 函式)一起使用。
like_regex 篩選器中使用的正則表示式模式的解釋存在細微差別,如 第 9.16.2.4 節中所述。
當您查詢 JSON 資料時,路徑表示式可能與實際的 JSON 資料結構不匹配。嘗試訪問物件中不存在的成員或陣列中不存在的元素被定義為結構錯誤。SQL/JSON 路徑表示式有兩種處理結構錯誤的方式
寬鬆模式(預設)——路徑引擎隱式地將查詢資料適應指定的路徑。任何無法按如下所述修復的結構錯誤都將被抑制,不產生匹配。
嚴格模式——如果發生結構錯誤,則會引發錯誤。
當 JSON 資料不符合預期模式時,寬鬆模式有助於匹配 JSON 文件和路徑表示式。如果運算元不符合特定操作的要求,它可以透過將其元素轉換為 SQL/JSON 序列來自動封裝為 SQL/JSON 陣列,或在執行操作之前解封裝。此外,在寬鬆模式下,比較運算子會自動解封裝其運算元,因此您可以直接比較 SQL/JSON 陣列。大小為 1 的陣列被視為與其唯一元素相等。在以下情況下不執行自動解封裝
路徑表示式包含 type() 或 size() 方法,它們分別返回陣列的型別和元素數量。
查詢的 JSON 資料包含巢狀陣列。在這種情況下,只有最外層陣列被解封裝,而所有內部陣列保持不變。因此,隱式解封裝在每個路徑評估步驟中只能向下進行一級。
例如,當查詢上述 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 值兩次
=>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)
儘管路徑表示式選擇了完整的陣列。使用嚴格模式恢復選擇陣列
=>select jsonb_path_query(:'json', 'strict $.track.segments[*].location ?(@[*] > 15)');jsonb_path_query ------------------- [47.763, 13.4034] [47.706, 13.2635] (2 rows)
表 9.52 顯示了 jsonpath 中可用的運算子和方法。請注意,雖然一元運算子和方法可以應用於前一個路徑步驟產生的多個值,但二元運算子(加法等)只能應用於單個值。在寬鬆模式下,應用於陣列的方法將對陣列中的每個值執行。例外是 .type() 和 .size(),它們應用於陣列本身。
表 9.52. 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.53 顯示了可用的篩選表示式元素。
表 9.53. 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 運算子的正則表示式定義,而該運算子又使用 XQuery 標準。PostgreSQL 目前不支援 LIKE_REGEX 運算子。因此,like_regex 篩選器是使用 第 9.7.3 節中描述的 POSIX 正則表示式引擎實現的。這導致與標準 SQL/JSON 行為存在各種細微差異,這些差異在 第 9.7.3.8 節中進行了分類。但是請注意,其中描述的標誌字母不相容性不適用於 SQL/JSON,因為它將 XQuery 標誌字母轉換為與 POSIX 引擎期望的匹配。
請記住,like_regex 的模式引數是一個 JSON 路徑字串字面量,根據 第 8.14.7 節中給出的規則編寫。這意味著,特別是您想在正則表示式中使用的任何反斜槓都必須加倍。例如,要匹配根文件中僅包含數字的字串值
$.* ? (@ like_regex "^\\d+$")
表 9.54 中描述的 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.54. 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 子句進行處理。
JSON_VALUE() 在 path_expression 返回 JSON null 時返回 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 [ AS json_path_name ] [ PASSING { value AS varname } [, ...] ]
COLUMNS ( json_table_column [, ...] )
[ { ERROR | EMPTY [ARRAY]} ON ERROR ]
)
where json_table_column is:
name FOR ORDINALITY
| name type
[ FORMAT JSON [ENCODING UTF8]]
[ PATH path_expression ]
[ { WITHOUT | WITH { CONDITIONAL | [UNCONDITIONAL] } } [ ARRAY ] WRAPPER ]
[ { KEEP | OMIT } QUOTES [ ON SCALAR STRING ] ]
[ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULT expression } ON EMPTY ]
[ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULT expression } ON ERROR ]
| name type EXISTS [ PATH path_expression ]
[ { ERROR | TRUE | FALSE | UNKNOWN } ON ERROR ]
| NESTED [ PATH ] path_expression [ AS json_path_name ] COLUMNS ( json_table_column [, ...] )
每個語法元素都將在下面更詳細地描述。
上下文項, 路徑表示式 [ AS json_path_name ] [ PASSING { 值 AS 變數名 } [, ...]]context_item 指定要查詢的輸入文件,path_expression 是一個定義查詢的 SQL/JSON 路徑表示式,而 json_path_name 是 path_expression 的可選名稱。可選的 PASSING 子句為 path_expression 中提到的變數提供資料值。使用上述元素評估輸入資料的結果稱為行模式,它用作構造檢視中行值的源。
COLUMNS ( json_table_column [, ...] )COLUMNS 子句定義了構造檢視的模式。在此子句中,您可以指定每個列都將填充一個 SQL/JSON 值,該值是透過將 JSON 路徑表示式應用於行模式後獲得的。json_table_column 具有以下變體
名稱 FOR ORDINALITY新增一個序號列,提供從 1 開始的順序行編號。每個 NESTED PATH(參見下文)都會為其任何巢狀序號列獲取自己的計數器。
名稱 型別 [FORMAT JSON [ENCODING UTF8]] [ PATH 路徑表示式 ]將透過對行模式應用 path_expression 獲得的 SQL/JSON 值在強制轉換為指定的 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 子句,則為後者。
名稱 型別 EXISTS [ PATH 路徑表示式 ]將透過對行模式應用 path_expression 獲得的布林值在強制轉換為指定的 type 後插入到檢視的輸出行中。
該值對應於將 PATH 表示式應用於行模式是否產生任何值。
指定的 type 應該可以從 boolean 型別進行轉換。
可選地,您可以使用 ON ERROR 指定在 JSON 路徑評估期間或將 SQL/JSON 值強制轉換為指定型別時發生錯誤時是丟擲錯誤還是返回指定值。預設是返回布林值 FALSE。
此子句在內部轉換為 JSON_EXISTS,並具有相同的語義。
NESTED [ PATH ] 路徑表示式 [ 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 子句,則使用路徑表示式 $.,其中 namename 是提供的列名。
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
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 級別使用 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)
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的內容,請使用 此表單 報告文件問題。