2018年10月16日18:14:21
官方文檔中文翻譯版
原文:https://dev.mysql.com/doc/refman/5.7/en/json.html
最后有部分實例和一個小總結
11.6 JSON數據類型
-
創建JSON值
-
JSON值的規范化,合並和自動包裝
-
搜索和修改JSON值
-
JSON值的比較和排序
-
在JSON和非JSON值之間轉換
-
JSON值的聚合
從MySQL 5.7.8開始,MySQL支持RFC 7159JSON
定義的本機數據類型 ,可以高效訪問JSON(JavaScript Object Notation)文檔中的數據。與在字符串列中存儲JSON格式字符串相比,數據類型具有以下優勢: JSON
-
自動驗證存儲在
JSON
列中的JSON文檔 。無效的文檔會產生錯誤。 -
優化的存儲格式。存儲在
JSON
列中的JSON文檔將 轉換為內部格式,以允許快速讀取文檔元素。當服務器稍后必須讀取以此二進制格式存儲的JSON值時,不需要從文本表示中解析該值。二進制格式的結構使服務器能夠直接通過鍵或數組索引查找子對象或嵌套值,而無需在文檔中讀取它們之前或之后的所有值。
此討論使用JSON
monotype來指定JSON數據類型和 常規字體中的“ JSON ”以指示一般的JSON數據。
存儲JSON
文檔所需的空間與LONGBLOB
或 大致相同LONGTEXT
; 有關更多信息,請參見 第11.8節“數據類型存儲要求”。請務必記住,JSON
列中存儲的任何JSON文檔的大小都限制為max_allowed_packet
系統變量的值。(當服務器在內存中內部操作JSON值時,它可能大於此值;當服務器存儲時,該限制適用。)
一JSON
列不能有默認值。
除了JSON
數據類型之外,還有一組SQL函數可用於對JSON值進行操作,例如創建,操作和搜索。以下討論顯示了這些操作的示例。有關各個函數的詳細信息,請參見第12.16節“JSON函數”。
還提供了一組用於操作GeoJSON值的空間函數。請參見第12.15.11節“空間GeoJSON函數”。
JSON
列,與其他二進制類型的列一樣,不直接索引; 相反,您可以在生成的列上創建索引,從列中提取標量值 JSON
。有關詳細示例,請參閱 索引生成的列以提供JSON列索引。
MySQL優化器還在與JSON表達式匹配的虛擬列上查找兼容索引。
MySQL NDB Cluster 7.5(7.5.2及更高版本)支持 JSON
列和MySQL JSON函數,包括在列生成的JSON
列上創建索引 ,作為無法索引JSON
列的變通方法。JSON
每個NDB
表最多支持3列 。
接下來的幾節提供了有關JSON值的創建和操作的基本信息。
創建JSON值
JSON數組包含一個由逗號分隔的值列表,並包含在 字符[
和]
字符中:
["abc", 10, null, true, false]
JSON對象包含一組由逗號分隔的鍵值對,並包含在字符{
和 }
字符中:
{"k1": "value", "k2": 10}
如示例所示,JSON數組和對象可以包含字符串或數字的標量值,JSON空文字或JSON布爾值true或false文字。JSON對象中的鍵必須是字符串。時間(日期,時間或日期時間)標量值也是允許的:
["12:18:29.000000", "2015-07-29", "2015-07-29 12:18:29.000000"]
JSON數組元素和JSON對象鍵值允許嵌套:
[99, {"id": "HK500", "cost": 75.99}, ["hot", "cold"]]
{"k1": "value", "k2": [10, 20]}
您還可以為此目的從MySQL提供的許多函數中獲取JSON值(請參見 第12.16.2節“創建JSON值的函數”)以及JSON
使用其他類型的值轉換為類型 (請參閱 在JSON之間轉換)和非JSON值)。接下來的幾段描述了MySQL如何處理作為輸入提供的JSON值。 CAST(
value
AS JSON)
在MySQL中,JSON值被寫為字符串。MySQL解析在需要JSON值的上下文中使用的任何字符串,如果它作為JSON無效則會產生錯誤。這些上下文包括將值插入到具有JSON
數據類型的列中, 並將參數傳遞給需要JSON值的函數(通常顯示為 json_doc
或 json_val
在MySQL JSON函數的文檔中),如以下示例所示:
-
JSON
如果值是有效的JSON值,則 嘗試將值插入列成功,但如果不是,則嘗試失敗:mysql> CREATE TABLE t1 (jdoc JSON); Query OK, 0 rows affected (0.20 sec) mysql> INSERT INTO t1 VALUES('{"key1": "value1", "key2": "value2"}'); Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO t1 VALUES('[1, 2,'); ERROR 3140 (22032) at line 2: Invalid JSON text: "Invalid value." at position 6 in value (or column) '[1, 2,'.
為位置“ 在位置
N
”在這樣的錯誤消息是基於0的,但應考慮其中一個值問題實際發生的粗指示。 -
該
JSON_TYPE()
函數需要一個JSON參數並嘗試將其解析為JSON值。如果值有效,則返回值的JSON類型,否則產生錯誤:mysql> SELECT JSON_TYPE('["a", "b", 1]'); +----------------------------+ | JSON_TYPE('["a", "b", 1]') | +----------------------------+ | ARRAY | +----------------------------+ mysql> SELECT JSON_TYPE('"hello"'); +----------------------+ | JSON_TYPE('"hello"') | +----------------------+ | STRING | +----------------------+ mysql> SELECT JSON_TYPE('hello'); ERROR 3146 (22032): Invalid data type for JSON data in argument 1 to function json_type; a JSON string or JSON type is required.
MySQL使用utf8mb4
字符集和utf8mb4_bin
排序規則處理JSON上下文中使用的 字符串 。其他字符集中的字符串將utf8mb4
根據需要進行轉換。(對於在串ascii
或 utf8
字符集,則不需要轉換,因為ascii
和utf8
都是的子集utf8mb4
。)
作為使用文字字符串編寫JSON值的替代方法,存在用於從組件元素組成JSON值的函數。JSON_ARRAY()
獲取(可能為空)值列表並返回包含這些值的JSON數組:
mysql> SELECT JSON_ARRAY('a', 1, NOW());
+----------------------------------------+
| JSON_ARRAY('a', 1, NOW()) |
+----------------------------------------+
| ["a", 1, "2015-07-27 09:43:47.000000"] |
+----------------------------------------+
JSON_OBJECT()
獲取一個(可能是空的)鍵值對列表,並返回包含這些對的JSON對象:
mysql> SELECT JSON_OBJECT('key1', 1, 'key2', 'abc');
+---------------------------------------+
| JSON_OBJECT('key1', 1, 'key2', 'abc') |
+---------------------------------------+
| {"key1": 1, "key2": "abc"} |
+---------------------------------------+
JSON_MERGE()
獲取兩個或多個JSON文檔並返回組合結果:
mysql> SELECT JSON_MERGE('["a", 1]', '{"key": "value"}');
+--------------------------------------------+
| JSON_MERGE('["a", 1]', '{"key": "value"}') |
+--------------------------------------------+
| ["a", 1, {"key": "value"}] |
+--------------------------------------------+
有關合並規則的信息,請參閱 JSON值的規范化,合並和自動包裝。
可以將JSON值分配給用戶定義的變量:
mysql> SET @j = JSON_OBJECT('key', 'value');
mysql> SELECT @j;
+------------------+
| @j |
+------------------+
| {"key": "value"} |
+------------------+
但是,用戶定義的變量不能是 JSON
數據類型,所以雖然 @j
在前面的例子中看起來像一個JSON值並且具有相同的字符集和歸類為JSON值,但它不具有 JSON
數據類型。相反,結果from JSON_OBJECT()
在分配給變量時會轉換為字符串。
通過轉換JSON值生成的字符串具有以下字符集utf8mb4
和排序規則 utf8mb4_bin
:
mysql> SELECT CHARSET(@j), COLLATION(@j);
+-------------+---------------+
| CHARSET(@j) | COLLATION(@j) |
+-------------+---------------+
| utf8mb4 | utf8mb4_bin |
+-------------+---------------+
因為utf8mb4_bin
是二進制排序規則,所以JSON值的比較區分大小寫。
mysql> SELECT JSON_ARRAY('x') = JSON_ARRAY('X');
+-----------------------------------+
| JSON_ARRAY('x') = JSON_ARRAY('X') |
+-----------------------------------+
| 0 |
+-----------------------------------+
區分大小寫也適用於JSON null
,true
和 false
文字,它們必須始終以小寫形式編寫:
mysql> SELECT JSON_VALID('null'), JSON_VALID('Null'), JSON_VALID('NULL');
+--------------------+--------------------+--------------------+
| JSON_VALID('null') | JSON_VALID('Null') | JSON_VALID('NULL') |
+--------------------+--------------------+--------------------+
| 1 | 0 | 0 |
+--------------------+--------------------+--------------------+
mysql> SELECT CAST('null' AS JSON);
+----------------------+
| CAST('null' AS JSON) |
+----------------------+
| null |
+----------------------+
1 row in set (0.00 sec)
mysql> SELECT CAST('NULL' AS JSON);
ERROR 3141 (22032): Invalid JSON text in argument 1 to function cast_as_json: "Invalid value." at position 0 in 'NULL'.
的字面JSON的情況下,靈敏度不同於所述SQL的NULL
,TRUE
和 FALSE
文字,它可以在任何大小寫被寫成:
mysql> SELECT ISNULL(null), ISNULL(Null), ISNULL(NULL);
+--------------+--------------+--------------+
| ISNULL(null) | ISNULL(Null) | ISNULL(NULL) |
+--------------+--------------+--------------+
| 1 | 1 | 1 |
+--------------+--------------+--------------+
有時可能需要或希望將引號字符("
或'
)插入JSON文檔中。假設您希望在此示例中插入一些JSON對象,這些對象包含表示有關MySQL的一些事實的句子,每個句子都與適當的關鍵字配對,使用此處顯示的SQL語句創建的表:
mysql> CREATE TABLE facts (sentence JSON);
這些關鍵詞 - 句子對中有這一個:
mascot: The MySQL mascot is a dolphin named "Sakila".
將此作為JSON對象插入facts
表中的一種方法 是使用MySQL JSON_OBJECT()
函數。在這種情況下,您必須使用反斜杠轉義每個引號字符,如下所示:
mysql> INSERT INTO facts VALUES
> (JSON_OBJECT("mascot", "Our mascot is a dolphin named \"Sakila\"."));
如果將值作為JSON對象文字插入,則此方法不起作用,在這種情況下,必須使用雙反斜杠轉義序列,如下所示:
mysql> INSERT INTO facts VALUES
> ('{"mascot": "Our mascot is a dolphin named \\"Sakila\\"."}');
使用雙反斜杠可以防止MySQL執行轉義序列處理,而是使它將字符串文字傳遞給存儲引擎進行處理。以剛才顯示的方式插入JSON對象后,您可以通過執行簡單操作看到反斜杠存在於JSON列值中SELECT
,如下所示:
mysql> SELECT sentence FROM facts;
+---------------------------------------------------------+
| sentence |
+---------------------------------------------------------+
| {"mascot": "Our mascot is a dolphin named \"Sakila\"."} |
+---------------------------------------------------------+
要使用mascot
鍵作為查找此特定句子 ,可以使用column-path運算符 ->
,如下所示:
mysql> SELECT col->"$.mascot" FROM qtest;
+---------------------------------------------+
| col->"$.mascot" |
+---------------------------------------------+
| "Our mascot is a dolphin named \"Sakila\"." |
+---------------------------------------------+
1 row in set (0.00 sec)
這樣就可以保留反斜杠以及周圍的引號。要使用mascot
鍵作為鍵顯示所需的值 ,但不包括周圍的引號或任何轉義符->>
,請使用內聯路徑運算符 ,如下所示:
mysql> SELECT sentence->>"$.mascot" FROM facts;
+-----------------------------------------+
| sentence->>"$.mascot" |
+-----------------------------------------+
| Our mascot is a dolphin named "Sakila". |
+-----------------------------------------+
如果NO_BACKSLASH_ESCAPES
啟用了服務器SQL模式,則前面的示例無法正常工作 。如果設置了此模式,則可以使用單個反斜杠而不是雙反斜杠來插入JSON對象文字,並保留反斜杠。如果JSON_OBJECT()
在執行插入時使用該功能並且設置了此模式,則必須替換單引號和雙引號,如下所示:
mysql> INSERT INTO facts VALUES
> (JSON_OBJECT('mascot', 'Our mascot is a dolphin named "Sakila".'));
有關JSON_UNQUOTE()
此模式對JSON值中的轉義字符的影響的詳細信息,請參閱該函數的說明 。
JSON值的規范化,合並和自動包裝
當解析一個字符串並發現它是一個有效的JSON文檔時,它也會被標准化:具有復制在文檔中較早找到的鍵的鍵的成員將被丟棄(即使值不同)。以下JSON_OBJECT()
調用生成的對象值 不包括第二個key1
元素,因為該鍵名稱出現在值的前面:
mysql> SELECT JSON_OBJECT('key1', 1, 'key2', 'abc', 'key1', 'def');
+------------------------------------------------------+
| JSON_OBJECT('key1', 1, 'key2', 'abc', 'key1', 'def') |
+------------------------------------------------------+
| {"key1": 1, "key2": "abc"} |
+------------------------------------------------------+
重復密鑰的 這種“ 第一關鍵勝利 ”處理與RFC 7159不一致 。這是MySQL 5.7中的已知問題,已在MySQL 8.0中修復。(Bug#86866,Bug#26369555)
MySQL還會丟棄原始JSON文檔中的鍵,值或元素之間的額外空格。為了使查找更有效,它還對JSON對象的鍵進行排序。 您應該知道,此排序的結果可能會發生變化,並且不保證在各個版本中保持一致。
生成JSON值的MySQL函數(請參見 第12.16.2節“創建JSON值的函數”)始終返回規范化值。
合並JSON值
在組合多個數組的上下文中,通過將稍后命名的數組連接到第一個數組的末尾,將數組合並為單個數組。在以下示例中, JSON_MERGE()
將其參數合並為單個數組:
mysql> SELECT JSON_MERGE('[1, 2]', '["a", "b"]', '[true, false]');
+-----------------------------------------------------+
| JSON_MERGE('[1, 2]', '["a", "b"]', '[true, false]') |
+-----------------------------------------------------+
| [1, 2, "a", "b", true, false] |
+-----------------------------------------------------+
將值插入JSON列時也會執行規范化,如下所示:
mysql> CREATE TABLE t1 (c1 JSON);
mysql> INSERT INTO t1 VALUES
> ('{"x": 17, "x": "red"}'),
> ('{"x": 17, "x": "red", "x": [3, 5, 7]}');
mysql> SELECT c1 FROM t1;
+-----------+
| c1 |
+-----------+
| {"x": 17} |
| {"x": 17} |
+-----------+
合並時的多個對象生成單個對象。如果多個對象具有相同的鍵,則生成的合並對象中該鍵的值是包含鍵值的數組:
mysql> SELECT JSON_MERGE('{"a": 1, "b": 2}', '{"c": 3, "a": 4}');
+----------------------------------------------------+
| JSON_MERGE('{"a": 1, "b": 2}', '{"c": 3, "a": 4}') |
+----------------------------------------------------+
| {"a": [1, 4], "b": 2, "c": 3} |
+----------------------------------------------------+
在需要數組值的上下文中使用的非陣列值是自動封裝的:該值由[
和]
字符包圍以將其轉換為數組。在以下語句中,每個參數都自動包裝為數組([1]
,[2]
)。然后將它們合並以生成單個結果數組:
mysql> SELECT JSON_MERGE('1', '2');
+----------------------+
| JSON_MERGE('1', '2') |
+----------------------+
| [1, 2] |
+----------------------+
通過將對象自動包裝為數組並合並兩個數組來合並數組和對象值:
mysql> SELECT JSON_MERGE('[10, 20]', '{"a": "x", "b": "y"}');
+------------------------------------------------+
| JSON_MERGE('[10, 20]', '{"a": "x", "b": "y"}') |
+------------------------------------------------+
| [10, 20, {"a": "x", "b": "y"}] |
+------------------------------------------------+
搜索和修改JSON值
JSON路徑表達式選擇JSON文檔中的值。
路徑表達式對於提取JSON文檔的一部分或修改JSON文檔的函數非常有用,以指定該文檔中的操作位置。例如,以下查詢從JSON文檔中提取具有name
鍵的成員的值 :
mysql> SELECT JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name');
+---------------------------------------------------------+
| JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name') |
+---------------------------------------------------------+
| "Aztalan" |
+---------------------------------------------------------+
路徑語法使用前導$
字符來表示正在考慮的JSON文檔,可選地后跟選擇器,它們連續指示文檔的更具體部分:
-
后跟密鑰名稱的句點使用給定密鑰命名對象中的成員。如果沒有引號的名稱在路徑表達式中不合法(例如,如果它包含空格),則必須在雙引號內指定鍵名。
-
[
附加到aN
]path
,選擇一個數組命名數組中位置的值N
。數組位置是從零開始的整數。如果path
未選擇數組值,path
[0]計算的值與path
以下相同 :mysql> SELECT JSON_SET('"x"', '$[0]', 'a'); +------------------------------+ | JSON_SET('"x"', '$[0]', 'a') | +------------------------------+ | "a" | +------------------------------+ 1 row in set (0.00 sec)
-
路徑可以包含
*
或**
通配符:-
.[*]
計算JSON對象中所有成員的值。 -
[*]
計算JSON數組中所有元素的值。 -
計算所有以命名前綴開頭並以命名后綴結尾的路徑。prefix
**suffix
-
-
文檔中不存在的路徑(評估為不存在的數據)的計算結果為
NULL
。
讓我們$
用三個元素來引用這個JSON數組:
[3, {"a": [5, 6], "b": 10}, [99, 100]]
然后:
-
$[0]
評估為3
。 -
$[1]
評估為{"a": [5, 6], "b": 10}
。 -
$[2]
評估為[99, 100]
。 -
$[3]
求值為NULL
(它指的是第四個不存在的數組元素)。
因為$[1]
並且$[2]
評估為非標量值,所以它們可以用作選擇嵌套值的更具體路徑表達式的基礎。例子:
-
$[1].a
評估為[5, 6]
。 -
$[1].a[1]
評估為6
。 -
$[1].b
評估為10
。 -
$[2][0]
評估為99
。
如前所述,如果路徑表達式中的未加引號的鍵名稱不合法,則必須引用命名鍵的路徑組件。讓我們$
參考這個值:
{"a fish": "shark", "a bird": "sparrow"}
密鑰都包含空格,必須引用:
-
$."a fish"
評估為shark
。 -
$."a bird"
評估為sparrow
。
使用通配符的路徑計算為可包含多個值的數組:
mysql> SELECT JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.*');
+---------------------------------------------------------+
| JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.*') |
+---------------------------------------------------------+
| [1, 2, [3, 4, 5]] |
+---------------------------------------------------------+
mysql> SELECT JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.c[*]');
+------------------------------------------------------------+
| JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.c[*]') |
+------------------------------------------------------------+
| [3, 4, 5] |
+------------------------------------------------------------+
在以下示例中,路徑$**.b
計算為多個路徑($.a.b
和 $.c.b
)並生成匹配路徑值的數組:
mysql> SELECT JSON_EXTRACT('{"a": {"b": 1}, "c": {"b": 2}}', '$**.b');
+---------------------------------------------------------+
| JSON_EXTRACT('{"a": {"b": 1}, "c": {"b": 2}}', '$**.b') |
+---------------------------------------------------------+
| [1, 2] |
+---------------------------------------------------------+
在MySQL 5.7.9及更高版本中,您可以使用 JSON列標識符和JSON路徑表達式作為同義詞 。有關更多信息,請參見 第12.16.3節“搜索JSON值的函數”。另請參見索引生成的列以提供JSON列索引。 column
->path
JSON_EXTRACT(
column
, path
)
某些函數采用現有的JSON文檔,以某種方式對其進行修改,並返回生成的修改后的文檔。路徑表達式指示文檔中的更改位置。例如,JSON_SET()
, JSON_INSERT()
,和JSON_REPLACE()
功能各采取JSON文檔,再加上描述其中修改文檔和使用的值的一個或多個路徑/值對。這些函數在處理文檔中的現有值和不存在值方面有所不同。
考慮這個文件:
mysql> SET @j = '["a", {"b": [true, false]}, [10, 20]]';
JSON_SET()
替換存在的路徑的值,並為不存在的路徑添加值:
mysql> SELECT JSON_SET(@j, '$[1].b[0]', 1, '$[2][2]', 2);
+--------------------------------------------+
| JSON_SET(@j, '$[1].b[0]', 1, '$[2][2]', 2) |
+--------------------------------------------+
| ["a", {"b": [1, false]}, [10, 20, 2]] |
+--------------------------------------------+
在這種情況下,路徑$[1].b[0]
選擇一個現有值(true
),該值將替換為path參數(1
)后面的值。該路徑$[2][2]
不存在,因此相應的值(2
)將添加到所選的值$[2]
。
JSON_INSERT()
添加新值但不替換現有值:
mysql> SELECT JSON_INSERT(@j, '$[1].b[0]', 1, '$[2][2]', 2);
+-----------------------------------------------+
| JSON_INSERT(@j, '$[1].b[0]', 1, '$[2][2]', 2) |
+-----------------------------------------------+
| ["a", {"b": [true, false]}, [10, 20, 2]] |
+-----------------------------------------------+
JSON_REPLACE()
替換現有值並忽略新值:
mysql> SELECT JSON_REPLACE(@j, '$[1].b[0]', 1, '$[2][2]', 2);
+------------------------------------------------+
| JSON_REPLACE(@j, '$[1].b[0]', 1, '$[2][2]', 2) |
+------------------------------------------------+
| ["a", {"b": [1, false]}, [10, 20]] |
+------------------------------------------------+
路徑/值對從左到右進行評估。通過評估一對產生的文檔成為評估下一對的新值。
JSON_REMOVE()
獲取JSON文檔和一個或多個指定要從文檔中刪除的值的路徑。返回值是原始文檔減去文檔中存在的路徑選擇的值:
mysql> SELECT JSON_REMOVE(@j, '$[2]', '$[1].b[1]', '$[1].b[1]');
+---------------------------------------------------+
| JSON_REMOVE(@j, '$[2]', '$[1].b[1]', '$[1].b[1]') |
+---------------------------------------------------+
| ["a", {"b": [true]}] |
+---------------------------------------------------+
路徑有這些影響:
-
$[2]
匹配[10, 20]
並刪除它。 -
的第一個實例
$[1].b[1]
相匹配false
的b
元素並將其刪除。 -
$[1].b[1]
匹配 的第二個實例沒有:該元素已被刪除,路徑不再存在,並且無效。
JSON值的比較和排序
JSON值可以使用進行比較 =
, <
, <=
, >
, >=
, <>
, !=
,和 <=>
運營商。
JSON值尚不支持以下比較運算符和函數:
-
BETWEEN
-
IN()
-
GREATEST()
-
LEAST()
剛才列出的比較運算符和函數的解決方法是將JSON值轉換為本機MySQL數值或字符串數據類型,以便它們具有一致的非JSON標量類型。
JSON值的比較發生在兩個級別。第一級比較基於比較值的JSON類型。如果類型不同,則比較結果僅由哪種類型具有更高優先級來確定。如果這兩個值具有相同的JSON類型,則使用特定於類型的規則進行第二級比較。
以下列表顯示了JSON類型的優先級,從最高優先級到最低優先級。(類型名稱是JSON_TYPE()
函數返回的類型名稱。)一行顯示的類型具有相同的優先級。列表中前面列出的任何具有JSON類型的值都比列表中稍后列出的具有JSON類型的任何值都要大。
BLOB
BIT
OPAQUE
DATETIME
TIME
DATE
BOOLEAN
ARRAY
OBJECT
STRING
INTEGER, DOUBLE
NULL
對於具有相同優先級的JSON值,比較規則是特定於類型的:
-
BLOB
N
比較兩個值 的第一個字節,其中N
是較短值中的字節數。如果N
兩個值的第一個 字節相同,則在較長值之前排序較短的值。 -
BIT
與...相同的規則
BLOB
。 -
OPAQUE
與...相同的規則
BLOB
。OPAQUE
值是未歸類為其他類型之一的值。 -
DATETIME
表示較早時間點的值在表示稍后時間點的值之前排序。如果兩個值最初 分別來自MySQL
DATETIME
和TIMESTAMP
類型,則它們相等,如果它們代表相同的時間點。 -
TIME
兩個時間值中較小的一個在較大的值之前排序。
-
DATE
較早的日期是在最近的日期之前訂購的。
-
ARRAY
如果兩個JSON數組具有相同的長度並且數組中相應位置的值相等,則它們是相等的。
如果數組不相等,則它們的順序由第一個位置中存在差異的元素確定。首先排序該位置具有較小值的數組。如果較短數組的所有值都等於較長數組中的相應值,則首先排序較短的數組。
例:
[] < ["a"] < ["ab"] < ["ab", "cd", "ef"] < ["ab", "ef"]
-
BOOLEAN
JSON false文字小於JSON true literal。
-
OBJECT
如果兩個JSON對象具有相同的鍵集,則它們是相等的,並且每個鍵在兩個對象中具有相同的值。
例:
{"a": 1, "b": 2} = {"b": 2, "a": 1}
兩個不相等的對象的順序是未指定的但是確定性的。
-
STRING
字符串在被比較的兩個字符串
N
的utf8mb4
表示的第一個字節 上以詞法方式排序 ,其中N
是較短字符串的長度。如果N
兩個字符串的第一個 字節相同,則認為較短的字符串小於較長的字符串。例:
"a" < "ab" < "b" < "bc"
此排序等同於具有排序規則的SQL字符串的排序
utf8mb4_bin
。因為utf8mb4_bin
是二進制排序規則,JSON值的比較區分大小寫:"A" < "a"
-
INTEGER
,DOUBLE
JSON值可以包含精確值數字和近似值數字。有關這些類型數字的一般討論,請參見第9.1.2節“數字文字”。
第12.2節“表達式求值中的類型轉換” 中討論了比較本機MySQL數值類型的規則,但是比較JSON值中的數字的規則有所不同:
-
在分別使用本機MySQL
INT
和DOUBLE
數字類型的兩列之間的比較中,已知所有比較都涉及整數和雙精度,因此對於所有行,整數被轉換為double。也就是說,精確值數字被轉換為近似值數字。 -
另一方面,如果查詢比較包含數字的兩個JSON列,則無法預先知道數字是整數還是雙數。為了在所有行中提供最一致的行為,MySQL將近似值數字轉換為精確值數字。得到的排序是一致的,並且不會丟失精確值數字的精度。例如,給定標量9223372036854775805,9223372036854775806,9223372036854775807和9.223372036854776e18,順序如下:
9223372036854775805 < 9223372036854775806 < 9223372036854775807 < 9.223372036854776e18 = 9223372036854776000 < 9223372036854776001
如果JSON比較使用非JSON數字比較規則,則可能發生不一致的排序。通常的MySQL數字比較規則會產生以下排序:
-
整數比較:
9223372036854775805 < 9223372036854775806 < 9223372036854775807
(未定義為9.223372036854776e18)
-
雙重比較:
9223372036854775805 = 9223372036854775806 = 9223372036854775807 = 9.223372036854776e18
-
為了將任何JSON值與SQL進行比較NULL
,結果是UNKNOWN
。
為了比較JSON和非JSON值,根據下表中的規則將非JSON值轉換為JSON,然后如前所述比較值。
在JSON和非JSON值之間轉換
下表提供了MySQL在JSON值和其他類型的值之間進行轉換時遵循的規則的摘要:
表11.3 JSON轉換規則
其他類型 | CAST(其他類型AS JSON) | CAST(JSON AS其他類型) |
---|---|---|
JSON | 沒變 | 沒變 |
UTF8字符類型(utf8mb4 ,utf8 ,ascii ) |
該字符串被解析為JSON值。 | JSON值被序列化為utf8mb4 字符串。 |
其他字符類型 | 其他字符編碼隱式轉換 utf8mb4 為utf8字符類型所描述和處理。 |
JSON值被序列化為utf8mb4 字符串,然后轉換為其他字符編碼。結果可能沒有意義。 |
NULL |
結果NULL 為JSON類型的值。 |
不適用。 |
幾何類型 | 通過調用將幾何值轉換為JSON文檔 ST_AsGeoJSON() 。 |
非法操作。解決方法:將結果傳遞 給 。CAST( ST_GeomFromGeoJSON() |
所有其他類型 | 結果是由單個標量值組成的JSON文檔。 | 如果JSON文檔由目標類型的單個標量值組成,並且標量值可以強制轉換為目標類型,則成功。否則,返回NULL 並發出警告。 |
ORDER BY
並GROUP BY
為JSON值根據這些原則,工作原理:
-
標量JSON值的排序使用與前面討論中相同的規則。
-
對於升序排序,SQL
NULL
訂單在所有JSON值之前,包括JSON null文字; 對於降序排序,NULL
所有JSON值之后的SQL 順序,包括JSON空文字。 -
JSON值的排序鍵由
max_sort_length
系統變量的值綁定 ,因此僅在第一個max_sort_length
字節比較之后才相同的鍵 相等。 -
目前不支持對非標量值進行排序,並發出警告。
對於排序,將JSON標量轉換為其他一些本機MySQL類型可能是有益的。例如,如果名為jdoc
包含JSON對象的列 包含由id
鍵和非負值組成的成員,請使用此表達式按id
值排序:
ORDER BY CAST(JSON_EXTRACT(jdoc, '$.id') AS UNSIGNED)
如果確定生成的列定義為使用與其中相同的表達式ORDER BY
,則MySQL優化器會識別該值並考慮使用索引執行查詢執行計划。請參見 第8.3.10節“生成列索引的優化程序使用”。
JSON值的聚合
對於JSON值的聚合,SQL NULL
值將與其他數據類型一樣被忽略。非NULL
值被轉換為數字類型和聚合,除 MIN()
, MAX()
和 GROUP_CONCAT()
。轉換為數字應該為數字標量的JSON值產生有意義的結果,盡管(取決於值)可能會發生截斷和精度損失。轉換為其他JSON值的數量可能不會產生有意義的結果。
11.6 JSON數據類型
-
創建JSON值
-
JSON值的規范化,合並和自動包裝
-
搜索和修改JSON值
-
JSON值的比較和排序
-
在JSON和非JSON值之間轉換
-
JSON值的聚合
從MySQL 5.7.8開始,MySQL支持RFC 7159JSON
定義的本機數據類型 ,可以高效訪問JSON(JavaScript Object Notation)文檔中的數據。與在字符串列中存儲JSON格式字符串相比,數據類型具有以下優勢: JSON
-
自動驗證存儲在
JSON
列中的JSON文檔 。無效的文檔會產生錯誤。 -
優化的存儲格式。存儲在
JSON
列中的JSON文檔將 轉換為內部格式,以允許快速讀取文檔元素。當服務器稍后必須讀取以此二進制格式存儲的JSON值時,不需要從文本表示中解析該值。二進制格式的結構使服務器能夠直接通過鍵或數組索引查找子對象或嵌套值,而無需在文檔中讀取它們之前或之后的所有值。
此討論使用JSON
monotype來指定JSON數據類型和 常規字體中的“ JSON ”以指示一般的JSON數據。
存儲JSON
文檔所需的空間與LONGBLOB
或 大致相同LONGTEXT
; 有關更多信息,請參見 第11.8節“數據類型存儲要求”。請務必記住,JSON
列中存儲的任何JSON文檔的大小都限制為max_allowed_packet
系統變量的值。(當服務器在內存中內部操作JSON值時,它可能大於此值;當服務器存儲時,該限制適用。)
一JSON
列不能有默認值。
除了JSON
數據類型之外,還有一組SQL函數可用於對JSON值進行操作,例如創建,操作和搜索。以下討論顯示了這些操作的示例。有關各個函數的詳細信息,請參見第12.16節“JSON函數”。
還提供了一組用於操作GeoJSON值的空間函數。請參見第12.15.11節“空間GeoJSON函數”。
JSON
列,與其他二進制類型的列一樣,不直接索引; 相反,您可以在生成的列上創建索引,從列中提取標量值 JSON
。有關詳細示例,請參閱 索引生成的列以提供JSON列索引。
MySQL優化器還在與JSON表達式匹配的虛擬列上查找兼容索引。
MySQL NDB Cluster 7.5(7.5.2及更高版本)支持 JSON
列和MySQL JSON函數,包括在列生成的JSON
列上創建索引 ,作為無法索引JSON
列的變通方法。JSON
每個NDB
表最多支持3列 。
接下來的幾節提供了有關JSON值的創建和操作的基本信息。
創建JSON值
JSON數組包含一個由逗號分隔的值列表,並包含在 字符[
和]
字符中:
["abc", 10, null, true, false]
JSON對象包含一組由逗號分隔的鍵值對,並包含在字符{
和 }
字符中:
{"k1": "value", "k2": 10}
如示例所示,JSON數組和對象可以包含字符串或數字的標量值,JSON空文字或JSON布爾值true或false文字。JSON對象中的鍵必須是字符串。時間(日期,時間或日期時間)標量值也是允許的:
["12:18:29.000000", "2015-07-29", "2015-07-29 12:18:29.000000"]
JSON數組元素和JSON對象鍵值允許嵌套:
[99, {"id": "HK500", "cost": 75.99}, ["hot", "cold"]]
{"k1": "value", "k2": [10, 20]}
您還可以為此目的從MySQL提供的許多函數中獲取JSON值(請參見 第12.16.2節“創建JSON值的函數”)以及JSON
使用其他類型的值轉換為類型 (請參閱 在JSON之間轉換)和非JSON值)。接下來的幾段描述了MySQL如何處理作為輸入提供的JSON值。 CAST(
value
AS JSON)
在MySQL中,JSON值被寫為字符串。MySQL解析在需要JSON值的上下文中使用的任何字符串,如果它作為JSON無效則會產生錯誤。這些上下文包括將值插入到具有JSON
數據類型的列中, 並將參數傳遞給需要JSON值的函數(通常顯示為 json_doc
或 json_val
在MySQL JSON函數的文檔中),如以下示例所示:
-
JSON
如果值是有效的JSON值,則 嘗試將值插入列成功,但如果不是,則嘗試失敗:mysql> CREATE TABLE t1 (jdoc JSON); Query OK, 0 rows affected (0.20 sec) mysql> INSERT INTO t1 VALUES('{"key1": "value1", "key2": "value2"}'); Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO t1 VALUES('[1, 2,'); ERROR 3140 (22032) at line 2: Invalid JSON text: "Invalid value." at position 6 in value (or column) '[1, 2,'.
為位置“ 在位置
N
”在這樣的錯誤消息是基於0的,但應考慮其中一個值問題實際發生的粗指示。 -
該
JSON_TYPE()
函數需要一個JSON參數並嘗試將其解析為JSON值。如果值有效,則返回值的JSON類型,否則產生錯誤:mysql> SELECT JSON_TYPE('["a", "b", 1]'); +----------------------------+ | JSON_TYPE('["a", "b", 1]') | +----------------------------+ | ARRAY | +----------------------------+ mysql> SELECT JSON_TYPE('"hello"'); +----------------------+ | JSON_TYPE('"hello"') | +----------------------+ | STRING | +----------------------+ mysql> SELECT JSON_TYPE('hello'); ERROR 3146 (22032): Invalid data type for JSON data in argument 1 to function json_type; a JSON string or JSON type is required.
MySQL使用utf8mb4
字符集和utf8mb4_bin
排序規則處理JSON上下文中使用的 字符串 。其他字符集中的字符串將utf8mb4
根據需要進行轉換。(對於在串ascii
或 utf8
字符集,則不需要轉換,因為ascii
和utf8
都是的子集utf8mb4
。)
作為使用文字字符串編寫JSON值的替代方法,存在用於從組件元素組成JSON值的函數。JSON_ARRAY()
獲取(可能為空)值列表並返回包含這些值的JSON數組:
mysql> SELECT JSON_ARRAY('a', 1, NOW());
+----------------------------------------+
| JSON_ARRAY('a', 1, NOW()) |
+----------------------------------------+
| ["a", 1, "2015-07-27 09:43:47.000000"] |
+----------------------------------------+
JSON_OBJECT()
獲取一個(可能是空的)鍵值對列表,並返回包含這些對的JSON對象:
mysql> SELECT JSON_OBJECT('key1', 1, 'key2', 'abc');
+---------------------------------------+
| JSON_OBJECT('key1', 1, 'key2', 'abc') |
+---------------------------------------+
| {"key1": 1, "key2": "abc"} |
+---------------------------------------+
JSON_MERGE()
獲取兩個或多個JSON文檔並返回組合結果:
mysql> SELECT JSON_MERGE('["a", 1]', '{"key": "value"}');
+--------------------------------------------+
| JSON_MERGE('["a", 1]', '{"key": "value"}') |
+--------------------------------------------+
| ["a", 1, {"key": "value"}] |
+--------------------------------------------+
有關合並規則的信息,請參閱 JSON值的規范化,合並和自動包裝。
可以將JSON值分配給用戶定義的變量:
mysql> SET @j = JSON_OBJECT('key', 'value');
mysql> SELECT @j;
+------------------+
| @j |
+------------------+
| {"key": "value"} |
+------------------+
但是,用戶定義的變量不能是 JSON
數據類型,所以雖然 @j
在前面的例子中看起來像一個JSON值並且具有相同的字符集和歸類為JSON值,但它不具有 JSON
數據類型。相反,結果from JSON_OBJECT()
在分配給變量時會轉換為字符串。
通過轉換JSON值生成的字符串具有以下字符集utf8mb4
和排序規則 utf8mb4_bin
:
mysql> SELECT CHARSET(@j), COLLATION(@j);
+-------------+---------------+
| CHARSET(@j) | COLLATION(@j) |
+-------------+---------------+
| utf8mb4 | utf8mb4_bin |
+-------------+---------------+
因為utf8mb4_bin
是二進制排序規則,所以JSON值的比較區分大小寫。
mysql> SELECT JSON_ARRAY('x') = JSON_ARRAY('X');
+-----------------------------------+
| JSON_ARRAY('x') = JSON_ARRAY('X') |
+-----------------------------------+
| 0 |
+-----------------------------------+
區分大小寫也適用於JSON null
,true
和 false
文字,它們必須始終以小寫形式編寫:
mysql> SELECT JSON_VALID('null'), JSON_VALID('Null'), JSON_VALID('NULL');
+--------------------+--------------------+--------------------+
| JSON_VALID('null') | JSON_VALID('Null') | JSON_VALID('NULL') |
+--------------------+--------------------+--------------------+
| 1 | 0 | 0 |
+--------------------+--------------------+--------------------+
mysql> SELECT CAST('null' AS JSON);
+----------------------+
| CAST('null' AS JSON) |
+----------------------+
| null |
+----------------------+
1 row in set (0.00 sec)
mysql> SELECT CAST('NULL' AS JSON);
ERROR 3141 (22032): Invalid JSON text in argument 1 to function cast_as_json: "Invalid value." at position 0 in 'NULL'.
的字面JSON的情況下,靈敏度不同於所述SQL的NULL
,TRUE
和 FALSE
文字,它可以在任何大小寫被寫成:
mysql> SELECT ISNULL(null), ISNULL(Null), ISNULL(NULL);
+--------------+--------------+--------------+
| ISNULL(null) | ISNULL(Null) | ISNULL(NULL) |
+--------------+--------------+--------------+
| 1 | 1 | 1 |
+--------------+--------------+--------------+
有時可能需要或希望將引號字符("
或'
)插入JSON文檔中。假設您希望在此示例中插入一些JSON對象,這些對象包含表示有關MySQL的一些事實的句子,每個句子都與適當的關鍵字配對,使用此處顯示的SQL語句創建的表:
mysql> CREATE TABLE facts (sentence JSON);
這些關鍵詞 - 句子對中有這一個:
mascot: The MySQL mascot is a dolphin named "Sakila".
將此作為JSON對象插入facts
表中的一種方法 是使用MySQL JSON_OBJECT()
函數。在這種情況下,您必須使用反斜杠轉義每個引號字符,如下所示:
mysql> INSERT INTO facts VALUES
> (JSON_OBJECT("mascot", "Our mascot is a dolphin named \"Sakila\"."));
如果將值作為JSON對象文字插入,則此方法不起作用,在這種情況下,必須使用雙反斜杠轉義序列,如下所示:
mysql> INSERT INTO facts VALUES
> ('{"mascot": "Our mascot is a dolphin named \\"Sakila\\"."}');
使用雙反斜杠可以防止MySQL執行轉義序列處理,而是使它將字符串文字傳遞給存儲引擎進行處理。以剛才顯示的方式插入JSON對象后,您可以通過執行簡單操作看到反斜杠存在於JSON列值中SELECT
,如下所示:
mysql> SELECT sentence FROM facts;
+---------------------------------------------------------+
| sentence |
+---------------------------------------------------------+
| {"mascot": "Our mascot is a dolphin named \"Sakila\"."} |
+---------------------------------------------------------+
要使用mascot
鍵作為查找此特定句子 ,可以使用column-path運算符 ->
,如下所示:
mysql> SELECT col->"$.mascot" FROM qtest;
+---------------------------------------------+
| col->"$.mascot" |
+---------------------------------------------+
| "Our mascot is a dolphin named \"Sakila\"." |
+---------------------------------------------+
1 row in set (0.00 sec)
這樣就可以保留反斜杠以及周圍的引號。要使用mascot
鍵作為鍵顯示所需的值 ,但不包括周圍的引號或任何轉義符->>
,請使用內聯路徑運算符 ,如下所示:
mysql> SELECT sentence->>"$.mascot" FROM facts;
+-----------------------------------------+
| sentence->>"$.mascot" |
+-----------------------------------------+
| Our mascot is a dolphin named "Sakila". |
+-----------------------------------------+
如果NO_BACKSLASH_ESCAPES
啟用了服務器SQL模式,則前面的示例無法正常工作 。如果設置了此模式,則可以使用單個反斜杠而不是雙反斜杠來插入JSON對象文字,並保留反斜杠。如果JSON_OBJECT()
在執行插入時使用該功能並且設置了此模式,則必須替換單引號和雙引號,如下所示:
mysql> INSERT INTO facts VALUES
> (JSON_OBJECT('mascot', 'Our mascot is a dolphin named "Sakila".'));
有關JSON_UNQUOTE()
此模式對JSON值中的轉義字符的影響的詳細信息,請參閱該函數的說明 。
JSON值的規范化,合並和自動包裝
當解析一個字符串並發現它是一個有效的JSON文檔時,它也會被標准化:具有復制在文檔中較早找到的鍵的鍵的成員將被丟棄(即使值不同)。以下JSON_OBJECT()
調用生成的對象值 不包括第二個key1
元素,因為該鍵名稱出現在值的前面:
mysql> SELECT JSON_OBJECT('key1', 1, 'key2', 'abc', 'key1', 'def');
+------------------------------------------------------+
| JSON_OBJECT('key1', 1, 'key2', 'abc', 'key1', 'def') |
+------------------------------------------------------+
| {"key1": 1, "key2": "abc"} |
+------------------------------------------------------+
重復密鑰的 這種“ 第一關鍵勝利 ”處理與RFC 7159不一致 。這是MySQL 5.7中的已知問題,已在MySQL 8.0中修復。(Bug#86866,Bug#26369555)
MySQL還會丟棄原始JSON文檔中的鍵,值或元素之間的額外空格。為了使查找更有效,它還對JSON對象的鍵進行排序。 您應該知道,此排序的結果可能會發生變化,並且不保證在各個版本中保持一致。
生成JSON值的MySQL函數(請參見 第12.16.2節“創建JSON值的函數”)始終返回規范化值。
合並JSON值
在組合多個數組的上下文中,通過將稍后命名的數組連接到第一個數組的末尾,將數組合並為單個數組。在以下示例中, JSON_MERGE()
將其參數合並為單個數組:
mysql> SELECT JSON_MERGE('[1, 2]', '["a", "b"]', '[true, false]');
+-----------------------------------------------------+
| JSON_MERGE('[1, 2]', '["a", "b"]', '[true, false]') |
+-----------------------------------------------------+
| [1, 2, "a", "b", true, false] |
+-----------------------------------------------------+
將值插入JSON列時也會執行規范化,如下所示:
mysql> CREATE TABLE t1 (c1 JSON);
mysql> INSERT INTO t1 VALUES
> ('{"x": 17, "x": "red"}'),
> ('{"x": 17, "x": "red", "x": [3, 5, 7]}');
mysql> SELECT c1 FROM t1;
+-----------+
| c1 |
+-----------+
| {"x": 17} |
| {"x": 17} |
+-----------+
合並時的多個對象生成單個對象。如果多個對象具有相同的鍵,則生成的合並對象中該鍵的值是包含鍵值的數組:
mysql> SELECT JSON_MERGE('{"a": 1, "b": 2}', '{"c": 3, "a": 4}');
+----------------------------------------------------+
| JSON_MERGE('{"a": 1, "b": 2}', '{"c": 3, "a": 4}') |
+----------------------------------------------------+
| {"a": [1, 4], "b": 2, "c": 3} |
+----------------------------------------------------+
在需要數組值的上下文中使用的非陣列值是自動封裝的:該值由[
和]
字符包圍以將其轉換為數組。在以下語句中,每個參數都自動包裝為數組([1]
,[2]
)。然后將它們合並以生成單個結果數組:
mysql> SELECT JSON_MERGE('1', '2');
+----------------------+
| JSON_MERGE('1', '2') |
+----------------------+
| [1, 2] |
+----------------------+
通過將對象自動包裝為數組並合並兩個數組來合並數組和對象值:
mysql> SELECT JSON_MERGE('[10, 20]', '{"a": "x", "b": "y"}');
+------------------------------------------------+
| JSON_MERGE('[10, 20]', '{"a": "x", "b": "y"}') |
+------------------------------------------------+
| [10, 20, {"a": "x", "b": "y"}] |
+------------------------------------------------+
搜索和修改JSON值
JSON路徑表達式選擇JSON文檔中的值。
路徑表達式對於提取JSON文檔的一部分或修改JSON文檔的函數非常有用,以指定該文檔中的操作位置。例如,以下查詢從JSON文檔中提取具有name
鍵的成員的值 :
mysql> SELECT JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name');
+---------------------------------------------------------+
| JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name') |
+---------------------------------------------------------+
| "Aztalan" |
+---------------------------------------------------------+
路徑語法使用前導$
字符來表示正在考慮的JSON文檔,可選地后跟選擇器,它們連續指示文檔的更具體部分:
-
后跟密鑰名稱的句點使用給定密鑰命名對象中的成員。如果沒有引號的名稱在路徑表達式中不合法(例如,如果它包含空格),則必須在雙引號內指定鍵名。
-
[
附加到aN
]path
,選擇一個數組命名數組中位置的值N
。數組位置是從零開始的整數。如果path
未選擇數組值,path
[0]計算的值與path
以下相同 :mysql> SELECT JSON_SET('"x"', '$[0]', 'a'); +------------------------------+ | JSON_SET('"x"', '$[0]', 'a') | +------------------------------+ | "a" | +------------------------------+ 1 row in set (0.00 sec)
-
路徑可以包含
*
或**
通配符:-
.[*]
計算JSON對象中所有成員的值。 -
[*]
計算JSON數組中所有元素的值。 -
計算所有以命名前綴開頭並以命名后綴結尾的路徑。prefix
**suffix
-
-
文檔中不存在的路徑(評估為不存在的數據)的計算結果為
NULL
。
讓我們$
用三個元素來引用這個JSON數組:
[3, {"a": [5, 6], "b": 10}, [99, 100]]
然后:
-
$[0]
評估為3
。 -
$[1]
評估為{"a": [5, 6], "b": 10}
。 -
$[2]
評估為[99, 100]
。 -
$[3]
求值為NULL
(它指的是第四個不存在的數組元素)。
因為$[1]
並且$[2]
評估為非標量值,所以它們可以用作選擇嵌套值的更具體路徑表達式的基礎。例子:
-
$[1].a
評估為[5, 6]
。 -
$[1].a[1]
評估為6
。 -
$[1].b
評估為10
。 -
$[2][0]
評估為99
。
如前所述,如果路徑表達式中的未加引號的鍵名稱不合法,則必須引用命名鍵的路徑組件。讓我們$
參考這個值:
{"a fish": "shark", "a bird": "sparrow"}
密鑰都包含空格,必須引用:
-
$."a fish"
評估為shark
。 -
$."a bird"
評估為sparrow
。
使用通配符的路徑計算為可包含多個值的數組:
mysql> SELECT JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.*');
+---------------------------------------------------------+
| JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.*') |
+---------------------------------------------------------+
| [1, 2, [3, 4, 5]] |
+---------------------------------------------------------+
mysql> SELECT JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.c[*]');
+------------------------------------------------------------+
| JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.c[*]') |
+------------------------------------------------------------+
| [3, 4, 5] |
+------------------------------------------------------------+
在以下示例中,路徑$**.b
計算為多個路徑($.a.b
和 $.c.b
)並生成匹配路徑值的數組:
mysql> SELECT JSON_EXTRACT('{"a": {"b": 1}, "c": {"b": 2}}', '$**.b');
+---------------------------------------------------------+
| JSON_EXTRACT('{"a": {"b": 1}, "c": {"b": 2}}', '$**.b') |
+---------------------------------------------------------+
| [1, 2] |
+---------------------------------------------------------+
在MySQL 5.7.9及更高版本中,您可以使用 JSON列標識符和JSON路徑表達式作為同義詞 。有關更多信息,請參見 第12.16.3節“搜索JSON值的函數”。另請參見索引生成的列以提供JSON列索引。 column
->path
JSON_EXTRACT(
column
, path
)
某些函數采用現有的JSON文檔,以某種方式對其進行修改,並返回生成的修改后的文檔。路徑表達式指示文檔中的更改位置。例如,JSON_SET()
, JSON_INSERT()
,和JSON_REPLACE()
功能各采取JSON文檔,再加上描述其中修改文檔和使用的值的一個或多個路徑/值對。這些函數在處理文檔中的現有值和不存在值方面有所不同。
考慮這個文件:
mysql> SET @j = '["a", {"b": [true, false]}, [10, 20]]';
JSON_SET()
替換存在的路徑的值,並為不存在的路徑添加值:
mysql> SELECT JSON_SET(@j, '$[1].b[0]', 1, '$[2][2]', 2);
+--------------------------------------------+
| JSON_SET(@j, '$[1].b[0]', 1, '$[2][2]', 2) |
+--------------------------------------------+
| ["a", {"b": [1, false]}, [10, 20, 2]] |
+--------------------------------------------+
在這種情況下,路徑$[1].b[0]
選擇一個現有值(true
),該值將替換為path參數(1
)后面的值。該路徑$[2][2]
不存在,因此相應的值(2
)將添加到所選的值$[2]
。
JSON_INSERT()
添加新值但不替換現有值:
mysql> SELECT JSON_INSERT(@j, '$[1].b[0]', 1, '$[2][2]', 2);
+-----------------------------------------------+
| JSON_INSERT(@j, '$[1].b[0]', 1, '$[2][2]', 2) |
+-----------------------------------------------+
| ["a", {"b": [true, false]}, [10, 20, 2]] |
+-----------------------------------------------+
JSON_REPLACE()
替換現有值並忽略新值:
mysql> SELECT JSON_REPLACE(@j, '$[1].b[0]', 1, '$[2][2]', 2);
+------------------------------------------------+
| JSON_REPLACE(@j, '$[1].b[0]', 1, '$[2][2]', 2) |
+------------------------------------------------+
| ["a", {"b": [1, false]}, [10, 20]] |
+------------------------------------------------+
路徑/值對從左到右進行評估。通過評估一對產生的文檔成為評估下一對的新值。
JSON_REMOVE()
獲取JSON文檔和一個或多個指定要從文檔中刪除的值的路徑。返回值是原始文檔減去文檔中存在的路徑選擇的值:
mysql> SELECT JSON_REMOVE(@j, '$[2]', '$[1].b[1]', '$[1].b[1]');
+---------------------------------------------------+
| JSON_REMOVE(@j, '$[2]', '$[1].b[1]', '$[1].b[1]') |
+---------------------------------------------------+
| ["a", {"b": [true]}] |
+---------------------------------------------------+
路徑有這些影響:
-
$[2]
匹配[10, 20]
並刪除它。 -
的第一個實例
$[1].b[1]
相匹配false
的b
元素並將其刪除。 -
$[1].b[1]
匹配 的第二個實例沒有:該元素已被刪除,路徑不再存在,並且無效。
JSON值的比較和排序
JSON值可以使用進行比較 =
, <
, <=
, >
, >=
, <>
, !=
,和 <=>
運營商。
JSON值尚不支持以下比較運算符和函數:
-
BETWEEN
-
IN()
-
GREATEST()
-
LEAST()
剛才列出的比較運算符和函數的解決方法是將JSON值轉換為本機MySQL數值或字符串數據類型,以便它們具有一致的非JSON標量類型。
JSON值的比較發生在兩個級別。第一級比較基於比較值的JSON類型。如果類型不同,則比較結果僅由哪種類型具有更高優先級來確定。如果這兩個值具有相同的JSON類型,則使用特定於類型的規則進行第二級比較。
以下列表顯示了JSON類型的優先級,從最高優先級到最低優先級。(類型名稱是JSON_TYPE()
函數返回的類型名稱。)一行顯示的類型具有相同的優先級。列表中前面列出的任何具有JSON類型的值都比列表中稍后列出的具有JSON類型的任何值都要大。
BLOB
BIT
OPAQUE
DATETIME
TIME
DATE
BOOLEAN
ARRAY
OBJECT
STRING
INTEGER, DOUBLE
NULL
對於具有相同優先級的JSON值,比較規則是特定於類型的:
-
BLOB
N
比較兩個值 的第一個字節,其中N
是較短值中的字節數。如果N
兩個值的第一個 字節相同,則在較長值之前排序較短的值。 -
BIT
與...相同的規則
BLOB
。 -
OPAQUE
與...相同的規則
BLOB
。OPAQUE
值是未歸類為其他類型之一的值。 -
DATETIME
表示較早時間點的值在表示稍后時間點的值之前排序。如果兩個值最初 分別來自MySQL
DATETIME
和TIMESTAMP
類型,則它們相等,如果它們代表相同的時間點。 -
TIME
兩個時間值中較小的一個在較大的值之前排序。
-
DATE
較早的日期是在最近的日期之前訂購的。
-
ARRAY
如果兩個JSON數組具有相同的長度並且數組中相應位置的值相等,則它們是相等的。
如果數組不相等,則它們的順序由第一個位置中存在差異的元素確定。首先排序該位置具有較小值的數組。如果較短數組的所有值都等於較長數組中的相應值,則首先排序較短的數組。
例:
[] < ["a"] < ["ab"] < ["ab", "cd", "ef"] < ["ab", "ef"]
-
BOOLEAN
JSON false文字小於JSON true literal。
-
OBJECT
如果兩個JSON對象具有相同的鍵集,則它們是相等的,並且每個鍵在兩個對象中具有相同的值。
例:
{"a": 1, "b": 2} = {"b": 2, "a": 1}
兩個不相等的對象的順序是未指定的但是確定性的。
-
STRING
字符串在被比較的兩個字符串
N
的utf8mb4
表示的第一個字節 上以詞法方式排序 ,其中N
是較短字符串的長度。如果N
兩個字符串的第一個 字節相同,則認為較短的字符串小於較長的字符串。例:
"a" < "ab" < "b" < "bc"
此排序等同於具有排序規則的SQL字符串的排序
utf8mb4_bin
。因為utf8mb4_bin
是二進制排序規則,JSON值的比較區分大小寫:"A" < "a"
-
INTEGER
,DOUBLE
JSON值可以包含精確值數字和近似值數字。有關這些類型數字的一般討論,請參見第9.1.2節“數字文字”。
第12.2節“表達式求值中的類型轉換” 中討論了比較本機MySQL數值類型的規則,但是比較JSON值中的數字的規則有所不同:
-
在分別使用本機MySQL
INT
和DOUBLE
數字類型的兩列之間的比較中,已知所有比較都涉及整數和雙精度,因此對於所有行,整數被轉換為double。也就是說,精確值數字被轉換為近似值數字。 -
另一方面,如果查詢比較包含數字的兩個JSON列,則無法預先知道數字是整數還是雙數。為了在所有行中提供最一致的行為,MySQL將近似值數字轉換為精確值數字。得到的排序是一致的,並且不會丟失精確值數字的精度。例如,給定標量9223372036854775805,9223372036854775806,9223372036854775807和9.223372036854776e18,順序如下:
9223372036854775805 < 9223372036854775806 < 9223372036854775807 < 9.223372036854776e18 = 9223372036854776000 < 9223372036854776001
如果JSON比較使用非JSON數字比較規則,則可能發生不一致的排序。通常的MySQL數字比較規則會產生以下排序:
-
整數比較:
9223372036854775805 < 9223372036854775806 < 9223372036854775807
(未定義為9.223372036854776e18)
-
雙重比較:
9223372036854775805 = 9223372036854775806 = 9223372036854775807 = 9.223372036854776e18
-
為了將任何JSON值與SQL進行比較NULL
,結果是UNKNOWN
。
為了比較JSON和非JSON值,根據下表中的規則將非JSON值轉換為JSON,然后如前所述比較值。
在JSON和非JSON值之間轉換
下表提供了MySQL在JSON值和其他類型的值之間進行轉換時遵循的規則的摘要:
表11.3 JSON轉換規則
其他類型 | CAST(其他類型AS JSON) | CAST(JSON AS其他類型) |
---|---|---|
JSON | 沒變 | 沒變 |
UTF8字符類型(utf8mb4 ,utf8 ,ascii ) |
該字符串被解析為JSON值。 | JSON值被序列化為utf8mb4 字符串。 |
其他字符類型 | 其他字符編碼隱式轉換 utf8mb4 為utf8字符類型所描述和處理。 |
JSON值被序列化為utf8mb4 字符串,然后轉換為其他字符編碼。結果可能沒有意義。 |
NULL |
結果NULL 為JSON類型的值。 |
不適用。 |
幾何類型 | 通過調用將幾何值轉換為JSON文檔 ST_AsGeoJSON() 。 |
非法操作。解決方法:將結果傳遞 給 。CAST( ST_GeomFromGeoJSON() |
所有其他類型 | 結果是由單個標量值組成的JSON文檔。 | 如果JSON文檔由目標類型的單個標量值組成,並且標量值可以強制轉換為目標類型,則成功。否則,返回NULL 並發出警告。 |
ORDER BY
並GROUP BY
為JSON值根據這些原則,工作原理:
-
標量JSON值的排序使用與前面討論中相同的規則。
-
對於升序排序,SQL
NULL
訂單在所有JSON值之前,包括JSON null文字; 對於降序排序,NULL
所有JSON值之后的SQL 順序,包括JSON空文字。 -
JSON值的排序鍵由
max_sort_length
系統變量的值綁定 ,因此僅在第一個max_sort_length
字節比較之后才相同的鍵 相等。 -
目前不支持對非標量值進行排序,並發出警告。
對於排序,將JSON標量轉換為其他一些本機MySQL類型可能是有益的。例如,如果名為jdoc
包含JSON對象的列 包含由id
鍵和非負值組成的成員,請使用此表達式按id
值排序:
ORDER BY CAST(JSON_EXTRACT(jdoc, '$.id') AS UNSIGNED)
如果確定生成的列定義為使用與其中相同的表達式ORDER BY
,則MySQL優化器會識別該值並考慮使用索引執行查詢執行計划。請參見 第8.3.10節“生成列索引的優化程序使用”。
JSON值的聚合
對於JSON值的聚合,SQL NULL
值將與其他數據類型一樣被忽略。非NULL
值被轉換為數字類型和聚合,除 MIN()
, MAX()
和 GROUP_CONCAT()
。轉換為數字應該為數字標量的JSON值產生有意義的結果,盡管(取決於值)可能會發生截斷和精度損失。轉換為其他JSON值的數量可能不會產生有意義的結果。
總結與實例: