2025年9月25日: PostgreSQL 18 釋出!
支援的版本: 當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2

8.14. JSON型別 #

JSON 資料型別用於儲存 JSON (JavaScript Object Notation) 資料,如 RFC 7159 中所指定。此類資料也可以儲存為 text,但 JSON 資料型別具有強制要求每個儲存的值都符合 JSON 規則的優點。這些資料型別還提供了各種 JSON 特定函式和運算子;請參閱 第 9.16 節

PostgreSQL 提供兩種儲存 JSON 資料的資料型別:jsonjsonb。為了實現這些資料型別的有效查詢機制,PostgreSQL 還提供了 第 8.14.7 節 中描述的 jsonpath 資料型別。

jsonjsonb 資料型別在輸入時接受幾乎相同的數值集。主要的實際區別在於效率。json 資料型別儲存輸入的文字的精確副本,處理函式必須在每次執行時重新解析;而 jsonb 資料以分解的二進位制格式儲存,由於增加了轉換開銷,輸入時稍慢,但處理速度顯著提高,因為不需要重新解析。jsonb 還支援索引,這可能是一個重要的優勢。

由於 json 型別儲存輸入的文字的精確副本,因此它會保留令牌之間的語義上不重要的空格,以及 JSON 物件中鍵的順序。此外,如果值中的 JSON 物件包含多個相同的鍵,則會保留所有鍵/值對。(處理函式將最後一個值視為有效的。)相比之下,jsonb 不會保留空格,也不會保留物件鍵的順序,也不會保留重複的物件鍵。如果輸入中指定了重複的鍵,則只保留最後一個值。

通常,大多數應用程式應傾向於將 JSON 資料儲存為 jsonb,除非有非常特殊的需求,例如對物件鍵排序的遺留假設。

RFC7159 指定 JSON 字串應使用 UTF8 編碼。因此,除非資料庫編碼為 UTF8,否則 JSON 型別無法嚴格遵守 JSON 規範。嘗試直接包含資料庫編碼無法表示的字元將失敗;相反,允許表示為資料庫編碼但無法在 UTF8 中表示的字元。

RFC7159 允許 JSON 字串包含由 \uXXXX 表示的 Unicode 轉義序列。在 json 型別的輸入函式中,無論資料庫編碼如何,都允許使用 Unicode 轉義,並且僅檢查語法正確性(即,\u 後面是四個十六進位制數字)。但是,jsonb 的輸入函式更嚴格:它不允許使用資料庫編碼無法表示的字元的 Unicode 轉義。jsonb 型別還會拒絕 \u0000(因為這在 PostgreSQLtext 型別中無法表示),並且它堅持要求使用 Unicode 代理對來表示 Unicode 基本多語言平面之外的字元時必須正確。有效的 Unicode 轉義將被轉換為等效的單個字元進行儲存;這包括將代理對摺疊成單個字元。

注意

第 9.16 節 中描述的許多 JSON 處理函式會將 Unicode 轉義轉換為普通字元,因此即使它們的輸入型別是 json 而不是 jsonb,也會丟擲與上述相同的錯誤。事實上,json 輸入函式不執行這些檢查可能被視為歷史遺留,儘管它允許在不支援所表示字元的資料庫編碼中簡單地儲存(不處理)JSON Unicode 轉義。

將文字 JSON 輸入轉換為 jsonb 時,7159 所描述的原始型別有效地對映到本地 PostgreSQL 型別,如 表 8.23 所示。因此,對於什麼是有效的 jsonb 資料,存在一些與 json 型別或抽象的 JSON 不適用的輕微附加限制,這對應於底層資料型別所能表示的內容的限制。尤其值得注意的是,jsonb 會拒絕超出 PostgreSQL numeric 資料類型範圍的數字,而 json 不會。7159 允許此類實現定義的限制。然而,實際上,這類問題在其他實現中出現的可能性要大得多,因為通常將 JSON 的 number 原始型別表示為 IEEE 754 雙精度浮點數(7159 明確預期並允許)。在與其他系統使用 JSON 作為交換格式時,應考慮與 PostgreSQL 最初儲存的資料相比,丟失數值精度的風險。RFC7159 允許 JSON 字串包含 Unicode 轉義序列,表示為 \uXXXX。在 json 型別的輸入函式中,Unicode 轉義允許,而不考慮資料庫編碼,並且僅在語法上進行檢查(即,\u 後面是四個十六進位制數字)。然而,jsonb 的輸入函式更嚴格:它不允許使用資料庫編碼無法表示的字元的 Unicode 轉義。jsonb 型別還會拒絕 \u0000(因為這在 PostgreSQLtext 型別中無法表示),並且它堅持要求使用 Unicode 代理對來表示 Unicode 基本多語言平面之外的字元時必須正確。有效的 Unicode 轉義將被轉換為等效的單個字元進行儲存;這包括將代理對摺疊成單個字元。RFC7159 允許 JSON 字串包含 Unicode 轉義序列,表示為 \uXXXX。在 json 型別的輸入函式中,Unicode 轉義允許,而不考慮資料庫編碼,並且僅在語法上進行檢查(即,\u 後面是四個十六進位制數字)。然而,jsonb 的輸入函式更嚴格:它不允許使用資料庫編碼無法表示的字元的 Unicode 轉義。jsonb 型別還會拒絕 \u0000(因為這在 PostgreSQLtext 型別中無法表示),並且它堅持要求使用 Unicode 代理對來表示 Unicode 基本多語言平面之外的字元時必須正確。有效的 Unicode 轉義將被轉換為等效的單個字元進行儲存;這包括將代理對摺疊成單個字元。RFC7159 明確預期並允許 JSON 的 number 原始型別表示為 IEEE 754 雙精度浮點數。當使用 JSON 作為與其他系統交換格式時,應考慮與 PostgreSQL 最初儲存的資料相比,丟失數值精度的風險。

相反,如表中所示,JSON 原始型別的輸入格式存在一些輕微限制,而這些限制不適用於相應的 PostgreSQL 型別。

表 8.23. JSON 原始型別和相應的 PostgreSQL 型別

JSON 原始型別 PostgreSQL 型別 註釋
string text \u0000 不允許,包含表示資料庫編碼中不可用字元的 Unicode 轉義也不允許
number numeric NaNinfinity 值不允許
boolean boolean 僅接受小寫的 truefalse 拼寫
null (無) SQL NULL 是一個不同的概念

8.14.1. JSON 輸入和輸出語法 #

JSON 資料型別的輸入/輸出語法如RFC 7159.

以下均為有效的 json(或 jsonb)表示式

-- Simple scalar/primitive value
-- Primitive values can be numbers, quoted strings, true, false, or null
SELECT '5'::json;

-- Array of zero or more elements (elements need not be of same type)
SELECT '[1, 2, "foo", null]'::json;

-- Object containing pairs of keys and values
-- Note that object keys must always be quoted strings
SELECT '{"bar": "baz", "balance": 7.77, "active": false}'::json;

-- Arrays and objects can be nested arbitrarily
SELECT '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'::json;

如前所述,當 JSON 值被輸入然後列印而沒有任何額外處理時,json 輸出的文字與輸入的相同,而 jsonb 不會保留語義上不重要的細節,例如空格。例如,請注意這裡的區別

SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::json;
                      json
-------------------------------------------------
 {"bar": "baz", "balance": 7.77, "active":false}
(1 row)

SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::jsonb;
                      jsonb
--------------------------------------------------
 {"bar": "baz", "active": false, "balance": 7.77}
(1 row)

一個值得注意的語義上不重要的細節是,在 jsonb 中,數字將根據底層 numeric 型別的行為進行列印。實際上,這意味著帶有 E 表示法的數字將不帶 E 表示法列印,例如

SELECT '{"reading": 1.230e-5}'::json, '{"reading": 1.230e-5}'::jsonb;
         json          |          jsonb
-----------------------+-------------------------
 {"reading": 1.230e-5} | {"reading": 0.00001230}
(1 row)

然而,jsonb 會保留尾隨的零分數,如本例所示,即使這些對於相等性檢查等目的而言在語義上不重要。

有關用於構造和處理 JSON 值的內建函式和運算子列表,請參閱 第 9.16 節

8.14.2. 設計 JSON 文件 #

將資料表示為 JSON 可能比傳統的二維資料模型靈活得多,這在需求不斷變化的壞境中很有吸引力。這兩種方法在同一個應用程式中共存和互補是完全可能的。但是,即使對於需要最大靈活性的應用程式,仍然建議 JSON 文件具有一定的固定結構。結構通常不受強制(儘管可以宣告性地強制執行某些業務規則),但具有可預測的結構使得編寫有用地彙總表中一組文件(資料項)的查詢變得更加容易。

當儲存在表中時,JSON 資料與其他任何資料型別一樣會受到相同的併發控制考慮。雖然儲存大型文件是可行的,但請記住,任何更新都會獲取對整個行的行級鎖。考慮將 JSON 文件限制在可管理的大小,以減少更新事務之間的鎖定爭用。理想情況下,JSON 文件應代表業務規則規定無法合理地進一步細分為可獨立修改的更小資料項的原子資料項。

8.14.3. jsonb 包含和存在性 #

包含測試是 jsonb 的一項重要功能。對於 json 型別沒有類似的設施。包含測試一個 jsonb 文件是否包含另一個文件。除了註明的情況外,這些示例都返回 true。

-- Simple scalar/primitive values contain only the identical value:
SELECT '"foo"'::jsonb @> '"foo"'::jsonb;

-- The array on the right side is contained within the one on the left:
SELECT '[1, 2, 3]'::jsonb @> '[1, 3]'::jsonb;

-- Order of array elements is not significant, so this is also true:
SELECT '[1, 2, 3]'::jsonb @> '[3, 1]'::jsonb;

-- Duplicate array elements don't matter either:
SELECT '[1, 2, 3]'::jsonb @> '[1, 2, 2]'::jsonb;

-- The object with a single pair on the right side is contained
-- within the object on the left side:
SELECT '{"product": "PostgreSQL", "version": 9.4, "jsonb": true}'::jsonb @> '{"version": 9.4}'::jsonb;

-- The array on the right side is not considered contained within the
-- array on the left, even though a similar array is nested within it:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[1, 3]'::jsonb;  -- yields false

-- But with a layer of nesting, it is contained:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[[1, 3]]'::jsonb;

-- Similarly, containment is not reported here:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"bar": "baz"}'::jsonb;  -- yields false

-- A top-level key and an empty object is contained:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"foo": {}}'::jsonb;

一般原則是,被包含物件必須在結構和資料內容上匹配包含物件,可能在丟棄包含物件中一些不匹配的陣列元素或物件鍵/值對之後。但請記住,在進行包含匹配時,陣列元素的順序不重要,重複的陣列元素實際上只考慮一次。

作為一般原則的特殊例外,結構必須匹配,一個數組可以包含一個原始值

-- This array contains the primitive string value:
SELECT '["foo", "bar"]'::jsonb @> '"bar"'::jsonb;

-- This exception is not reciprocal -- non-containment is reported here:
SELECT '"bar"'::jsonb @> '["bar"]'::jsonb;  -- yields false

jsonb 還有一個存在性運算子,它是包含主題的一個變體:它測試一個字串(以 text 值給出)是否出現在 jsonb 值頂層的物件鍵或陣列元素中。除了註明的情況外,這些示例都返回 true。

-- String exists as array element:
SELECT '["foo", "bar", "baz"]'::jsonb ? 'bar';

-- String exists as object key:
SELECT '{"foo": "bar"}'::jsonb ? 'foo';

-- Object values are not considered:
SELECT '{"foo": "bar"}'::jsonb ? 'bar';  -- yields false

-- As with containment, existence must match at the top level:
SELECT '{"foo": {"bar": "baz"}}'::jsonb ? 'bar'; -- yields false

-- A string is considered to exist if it matches a primitive JSON string:
SELECT '"foo"'::jsonb ? 'foo';

當涉及許多鍵或元素時,JSON 物件比陣列更適合測試包含或存在性,因為與陣列不同,它們在內部經過最佳化以便搜尋,並且不需要線性搜尋。

提示

由於 JSON 包含是巢狀的,因此合適的查詢可以跳過顯式選擇子物件。例如,假設我們有一個 doc 列,其中包含頂層的物件,大多數物件包含包含子物件陣列的 tags 欄位。此查詢查詢包含 "term":"paris""term":"food" 的子物件的條目,同時忽略 tags 陣列之外的任何此類鍵。

SELECT doc->'site_name' FROM websites
  WHERE doc @> '{"tags":[{"term":"paris"}, {"term":"food"}]}';

可以使用類似的方法完成相同的事情,例如

SELECT doc->'site_name' FROM websites
  WHERE doc->'tags' @> '[{"term":"paris"}, {"term":"food"}]';

但這種方法不太靈活,而且通常效率也較低。

另一方面,JSON 存在性運算子不是巢狀的:它只查詢 JSON 值頂層的指定鍵或陣列元素。

各種包含和存在性運算子以及所有其他 JSON 運算子和函式都記錄在 第 9.16 節 中。

8.14.4. jsonb 索引 #

GIN 索引可用於高效地搜尋大量 jsonb 文件(資料項)中出現的鍵或鍵/值對。提供了兩個 GIN運算子類,提供不同的效能和靈活性權衡。

用於 jsonb 的預設 GIN 運算子類支援使用鍵存在運算子 ??|?&、包含運算子 @> 以及 jsonpath 匹配運算子 @?@@ 的查詢。(有關這些運算子實現的語義的詳細資訊,請參閱 表 9.48。)建立此運算子類的索引的示例是

CREATE INDEX idxgin ON api USING GIN (jdoc);

非預設 GIN 運算子類 jsonb_path_ops 不支援鍵存在運算子,但它支援 @>@?@@。建立此運算子類的索引的示例是

CREATE INDEX idxginp ON api USING GIN (jdoc jsonb_path_ops);

考慮一個儲存從第三方 Web 服務檢索到的 JSON 文件的表,該表具有文件化的架構定義。典型的文件是

{
    "guid": "9c36adc1-7fb5-4d5b-83b4-90356a46061a",
    "name": "Angela Barton",
    "is_active": true,
    "company": "Magnafone",
    "address": "178 Howard Place, Gulf, Washington, 702",
    "registered": "2009-11-07T08:53:22 +08:00",
    "latitude": 19.793713,
    "longitude": 86.513373,
    "tags": [
        "enim",
        "aliquip",
        "qui"
    ]
}

我們將這些文件儲存在名為 api 的表中,在名為 jdocjsonb 列中。如果在該列上建立了 GIN 索引,則以下查詢可以使用該索引。

-- Find documents in which the key "company" has value "Magnafone"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"company": "Magnafone"}';

但是,索引不能用於以下型別的查詢,因為儘管運算子 ? 可索引,但它沒有直接應用於索引列 jdoc

-- Find documents in which the key "tags" contains key or array element "qui"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc -> 'tags' ? 'qui';

儘管如此,透過適當使用表示式索引,上述查詢可以使用索引。如果經常查詢 "tags" 鍵內的特定項,則定義如下索引可能值得。

CREATE INDEX idxgintags ON api USING GIN ((jdoc -> 'tags'));

現在,WHERE 子句 jdoc -> 'tags' ? 'qui' 將被識別為在索引表示式 jdoc -> 'tags' 上應用了可索引運算子 ?。(有關表示式索引的更多資訊,請參閱 第 11.7 節。)

另一種查詢方法是利用包含,例如

-- Find documents in which the key "tags" contains array element "qui"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qui"]}';

jdoc 列上的簡單 GIN 索引可以支援此查詢。但請注意,此類索引將儲存 jdoc 列中的每個鍵和值的副本,而前一個示例中的表示式索引僅儲存 tags 鍵下的資料。雖然簡單的索引方法更靈活(因為它支援關於任何鍵的查詢),但有針對性的表示式索引可能比簡單索引更小,搜尋速度更快。

GIN 索引還支援 @?@@ 運算子,它們執行 jsonpath 匹配。示例是

SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @? '$.tags[*] ? (@ == "qui")';
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @@ '$.tags[*] == "qui"';

對於這些運算子,GIN 索引會從 jsonpath 模式中提取 accessors_chain == constant 形式的子句,並基於這些子句中提到的鍵和值執行索引搜尋。訪問器鏈可以包括 .key[*][index] 訪問器。jsonb_ops 運算子類還支援 .*.** 訪問器,但 jsonb_path_ops 運算子類不支援。

儘管 jsonb_path_ops 運算子類僅支援使用 @>@?@@ 運算子的查詢,但它與預設運算子類 jsonb_ops 相比具有顯著的效能優勢。jsonb_path_ops 索引通常比相同資料的 jsonb_ops 索引小得多,並且搜尋的特異性更好,尤其是在查詢包含資料中經常出現的鍵時。因此,搜尋操作通常比預設運算子類更好。

jsonb_opsjsonb_path_ops GIN 索引之間,技術上的區別在於前者為資料中的每個鍵和值建立獨立的索引項,而後者僅為資料中的每個值建立索引項。[7] 基本上,每個 jsonb_path_ops 索引項是值和導致它的鍵(們)的雜湊值;例如,要索引 {"foo": {"bar": "baz"}},將建立一個包含 foobarbaz 的單個索引項到雜湊值中。因此,查詢此結構的包含查詢將導致非常特定的索引搜尋;但沒有辦法確定 foo 是否作為鍵出現。另一方面,jsonb_ops 索引將建立三個單獨表示 foobarbaz 的索引項;然後,要執行包含查詢,它將查詢包含這三個項的行。雖然 GIN 索引可以相當有效地執行這種 AND 搜尋,但它仍然不如等效的 jsonb_path_ops 搜尋,特別是如果存在包含這三個索引項中任何一個的非常多的行。

jsonb_path_ops 方法的一個缺點是它不會為不包含任何值的 JSON 結構建立索引條目,例如 {"a": {}}。如果請求搜尋包含此類結構的文件,將需要一個完整的索引掃描,這非常慢。jsonb_path_ops 因此不適合經常執行此類搜尋的應用程式。

jsonb 還支援 btreehash 索引。這些通常僅在檢查完整 JSON 文件的相等性很重要時才有用。jsonb 資料項的 btree 排序很少有很大的意義,但為完整起見,它是

Object > Array > Boolean > Number > String > null

Object with n pairs > object with n - 1 pairs

Array with n elements > array with n - 1 elements

例外情況是(由於歷史原因)頂層空陣列排序小於null。具有相同數量對的物件按順序比較

key-1, value-1, key-2 ...

請注意,物件鍵按其儲存順序進行比較;特別是,因為較短的鍵比較長的鍵先儲存,這可能導致一些可能令人費解的結果,例如

{ "aa": 1, "c": 1} > {"b": 1, "d": 1}

同樣,具有相同數量元素的陣列按順序比較

element-1, element-2 ...

原始 JSON 值使用與底層 PostgreSQL 資料型別相同的比較規則進行比較。字串使用預設資料庫排序規則進行比較。

8.14.5. jsonb 下標 #

jsonb 資料型別支援類陣列的下標表達式來提取和修改元素。可以透過連結下標表達式來指示巢狀值,遵循與 jsonb_set 函式中的 path 引數相同的規則。如果 jsonb 值是陣列,則數字下標從零開始,負整數從陣列最後一個元素向後計數。不支援切片表示式。下標表達式的結果始終是 jsonb 資料型別。

UPDATE 語句可以在 SET 子句中使用下標來修改 jsonb 值。下標路徑必須對於所有受影響的值(只要它們存在)都可以遍歷。例如,路徑 val['a']['b']['c'] 可以一直遍歷到 c,如果每個 valval['a']val['a']['b'] 都是物件。如果任何 val['a']val['a']['b'] 未定義,它將被建立為空物件並按需填充。但是,如果任何 val 本身或中間值被定義為非物件(如字串、數字或 jsonb null),則遍歷無法繼續,將引發錯誤並中止事務。

下標語法的示例

-- Extract object value by key
SELECT ('{"a": 1}'::jsonb)['a'];

-- Extract nested object value by key path
SELECT ('{"a": {"b": {"c": 1}}}'::jsonb)['a']['b']['c'];

-- Extract array element by index
SELECT ('[1, "2", null]'::jsonb)[1];

-- Update object value by key. Note the quotes around '1': the assigned
-- value must be of the jsonb type as well
UPDATE table_name SET jsonb_field['key'] = '1';

-- This will raise an error if any record's jsonb_field['a']['b'] is something
-- other than an object. For example, the value {"a": 1} has a numeric value
-- of the key 'a'.
UPDATE table_name SET jsonb_field['a']['b']['c'] = '1';

-- Filter records using a WHERE clause with subscripting. Since the result of
-- subscripting is jsonb, the value we compare it against must also be jsonb.
-- The double quotes make "value" also a valid jsonb string.
SELECT * FROM table_name WHERE jsonb_field['key'] = '"value"';

jsonb 透過下標進行的賦值在某些邊緣情況下與 jsonb_set 不同。當源 jsonb 值為 NULL 時,透過下標賦值將按其型別(物件或陣列)的空 JSON 值進行,該型別由下標鍵暗示。

-- Where jsonb_field was NULL, it is now {"a": 1}
UPDATE table_name SET jsonb_field['a'] = '1';

-- Where jsonb_field was NULL, it is now [1]
UPDATE table_name SET jsonb_field[0] = '1';

如果為元素數量不足的陣列指定了索引,將附加 NULL 元素,直到可以訪問索引並設定值。

-- Where jsonb_field was [], it is now [null, null, 2];
-- where jsonb_field was [0], it is now [0, null, 2]
UPDATE table_name SET jsonb_field[2] = '2';

jsonb 值將接受對不存在的下標路徑的賦值,只要要遍歷的最後一個現有元素是物件或陣列(由相應的下標暗示,最後一個下標路徑中的元素不遍歷,可以是任何值)。將建立巢狀的陣列和物件結構,並且在前者情況下,將根據下標路徑填充 null,直到可以放置賦值的值。

-- Where jsonb_field was {}, it is now {"a": [{"b": 1}]}
UPDATE table_name SET jsonb_field['a'][0]['b'] = '1';

-- Where jsonb_field was [], it is now [null, {"a": 1}]
UPDATE table_name SET jsonb_field[1]['a'] = '1';

8.14.6. 轉換 #

還有額外的擴充套件實現了不同過程語言的 jsonb 型別的轉換。

PL/Perl 的擴充套件稱為 jsonb_plperljsonb_plperlu。如果使用它們,jsonb 值將根據情況對映到 Perl 陣列、雜湊和標量。

PL/Python 的擴充套件稱為 jsonb_plpython3u。如果使用它,jsonb 值將根據情況對映到 Python 字典、列表和標量。

在這些擴充套件中,jsonb_plperl 被認為是受信任的,即,它可以由沒有資料庫超級使用者許可權但具有當前資料庫CREATE許可權的非超級使用者安裝。其餘擴充套件需要超級使用者許可權才能安裝。

8.14.7. jsonpath 型別 #

jsonpath 型別在 PostgreSQL 中實現了對 SQL/JSON 路徑語言的支援,以便高效地查詢 JSON 資料。它提供了已解析的 SQL/JSON 路徑表示式的二進位制表示,該表示式指定路徑引擎從 JSON 資料中檢索要進一步與 SQL/JSON 查詢函式進行處理的專案。

SQL/JSON 路徑謂詞和運算子的語義通常遵循 SQL。同時,為了提供一種處理 JSON 資料的自然方式,SQL/JSON 路徑語法使用了一些 JavaScript 約定。

  • 點(.)用於成員訪問。

  • 方括號([])用於陣列訪問。

  • SQL/JSON 陣列是 0 相對的,與從 1 開始的常規 SQL 陣列不同。

SQL/JSON 路徑表示式中的數字文字遵循 JavaScript 規則,這些規則在某些細節上與 SQL 和 JSON 都不同。例如,SQL/JSON 路徑允許 .11.,這在 JSON 中是無效的。支援非十進位制整數文字和下劃線分隔符,例如 1_000_0000x1EEE_FFFF0o2730b100101。在 SQL/JSON 路徑(和 JavaScript 中,但在 SQL 本身中不是)中,不得在基數字首之後直接使用下劃線分隔符。

SQL/JSON 路徑表示式通常在 SQL 查詢中寫為 SQL 字串文字,因此它必須用單引號括起來,並且值中任何想要的單引號都必須加倍(參見 第 4.1.2.1 節)。某些路徑表示式形式需要其中的字串文字。這些嵌入的字串文字遵循 JavaScript/ECMAScript 約定:它們必須用雙引號括起來,並且可以在其中使用反斜槓轉義來表示難以鍵入的字元。特別地,在嵌入式字串文字中寫入雙引號的方法是 \",要寫入反斜槓本身,您必須寫入 \\。其他特殊反斜槓序列包括 JavaScript 字串中識別的序列:\b\f\n\r\t\v 用於各種 ASCII 控制字元,\xNN 用於僅用兩個十六進位制數字編寫的字元程式碼,\uNNNN 用於由其 4 位十六進位制程式碼點標識的 Unicode 字元,以及 \u{N...} 用於用 1 到 6 位十六進位制數字編寫的 Unicode 字元程式碼點。

路徑表示式由一系列路徑元素組成,這些元素可以是以下任何一種:

  • JSON 原始型別的路徑文字:Unicode 文字、數字、true、false 或 null。

  • 表 8.24 中列出的路徑變數。

  • 表 8.25 中列出的訪問器運算子。

  • jsonpath 運算子和方法列於 第 9.16.2.3 節

  • 括號,可用於提供過濾表示式或定義路徑評估順序。

有關使用 jsonpath 表示式與 SQL/JSON 查詢函式的詳細資訊,請參閱 第 9.16.2 節

表 8.24. jsonpath 變數

變數 描述
$ 表示正在查詢的 JSON 值(上下文項)的變數。
$varname 命名變數。它的值可以由幾個 JSON 處理函式的引數vars設定;有關詳細資訊,請參閱 表 9.51
@ 表示過濾表示式中路徑評估結果的變數。

表 8.25. jsonpath 訪問器

訪問器運算子 描述

.key

."$varname"

成員訪問器,返回具有指定鍵的物件成員。如果鍵名與以 $ 開頭的任何命名變數匹配,或者不符合 JavaScript 識別符號規則,則必須用雙引號括起來,使其成為字串文字。

.*

萬用字元成員訪問器,返回當前物件頂層所有成員的值。

.**

遞迴萬用字元成員訪問器,處理當前物件 JSON 層次結構的所有級別,並返回所有成員的值,無論其巢狀級別如何。這是 SQL/JSON 標準的 PostgreSQL 擴充套件。

.**{level}

.**{start_levelend_level}

類似於 .**,但僅選擇 JSON 層次結構的指定級別。巢狀級別用整數指定。級別零對應於當前物件。要訪問最低巢狀級別,可以使用 last 關鍵字。這是 SQL/JSON 標準的 PostgreSQL 擴充套件。

[subscript, ...]

陣列元素訪問器。subscript 可以有兩種形式:indexstart_indexend_index。第一種形式按索引返回單個數組元素。第二種形式透過索引範圍返回一個數組切片,包括與提供的 start_indexend_index 對應的元素。

指定的 index 可以是整數,也可以是返回單個數值的表示式,該表示式會自動轉換為整數。索引零對應於第一個陣列元素。您還可以使用 last 關鍵字來表示最後一個數組元素,這對於處理未知長度的陣列很有用。

[*]

萬用字元陣列元素訪問器,返回所有陣列元素。




[7] 出於此目的,術語包括陣列元素,儘管 JSON 術語有時將陣列元素視為與物件內的值不同。

提交更正

如果您在文件中看到任何不正確的內容,與您對特定功能的體驗不符,或者需要進一步澄清,請使用 此表單 報告文件問題。