文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 參考手冊  /  ...  /  搜尋 JSON 值的函數

14.17.3 搜尋 JSON 值的函數

本節中的函數會對 JSON 值執行搜尋或比較運算,以便從中擷取資料、報告資料是否存在於其中的某個位置,或報告資料在其中的路徑。此處也會記錄 MEMBER OF() 運算子。

  • JSON_CONTAINS(target, candidate[, path])

    透過傳回 1 或 0 來表示指定的 candidate JSON 文件是否包含在 target JSON 文件中,或者如果提供 path 引數,則表示是否在目標內的特定路徑找到候選項目。如果任何引數為 NULL,或路徑引數未識別目標文件的區段,則傳回 NULL。如果 targetcandidate 不是有效的 JSON 文件,或者如果 path 引數不是有效的路徑表達式或包含 *** 萬用字元,則會發生錯誤。

    若要僅檢查路徑上是否有任何資料存在,請改用 JSON_CONTAINS_PATH()

    下列規則定義包含關係

    • 當候選純量和目標純量可以比較且相等時,候選純量會包含在目標純量中。如果兩個純量值具有相同的 JSON_TYPE() 類型,則可以比較它們,但 INTEGERDECIMAL 類型的值也可以彼此比較。

    • 如果候選陣列中的每個元素都包含在目標陣列的某個元素中,則候選陣列會包含在目標陣列中。

    • 如果候選非陣列包含在目標陣列的某個元素中,則候選非陣列會包含在目標陣列中。

    • 如果候選物件中每個索引鍵在目標中都有同名的索引鍵,且與候選索引鍵關聯的值包含在與目標索引鍵關聯的值中,則候選物件會包含在目標物件中。

    否則,候選值不會包含在目標文件中。

    使用 JSON_CONTAINS()InnoDB 表格上執行的查詢可以使用多值索引進行最佳化;如需更多資訊,請參閱多值索引

    mysql> SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
    mysql> SET @j2 = '1';
    mysql> SELECT JSON_CONTAINS(@j, @j2, '$.a');
    +-------------------------------+
    | JSON_CONTAINS(@j, @j2, '$.a') |
    +-------------------------------+
    |                             1 |
    +-------------------------------+
    mysql> SELECT JSON_CONTAINS(@j, @j2, '$.b');
    +-------------------------------+
    | JSON_CONTAINS(@j, @j2, '$.b') |
    +-------------------------------+
    |                             0 |
    +-------------------------------+
    
    mysql> SET @j2 = '{"d": 4}';
    mysql> SELECT JSON_CONTAINS(@j, @j2, '$.a');
    +-------------------------------+
    | JSON_CONTAINS(@j, @j2, '$.a') |
    +-------------------------------+
    |                             0 |
    +-------------------------------+
    mysql> SELECT JSON_CONTAINS(@j, @j2, '$.c');
    +-------------------------------+
    | JSON_CONTAINS(@j, @j2, '$.c') |
    +-------------------------------+
    |                             1 |
    +-------------------------------+
  • JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] ...)

    傳回 0 或 1,以表示 JSON 文件是否在給定的路徑或多個路徑包含資料。如果任何引數為 NULL,則傳回 NULL。如果 json_doc 引數不是有效的 JSON 文件,任何 path 引數不是有效的路徑表達式,或者 one_or_all 不是 'one''all',則會發生錯誤。

    若要檢查路徑上是否有特定值,請改用 JSON_CONTAINS()

    如果文件中沒有指定的路徑存在,則傳回值為 0。否則,傳回值取決於 one_or_all 引數

    • 'one':如果文件中至少存在一個路徑,則為 1,否則為 0。

    • 'all':如果文件中存在所有路徑,則為 1,否則為 0。

    mysql> SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
    mysql> SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a', '$.e');
    +---------------------------------------------+
    | JSON_CONTAINS_PATH(@j, 'one', '$.a', '$.e') |
    +---------------------------------------------+
    |                                           1 |
    +---------------------------------------------+
    mysql> SELECT JSON_CONTAINS_PATH(@j, 'all', '$.a', '$.e');
    +---------------------------------------------+
    | JSON_CONTAINS_PATH(@j, 'all', '$.a', '$.e') |
    +---------------------------------------------+
    |                                           0 |
    +---------------------------------------------+
    mysql> SELECT JSON_CONTAINS_PATH(@j, 'one', '$.c.d');
    +----------------------------------------+
    | JSON_CONTAINS_PATH(@j, 'one', '$.c.d') |
    +----------------------------------------+
    |                                      1 |
    +----------------------------------------+
    mysql> SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a.d');
    +----------------------------------------+
    | JSON_CONTAINS_PATH(@j, 'one', '$.a.d') |
    +----------------------------------------+
    |                                      0 |
    +----------------------------------------+
  • JSON_EXTRACT(json_doc, path[, path] ...)

    從 JSON 文件傳回資料,該資料是從 path 引數比對的文件部分選取的。如果任何引數為 NULL,或沒有任何路徑在文件中找到值,則傳回 NULL。如果 json_doc 引數不是有效的 JSON 文件,或任何 path 引數不是有效的路徑表達式,則會發生錯誤。

    傳回值包含所有符合 path 引數的值。如果這些引數可能會傳回多個值,則符合的值會自動包裝成陣列,其順序對應於產生這些值的路徑。否則,傳回值會是單一符合的值。

    mysql> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]');
    +--------------------------------------------+
    | JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]') |
    +--------------------------------------------+
    | 20                                         |
    +--------------------------------------------+
    mysql> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]', '$[0]');
    +----------------------------------------------------+
    | JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]', '$[0]') |
    +----------------------------------------------------+
    | [20, 10]                                           |
    +----------------------------------------------------+
    mysql> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[2][*]');
    +-----------------------------------------------+
    | JSON_EXTRACT('[10, 20, [30, 40]]', '$[2][*]') |
    +-----------------------------------------------+
    | [30, 40]                                      |
    +-----------------------------------------------+

    MySQL 支援 -> 運算子,作為此函數的簡寫,用於帶有 2 個引數的情況,其中左側是 JSON 資料欄識別符 (而非運算式),右側是要在資料欄中比對的 JSON 路徑。

  • column->path

    -> 運算子與兩個引數一起使用時,它會作為 JSON_EXTRACT() 函數的別名,左側為資料欄識別符,右側為 JSON 路徑 (字串常值),並針對 JSON 文件 (資料欄值) 進行評估。您可以在 SQL 陳述式中任何出現資料欄參照的位置使用此類運算式。

    這裡顯示的兩個 SELECT 陳述式會產生相同的輸出

    mysql> SELECT c, JSON_EXTRACT(c, "$.id"), g
         > FROM jemp
         > WHERE JSON_EXTRACT(c, "$.id") > 1
         > ORDER BY JSON_EXTRACT(c, "$.name");
    +-------------------------------+-----------+------+
    | c                             | c->"$.id" | g    |
    +-------------------------------+-----------+------+
    | {"id": "3", "name": "Barney"} | "3"       |    3 |
    | {"id": "4", "name": "Betty"}  | "4"       |    4 |
    | {"id": "2", "name": "Wilma"}  | "2"       |    2 |
    +-------------------------------+-----------+------+
    3 rows in set (0.00 sec)
    
    mysql> SELECT c, c->"$.id", g
         > FROM jemp
         > WHERE c->"$.id" > 1
         > ORDER BY c->"$.name";
    +-------------------------------+-----------+------+
    | c                             | c->"$.id" | g    |
    +-------------------------------+-----------+------+
    | {"id": "3", "name": "Barney"} | "3"       |    3 |
    | {"id": "4", "name": "Betty"}  | "4"       |    4 |
    | {"id": "2", "name": "Wilma"}  | "2"       |    2 |
    +-------------------------------+-----------+------+
    3 rows in set (0.00 sec)

    此功能不限於 SELECT,如下所示

    mysql> ALTER TABLE jemp ADD COLUMN n INT;
    Query OK, 0 rows affected (0.68 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> UPDATE jemp SET n=1 WHERE c->"$.id" = "4";
    Query OK, 1 row affected (0.04 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT c, c->"$.id", g, n
         > FROM jemp
         > WHERE JSON_EXTRACT(c, "$.id") > 1
         > ORDER BY c->"$.name";
    +-------------------------------+-----------+------+------+
    | c                             | c->"$.id" | g    | n    |
    +-------------------------------+-----------+------+------+
    | {"id": "3", "name": "Barney"} | "3"       |    3 | NULL |
    | {"id": "4", "name": "Betty"}  | "4"       |    4 |    1 |
    | {"id": "2", "name": "Wilma"}  | "2"       |    2 | NULL |
    +-------------------------------+-----------+------+------+
    3 rows in set (0.00 sec)
    
    mysql> DELETE FROM jemp WHERE c->"$.id" = "4";
    Query OK, 1 row affected (0.04 sec)
    
    mysql> SELECT c, c->"$.id", g, n
         > FROM jemp
         > WHERE JSON_EXTRACT(c, "$.id") > 1
         > ORDER BY c->"$.name";
    +-------------------------------+-----------+------+------+
    | c                             | c->"$.id" | g    | n    |
    +-------------------------------+-----------+------+------+
    | {"id": "3", "name": "Barney"} | "3"       |    3 | NULL |
    | {"id": "2", "name": "Wilma"}  | "2"       |    2 | NULL |
    +-------------------------------+-----------+------+------+
    2 rows in set (0.00 sec)

    (如需用於建立和填入剛剛顯示的資料表的陳述式,請參閱 為 JSON 資料欄索引提供索引的產生資料欄。)

    這也適用於 JSON 陣列值,如下所示

    mysql> CREATE TABLE tj10 (a JSON, b INT);
    Query OK, 0 rows affected (0.26 sec)
    
    mysql> INSERT INTO tj10
         > VALUES ("[3,10,5,17,44]", 33), ("[3,10,5,17,[22,44,66]]", 0);
    Query OK, 1 row affected (0.04 sec)
    
    mysql> SELECT a->"$[4]" FROM tj10;
    +--------------+
    | a->"$[4]"    |
    +--------------+
    | 44           |
    | [22, 44, 66] |
    +--------------+
    2 rows in set (0.00 sec)
    
    mysql> SELECT * FROM tj10 WHERE a->"$[0]" = 3;
    +------------------------------+------+
    | a                            | b    |
    +------------------------------+------+
    | [3, 10, 5, 17, 44]           |   33 |
    | [3, 10, 5, 17, [22, 44, 66]] |    0 |
    +------------------------------+------+
    2 rows in set (0.00 sec)

    支援巢狀陣列。如果目標 JSON 文件中找不到相符的鍵,則使用 -> 的運算式會評估為 NULL,如下所示

    mysql> SELECT * FROM tj10 WHERE a->"$[4][1]" IS NOT NULL;
    +------------------------------+------+
    | a                            | b    |
    +------------------------------+------+
    | [3, 10, 5, 17, [22, 44, 66]] |    0 |
    +------------------------------+------+
    
    mysql> SELECT a->"$[4][1]" FROM tj10;
    +--------------+
    | a->"$[4][1]" |
    +--------------+
    | NULL         |
    | 44           |
    +--------------+
    2 rows in set (0.00 sec)

    這與使用 JSON_EXTRACT() 時在此類情況下看到的行為相同

    mysql> SELECT JSON_EXTRACT(a, "$[4][1]") FROM tj10;
    +----------------------------+
    | JSON_EXTRACT(a, "$[4][1]") |
    +----------------------------+
    | NULL                       |
    | 44                         |
    +----------------------------+
    2 rows in set (0.00 sec)
  • column->>path

    這是一個改良的、取消引號的擷取運算子。 -> 運算子僅擷取值,而 ->> 運算子還會取消擷取結果的引號。換句話說,給定 JSON 資料欄值 column 和路徑運算式 path (字串常值),以下三個運算式會傳回相同的值

    在允許使用 JSON_UNQUOTE(JSON_EXTRACT()) 的任何位置,都可以使用 ->> 運算子。這包括 (但不限於) SELECT 清單、WHEREHAVING 子句,以及 ORDER BYGROUP BY 子句。

    接下來的幾個陳述式示範了 mysql 用戶端中 ->> 運算子與其他運算式的一些等效性

    mysql> SELECT * FROM jemp WHERE g > 2;
    +-------------------------------+------+
    | c                             | g    |
    +-------------------------------+------+
    | {"id": "3", "name": "Barney"} |    3 |
    | {"id": "4", "name": "Betty"}  |    4 |
    +-------------------------------+------+
    2 rows in set (0.01 sec)
    
    mysql> SELECT c->'$.name' AS name
        ->     FROM jemp WHERE g > 2;
    +----------+
    | name     |
    +----------+
    | "Barney" |
    | "Betty"  |
    +----------+
    2 rows in set (0.00 sec)
    
    mysql> SELECT JSON_UNQUOTE(c->'$.name') AS name
        ->     FROM jemp WHERE g > 2;
    +--------+
    | name   |
    +--------+
    | Barney |
    | Betty  |
    +--------+
    2 rows in set (0.00 sec)
    
    mysql> SELECT c->>'$.name' AS name
        ->     FROM jemp WHERE g > 2;
    +--------+
    | name   |
    +--------+
    | Barney |
    | Betty  |
    +--------+
    2 rows in set (0.00 sec)

    如需用於建立和填入剛剛顯示的範例集中 jemp 資料表的 SQL 陳述式,請參閱 為 JSON 資料欄索引提供索引的產生資料欄

    此運算子也可以與 JSON 陣列搭配使用,如下所示

    mysql> CREATE TABLE tj10 (a JSON, b INT);
    Query OK, 0 rows affected (0.26 sec)
    
    mysql> INSERT INTO tj10 VALUES
        ->     ('[3,10,5,"x",44]', 33),
        ->     ('[3,10,5,17,[22,"y",66]]', 0);
    Query OK, 2 rows affected (0.04 sec)
    Records: 2  Duplicates: 0  Warnings: 0
    
    mysql> SELECT a->"$[3]", a->"$[4][1]" FROM tj10;
    +-----------+--------------+
    | a->"$[3]" | a->"$[4][1]" |
    +-----------+--------------+
    | "x"       | NULL         |
    | 17        | "y"          |
    +-----------+--------------+
    2 rows in set (0.00 sec)
    
    mysql> SELECT a->>"$[3]", a->>"$[4][1]" FROM tj10;
    +------------+---------------+
    | a->>"$[3]" | a->>"$[4][1]" |
    +------------+---------------+
    | x          | NULL          |
    | 17         | y             |
    +------------+---------------+
    2 rows in set (0.00 sec)

    -> 相同,->> 運算子始終會在 EXPLAIN 的輸出中展開,如下列範例所示

    mysql> EXPLAIN SELECT c->>'$.name' AS name
        ->     FROM jemp WHERE g > 2\G
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: jemp
       partitions: NULL
             type: range
    possible_keys: i
              key: i
          key_len: 5
              ref: NULL
             rows: 2
         filtered: 100.00
            Extra: Using where
    1 row in set, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Note
       Code: 1003
    Message: /* select#1 */ select
    json_unquote(json_extract(`jtest`.`jemp`.`c`,'$.name')) AS `name` from
    `jtest`.`jemp` where (`jtest`.`jemp`.`g` > 2)
    1 row in set (0.00 sec)

    這類似於 MySQL 在相同情況下展開 -> 運算子的方式。

  • JSON_KEYS(json_doc[, path])

    將 JSON 物件頂層值的鍵傳回為 JSON 陣列,或者,如果提供 path 引數,則傳回選定路徑的頂層鍵。如果任何引數為 NULLjson_doc 引數不是物件,或 path (如果提供) 找不到物件,則傳回 NULL。如果 json_doc 引數不是有效的 JSON 文件,或 path 引數不是有效的路徑運算式,或包含 *** 萬用字元,則會發生錯誤。

    如果選取的物件是空的,則結果陣列也是空的。如果頂層值具有巢狀子物件,則傳回值不包含這些子物件的鍵。

    mysql> SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}');
    +---------------------------------------+
    | JSON_KEYS('{"a": 1, "b": {"c": 30}}') |
    +---------------------------------------+
    | ["a", "b"]                            |
    +---------------------------------------+
    mysql> SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}', '$.b');
    +----------------------------------------------+
    | JSON_KEYS('{"a": 1, "b": {"c": 30}}', '$.b') |
    +----------------------------------------------+
    | ["c"]                                        |
    +----------------------------------------------+
  • JSON_OVERLAPS(json_doc1, json_doc2)

    比較兩個 JSON 文件。如果兩個文件有任何共同的鍵值配對或陣列元素,則傳回 true (1)。如果兩個引數都是純量,則函數會執行簡單的相等性測試。如果任一引數為 NULL,則函數會傳回 NULL

    此函數作為 JSON_CONTAINS() 的對應函數,它要求所搜尋的陣列的所有元素都必須存在於所搜尋的陣列中。因此,JSON_CONTAINS() 會對搜尋鍵執行 AND 運算,而 JSON_OVERLAPS() 則會執行 OR 運算。

    可以使用多值索引來最佳化在 WHERE 子句中使用 JSON_OVERLAPS()InnoDB 資料表的 JSON 資料欄執行的查詢。多值索引提供詳細資訊和範例。

    比較兩個陣列時,如果它們共同擁有一個或多個陣列元素,則 JSON_OVERLAPS() 會傳回 true,否則會傳回 false

    mysql> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,5,7]");
    +---------------------------------------+
    | JSON_OVERLAPS("[1,3,5,7]", "[2,5,7]") |
    +---------------------------------------+
    |                                     1 |
    +---------------------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,6,7]");
    +---------------------------------------+
    | JSON_OVERLAPS("[1,3,5,7]", "[2,6,7]") |
    +---------------------------------------+
    |                                     1 |
    +---------------------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,6,8]");
    +---------------------------------------+
    | JSON_OVERLAPS("[1,3,5,7]", "[2,6,8]") |
    +---------------------------------------+
    |                                     0 |
    +---------------------------------------+
    1 row in set (0.00 sec)

    部分比對會被視為不比對,如下所示

    mysql> SELECT JSON_OVERLAPS('[[1,2],[3,4],5]', '[1,[2,3],[4,5]]');
    +-----------------------------------------------------+
    | JSON_OVERLAPS('[[1,2],[3,4],5]', '[1,[2,3],[4,5]]') |
    +-----------------------------------------------------+
    |                                                   0 |
    +-----------------------------------------------------+
    1 row in set (0.00 sec)

    比較物件時,如果它們至少有一個共同的鍵值配對,則結果為 true。

    mysql> SELECT JSON_OVERLAPS('{"a":1,"b":10,"d":10}', '{"c":1,"e":10,"f":1,"d":10}');
    +-----------------------------------------------------------------------+
    | JSON_OVERLAPS('{"a":1,"b":10,"d":10}', '{"c":1,"e":10,"f":1,"d":10}') |
    +-----------------------------------------------------------------------+
    |                                                                     1 |
    +-----------------------------------------------------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT JSON_OVERLAPS('{"a":1,"b":10,"d":10}', '{"a":5,"e":10,"f":1,"d":20}');
    +-----------------------------------------------------------------------+
    | JSON_OVERLAPS('{"a":1,"b":10,"d":10}', '{"a":5,"e":10,"f":1,"d":20}') |
    +-----------------------------------------------------------------------+
    |                                                                     0 |
    +-----------------------------------------------------------------------+
    1 row in set (0.00 sec)

    如果將兩個純量用作函數的引數,則 JSON_OVERLAPS() 會執行簡單的相等性測試

    mysql> SELECT JSON_OVERLAPS('5', '5');
    +-------------------------+
    | JSON_OVERLAPS('5', '5') |
    +-------------------------+
    |                       1 |
    +-------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT JSON_OVERLAPS('5', '6');
    +-------------------------+
    | JSON_OVERLAPS('5', '6') |
    +-------------------------+
    |                       0 |
    +-------------------------+
    1 row in set (0.00 sec)

    當將純量與陣列比較時,JSON_OVERLAPS() 會嘗試將純量視為陣列元素。在此範例中,第二個引數 6 會解譯為 [6],如下所示

    mysql> SELECT JSON_OVERLAPS('[4,5,6,7]', '6');
    +---------------------------------+
    | JSON_OVERLAPS('[4,5,6,7]', '6') |
    +---------------------------------+
    |                               1 |
    +---------------------------------+
    1 row in set (0.00 sec)

    此函數不會執行類型轉換

    mysql> SELECT JSON_OVERLAPS('[4,5,"6",7]', '6');
    +-----------------------------------+
    | JSON_OVERLAPS('[4,5,"6",7]', '6') |
    +-----------------------------------+
    |                                 0 |
    +-----------------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT JSON_OVERLAPS('[4,5,6,7]', '"6"');
    +-----------------------------------+
    | JSON_OVERLAPS('[4,5,6,7]', '"6"') |
    +-----------------------------------+
    |                                 0 |
    +-----------------------------------+
    1 row in set (0.00 sec)
  • JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] ...])

    傳回 JSON 文件中指定字串的路徑。如果任何 json_docsearch_strpath 引數為 NULL;文件中不存在 path;或找不到 search_str,則傳回 NULL。如果 json_doc 引數不是有效的 JSON 文件,任何 path 引數不是有效的路徑運算式,one_or_all 不是 'one''all',或 escape_char 不是常數運算式,則會發生錯誤。

    one_or_all 引數會依如下方式影響搜尋

    • 'one': 搜尋會在第一個比對之後終止,並傳回一個路徑字串。未定義哪個比對被視為第一個。

    • 'all': 搜尋會傳回所有相符的路徑字串,這樣就不會包含重複的路徑。如果有多個字串,則會將它們自動包裝為陣列。陣列元素的順序未定義。

    search_str 搜尋字串引數中,%_ 字元的運作方式與 LIKE 運算子相同:% 會比對任何數量的字元 (包括零個字元),而 _ 則會比對一個字元。

    若要在搜尋字串中指定常值 %_ 字元,請在其前面加上逸出字元。如果缺少 escape_char 引數或為 NULL,則預設值為 \。否則,escape_char 必須是空值或一個字元的常數。

    如需比對和逸出字元行為的詳細資訊,請參閱 第 14.8.1 節「字串比較函數和運算子」LIKE 的描述。對於逸出字元處理,與 LIKE 行為的不同之處在於 JSON_SEARCH() 的逸出字元必須在編譯時評估為常數,而不僅僅是在執行時評估。例如,如果在預先準備好的陳述式中使用 JSON_SEARCH(),並且使用 ? 參數提供 escape_char 引數,則參數值在執行時可能是常數,但在編譯時則不是。

    mysql> SET @j = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
    
    mysql> SELECT JSON_SEARCH(@j, 'one', 'abc');
    +-------------------------------+
    | JSON_SEARCH(@j, 'one', 'abc') |
    +-------------------------------+
    | "$[0]"                        |
    +-------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', 'abc');
    +-------------------------------+
    | JSON_SEARCH(@j, 'all', 'abc') |
    +-------------------------------+
    | ["$[0]", "$[2].x"]            |
    +-------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', 'ghi');
    +-------------------------------+
    | JSON_SEARCH(@j, 'all', 'ghi') |
    +-------------------------------+
    | NULL                          |
    +-------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '10');
    +------------------------------+
    | JSON_SEARCH(@j, 'all', '10') |
    +------------------------------+
    | "$[1][0].k"                  |
    +------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$');
    +-----------------------------------------+
    | JSON_SEARCH(@j, 'all', '10', NULL, '$') |
    +-----------------------------------------+
    | "$[1][0].k"                             |
    +-----------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[*]');
    +--------------------------------------------+
    | JSON_SEARCH(@j, 'all', '10', NULL, '$[*]') |
    +--------------------------------------------+
    | "$[1][0].k"                                |
    +--------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$**.k');
    +---------------------------------------------+
    | JSON_SEARCH(@j, 'all', '10', NULL, '$**.k') |
    +---------------------------------------------+
    | "$[1][0].k"                                 |
    +---------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[*][0].k');
    +-------------------------------------------------+
    | JSON_SEARCH(@j, 'all', '10', NULL, '$[*][0].k') |
    +-------------------------------------------------+
    | "$[1][0].k"                                     |
    +-------------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[1]');
    +--------------------------------------------+
    | JSON_SEARCH(@j, 'all', '10', NULL, '$[1]') |
    +--------------------------------------------+
    | "$[1][0].k"                                |
    +--------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[1][0]');
    +-----------------------------------------------+
    | JSON_SEARCH(@j, 'all', '10', NULL, '$[1][0]') |
    +-----------------------------------------------+
    | "$[1][0].k"                                   |
    +-----------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', 'abc', NULL, '$[2]');
    +---------------------------------------------+
    | JSON_SEARCH(@j, 'all', 'abc', NULL, '$[2]') |
    +---------------------------------------------+
    | "$[2].x"                                    |
    +---------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '%a%');
    +-------------------------------+
    | JSON_SEARCH(@j, 'all', '%a%') |
    +-------------------------------+
    | ["$[0]", "$[2].x"]            |
    +-------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '%b%');
    +-------------------------------+
    | JSON_SEARCH(@j, 'all', '%b%') |
    +-------------------------------+
    | ["$[0]", "$[2].x", "$[3].y"]  |
    +-------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '$[0]');
    +---------------------------------------------+
    | JSON_SEARCH(@j, 'all', '%b%', NULL, '$[0]') |
    +---------------------------------------------+
    | "$[0]"                                      |
    +---------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '$[2]');
    +---------------------------------------------+
    | JSON_SEARCH(@j, 'all', '%b%', NULL, '$[2]') |
    +---------------------------------------------+
    | "$[2].x"                                    |
    +---------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '$[1]');
    +---------------------------------------------+
    | JSON_SEARCH(@j, 'all', '%b%', NULL, '$[1]') |
    +---------------------------------------------+
    | NULL                                        |
    +---------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', '', '$[1]');
    +-------------------------------------------+
    | JSON_SEARCH(@j, 'all', '%b%', '', '$[1]') |
    +-------------------------------------------+
    | NULL                                      |
    +-------------------------------------------+
    
    mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', '', '$[3]');
    +-------------------------------------------+
    | JSON_SEARCH(@j, 'all', '%b%', '', '$[3]') |
    +-------------------------------------------+
    | "$[3].y"                                  |
    +-------------------------------------------+

    如需 MySQL 支援的 JSON 路徑語法的詳細資訊 (包括管理萬用字元 *** 的規則),請參閱 JSON 路徑語法

  • JSON_VALUE(json_doc, path)

    從指定文件中給定路徑的 JSON 文件中擷取值,並傳回擷取的值,選擇性地將其轉換為所需的類型。完整語法如下所示

    JSON_VALUE(json_doc, path [RETURNING type] [on_empty] [on_error])
    
    on_empty:
        {NULL | ERROR | DEFAULT value} ON EMPTY
    
    on_error:
        {NULL | ERROR | DEFAULT value} ON ERROR

    json_doc 是有效的 JSON 文件。如果此為 NULL,則函數會傳回 NULL

    path 是指向文件中位置的 JSON 路徑。這必須是字串常值。

    type 是下列其中一個資料類型

    剛列出的類型與 CAST() 函數支援的 (非陣列) 類型相同。

    如果沒有使用 RETURNING 子句指定,JSON_VALUE() 函數的回傳類型為 VARCHAR(512)。當回傳類型沒有指定字元集時,JSON_VALUE() 使用 utf8mb4 和二進位排序規則,這會區分大小寫;如果為結果指定 utf8mb4 作為字元集,伺服器會使用此字元集的預設排序規則,該規則不區分大小寫。

    當指定路徑上的資料包含或解析為 JSON null 文字時,函數會傳回 SQL NULL

    如果指定 on_empty,則決定當在給定的路徑上找不到資料時,JSON_VALUE() 的行為;此子句採用下列其中一個值

    • NULL ON EMPTY:函數傳回 NULL;這是預設的 ON EMPTY 行為。

    • DEFAULT value ON EMPTY:傳回提供的 value。值的類型必須與回傳類型相符。

    • ERROR ON EMPTY:函數會拋出錯誤。

    如果使用 on_error,則會採用下列其中一個值,並在發生錯誤時產生相應的結果,如下所示

    • NULL ON ERRORJSON_VALUE() 會傳回 NULL;如果沒有使用 ON ERROR 子句,這是預設行為。

    • DEFAULT value ON ERROR:這是傳回的值;其值必須與回傳類型相符。

    • ERROR ON ERROR:會拋出錯誤。

    如果使用 ON EMPTY,則必須在任何 ON ERROR 子句之前。以錯誤的順序指定它們會導致語法錯誤。

    錯誤處理。一般而言,JSON_VALUE() 處理錯誤的方式如下

    • 所有 JSON 輸入(文件和路徑)都會檢查其有效性。如果其中任何一個無效,則會拋出 SQL 錯誤,而不會觸發 ON ERROR 子句。

    • 當發生下列任何事件時,就會觸發 ON ERROR

      • 嘗試擷取物件或陣列,例如從解析為 JSON 文件中多個位置的路徑所產生的物件或陣列

      • 轉換錯誤,例如嘗試將 'asdf' 轉換為 UNSIGNED

      • 值的截斷

    • 即使指定了 NULL ON ERRORDEFAULT ... ON ERROR,轉換錯誤始終會觸發警告。

    • 當來源 JSON 文件(expr)在指定的位置(path)沒有資料時,會觸發 ON EMPTY 子句。

    範例。此處顯示兩個簡單的範例

    mysql> SELECT JSON_VALUE('{"fname": "Joe", "lname": "Palmer"}', '$.fname');
    +--------------------------------------------------------------+
    | JSON_VALUE('{"fname": "Joe", "lname": "Palmer"}', '$.fname') |
    +--------------------------------------------------------------+
    | Joe                                                          |
    +--------------------------------------------------------------+
    
    mysql> SELECT JSON_VALUE('{"item": "shoes", "price": "49.95"}', '$.price'
        -> RETURNING DECIMAL(4,2)) AS price;
    +-------+
    | price |
    +-------+
    | 49.95 |
    +-------+

    語句 SELECT JSON_VALUE(json_doc, path RETURNING type) 等同於下列語句

    SELECT CAST(
        JSON_UNQUOTE( JSON_EXTRACT(json_doc, path) )
        AS type
    );

    JSON_VALUE() 簡化了在 JSON 資料行上建立索引的方式,在許多情況下,不再需要在產生的資料行上建立索引。當建立具有 JSON 資料行的資料表 t1 時,可以透過在操作該資料行的 JSON_VALUE() 的表示式上建立索引來實現(路徑與該資料行的值相符),如下所示

    CREATE TABLE t1(
        j JSON,
        INDEX i1 ( (JSON_VALUE(j, '$.id' RETURNING UNSIGNED)) )
    );

    下列 EXPLAIN 輸出顯示,對 t1 的查詢使用 WHERE 子句中的索引表示式,因此使用了建立的索引

    mysql> EXPLAIN SELECT * FROM t1
        ->     WHERE JSON_VALUE(j, '$.id' RETURNING UNSIGNED) = 123\G
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: t1
       partitions: NULL
             type: ref
    possible_keys: i1
              key: i1
          key_len: 9
              ref: const
             rows: 1
         filtered: 100.00
            Extra: NULL

    這與建立在產生的資料行上具有索引的資料表 t2 達到幾乎相同的效果(請參閱索引產生的資料行以提供 JSON 資料行索引),如下所示

    CREATE TABLE t2 (
        j JSON,
        g INT GENERATED ALWAYS AS (j->"$.id"),
        INDEX i1 (g)
    );

    對此資料表執行查詢並參考產生的資料行的 EXPLAIN 輸出顯示,索引的使用方式與先前對資料表 t1 進行查詢的方式相同

    mysql> EXPLAIN SELECT * FROM t2 WHERE g  = 123\G
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: t2
       partitions: NULL
             type: ref
    possible_keys: i1
              key: i1
          key_len: 5
              ref: const
             rows: 1
         filtered: 100.00
            Extra: NULL

    有關使用產生的資料行上的索引對 JSON 資料行進行間接索引的相關資訊,請參閱索引產生的資料行以提供 JSON 資料行索引

  • value MEMBER OF(json_array)

    如果 valuejson_array 的元素,則傳回 true (1),否則傳回 false (0)。value 必須是純量或 JSON 文件;如果它是純量,運算子會嘗試將其視為 JSON 陣列的元素。如果 valuejson_arrayNULL,則函數會傳回 NULL

    InnoDB 資料表的 JSON 資料行上使用 MEMBER OF() 的查詢可以在 WHERE 子句中使用多值索引進行最佳化。如需詳細資訊和範例,請參閱多值索引

    簡單的純量會被視為陣列值,如下所示

    mysql> SELECT 17 MEMBER OF('[23, "abc", 17, "ab", 10]');
    +-------------------------------------------+
    | 17 MEMBER OF('[23, "abc", 17, "ab", 10]') |
    +-------------------------------------------+
    |                                         1 |
    +-------------------------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT 'ab' MEMBER OF('[23, "abc", 17, "ab", 10]');
    +---------------------------------------------+
    | 'ab' MEMBER OF('[23, "abc", 17, "ab", 10]') |
    +---------------------------------------------+
    |                                           1 |
    +---------------------------------------------+
    1 row in set (0.00 sec)

    陣列元素值的局部比對不會相符

    mysql> SELECT 7 MEMBER OF('[23, "abc", 17, "ab", 10]');
    +------------------------------------------+
    | 7 MEMBER OF('[23, "abc", 17, "ab", 10]') |
    +------------------------------------------+
    |                                        0 |
    +------------------------------------------+
    1 row in set (0.00 sec)
    mysql> SELECT 'a' MEMBER OF('[23, "abc", 17, "ab", 10]');
    +--------------------------------------------+
    | 'a' MEMBER OF('[23, "abc", 17, "ab", 10]') |
    +--------------------------------------------+
    |                                          0 |
    +--------------------------------------------+
    1 row in set (0.00 sec)

    不會執行字串類型之間的轉換

    mysql> SELECT
        -> 17 MEMBER OF('[23, "abc", "17", "ab", 10]'),
        -> "17" MEMBER OF('[23, "abc", 17, "ab", 10]')\G
    *************************** 1. row ***************************
    17 MEMBER OF('[23, "abc", "17", "ab", 10]'): 0
    "17" MEMBER OF('[23, "abc", 17, "ab", 10]'): 0
    1 row in set (0.00 sec)

    若要將此運算子與本身是陣列的值搭配使用,必須將其明確轉換為 JSON 陣列。您可以使用 CAST(... AS JSON) 來執行此操作

    mysql> SELECT CAST('[4,5]' AS JSON) MEMBER OF('[[3,4],[4,5]]');
    +--------------------------------------------------+
    | CAST('[4,5]' AS JSON) MEMBER OF('[[3,4],[4,5]]') |
    +--------------------------------------------------+
    |                                                1 |
    +--------------------------------------------------+
    1 row in set (0.00 sec)

    也可以使用 JSON_ARRAY() 函數來執行必要的轉換,如下所示

    mysql> SELECT JSON_ARRAY(4,5) MEMBER OF('[[3,4],[4,5]]');
    +--------------------------------------------+
    | JSON_ARRAY(4,5) MEMBER OF('[[3,4],[4,5]]') |
    +--------------------------------------------+
    |                                          1 |
    +--------------------------------------------+
    1 row in set (0.00 sec)

    任何用作要測試的值或出現在目標陣列中的 JSON 物件都必須使用 CAST(... AS JSON)JSON_OBJECT() 強制轉換為正確的類型。此外,包含 JSON 物件的目標陣列本身也必須使用 JSON_ARRAY 轉換。以下一系列語句說明了這一點

    mysql> SET @a = CAST('{"a":1}' AS JSON);
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SET @b = JSON_OBJECT("b", 2);
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SET @c = JSON_ARRAY(17, @b, "abc", @a, 23);
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @a MEMBER OF(@c), @b MEMBER OF(@c);
    +------------------+------------------+
    | @a MEMBER OF(@c) | @b MEMBER OF(@c) |
    +------------------+------------------+
    |                1 |                1 |
    +------------------+------------------+
    1 row in set (0.00 sec)