11.5 Тип данных JSON
Начиная с MySQL 5.7.8, MySQL поддерживает встроенный тип данных JSON (JavaScript Object Notation), определенный в RFC 8259, что обеспечивает эффективный доступ к данным в документах JSON. Тип данных JSON предоставляет следующие преимущества по сравнению с хранением строк в формате JSON в столбце типа string:
Автоматическая проверка документов JSON, хранящихся в столбцах типа
JSON. Невалидные документы вызывают ошибку.Оптимизированный формат хранения. Документы JSON, хранящиеся в столбцах типа
JSON, преобразуются во внутренний формат, позволяющий быстро получить доступ к элементам документа. Когда серверу позже нужно считать значение JSON, сохраненное в этом двоичном формате, ему не нужно его парсить из текстового представления. Двоичный формат структурирован таким образом, чтобы сервер мог напрямую искать подобъекты или вложенные значения по ключу или индексу массива, не читая все значения до или после них в документе.
В этом обсуждении используется JSON в моноширинном шрифте, чтобы указать конкретно тип данных JSON, и «JSON» в обычном шрифте, чтобы обозначить данные JSON в общем.
Место, занимаемое документом JSON, примерно равно объёму для LONGBLOB или LONGTEXT; см. Раздел 11.7, «Требования к хранению типов данных» для получения дополнительной информации. Важно помнить, что размер любого документа JSON, хранящегося в столбце типа JSON, ограничен значением системной переменной max_allowed_packet. (Когда сервер обрабатывает значение JSON внутри памяти, оно может быть больше этого; ограничение относится к хранению на сервере.)
Столбец типа JSON не может иметь значение по умолчанию, отличное от NULL.
Вместе с типом данных JSON доступен набор функций SQL, позволяющий выполнять операции над значениями JSON, такие как создание, манипулирование и поиск. Ниже приведены примеры этих операций. Подробную информацию об отдельных функциях см. в Разделе 12.17, «Функции JSON».
Также доступен набор пространственных функций для работы со значениями GeoJSON. См. Раздел 12.16.11, «Пространственные функции GeoJSON».
Столбцы типа JSON, как и столбцы других бинарных типов, не индексируются напрямую; вместо этого вы можете создать индекс на вычисляемом столбце, который извлекает скалярное значение из столбца типа JSON. См. Индексирование вычисляемого столбца для создания индекса столбца JSON для подробного примера.
Оптимизатор MySQL также ищет совместимые индексы на виртуальных столбцах, которые соответствуют выражениям JSON.
MySQL NDB Cluster 7.5 (7.5.2 и новее) поддерживает столбцы типа JSON и функции MySQL JSON, включая создание индекса на столбце, сгенерированном из столбца типа JSON, как обходной путь для невозможности индексирования столбца типа JSON. Максимально поддерживается 3 столбца типа JSON на таблицу NDB.
В следующих разделах приводится основная информация о создании и обработке значений JSON.
END_OF_DOCUMENT_MARKERСоздание значений JSON
Массив JSON содержит список значений, разделенных запятыми и заключенных в символы [ и ]:
["abc", 10, null, true, false]
Объект JSON содержит набор пар ключ-значение, разделенных запятыми и заключенных в символы { и }:
{"k1": "value", "k2": 10}
Как показывают примеры, массивы и объекты JSON могут содержать скалярные значения, которые являются строками или числами, литерал JSON null или логические литералы 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]}
Вы также можете получить значения JSON с помощью ряда функций MySQL для этой цели (см. Раздел 12.17.2, «Функции для создания значений JSON»), а также путем приведения значений других типов к типу JSON с помощью CAST( (см. Преобразование между значениями JSON и не-JSON). Следующие несколько абзацев описывают, как MySQL обрабатывает значения JSON, предоставленные в качестве входных данных. 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” в таких сообщениях об ошибках нумеруются с нуля, но следует рассматривать их как приблизительные указания на то, где на самом деле возникает проблема в значении. -
Функция
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 обрабатывает строки, используемые в контексте JSON, с помощью набора символов utf8mb4 и сортировки utf8mb4_bin. Строки в других наборах символов преобразуются в 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. Вместо этого результат функции 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 в качестве ключа, вы можете использовать оператор пути столбца ->, как показано здесь:
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". |
+-----------------------------------------+
Предыдущий пример не работает так, как показано, если серверный режим SQL NO_BACKSLASH_ESCAPES включен. Если этот режим установлен, одну обратную косую черту вместо двойных обратных косых черт можно использовать для вставки литерала объекта JSON, и обратные косые черты сохраняются. Если вы используете функцию JSON_OBJECT() при выполнении вставки, и этот режим установлен, вы должны чередовать одинарные и двойные кавычки, как показано здесь:
mysql> INSERT INTO facts VALUES
> (JSON_OBJECT('mascot', 'Our mascot is a dolphin named "Sakila".'));
Более подробную информацию об эффектах этого режима на экранированные символы в значениях JSON см. в описании функции JSON_UNQUOTE().
Нормализация, объединение и автоматическое обертывание значений 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. (Ошибка #86866, Ошибка #26369555)
MySQL также отбрасывает лишние пробелы между ключами, значениями или элементами в исходном документе JSON и оставляет (или вставляет, когда это необходимо) один пробел после каждой запятой (,) или двоеточия (:) при отображении. Это делается для повышения читаемости.
Функции MySQL, создающие значения JSON (см. Раздел 12.17.2, «Функции, создающие значения JSON»), всегда возвращают нормализованные значения.
Для повышения эффективности поиска также сортируются ключи объекта 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 значение элемента с ключом name:
mysql> SELECT JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name');
+---------------------------------------------------------+
| JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name') |
+---------------------------------------------------------+
| "Aztalan" |
+---------------------------------------------------------+
Синтаксис пути использует ведущий символ $ для представления рассматриваемого документа JSON, за которым необязательно следуют селекторы, указывающие последовательно более специфичные части документа:
Точка, за которой следует имя ключа, называет элемент в объекте с заданным ключом. Имя ключа должно быть указано в двойных кавычках, если имя без кавычек не является допустимым в выражениях пути (например, если оно содержит пробел).
-
[, добавленное кN]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 как синоним для column->pathJSON_EXTRACT(. Дополнительную информацию см. в разделе Раздел 12.17.3, «Функции поиска значений JSON». См. также Индексирование генерируемого столбца для создания индекса столбца JSON.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), которое заменяется значением, следующим за аргументом пути (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, поддерживаемые MySQL и описанные в другом месте этого руководства (см. Раздел 12.17, «Функции JSON»), требуют выражения пути для идентификации конкретного элемента в документе JSON. Путь состоит из области действия пути, за которой следуют один или несколько отрезков пути. Для путей, используемых в функциях JSON MySQL, область действия всегда является документом, в котором выполняется поиск или выполняется операция, представленная ведущим символом $. Отрезки пути разделяются точками (.). Ячейки массивов представлены как [, где N]N — неотрицательное целое число. Имена ключей должны быть строками в двойных кавычках или допустимыми идентификаторами ECMAScript (см. http://www.ecma-international.org/ecma-262/5.1/#sec-7.6). Выражения путей, как и тексты JSON, должны быть закодированы с использованием набора символов ascii, utf8 или utf8mb4. Другие кодировки символов неявно преобразуются в utf8mb4. Полный синтаксис показан здесь:
pathExpression:
scope[(pathLeg)*]
pathLeg:
member | arrayLocation | doubleAsterisk
member:
period ( keyName | asterisk )
arrayLocation:
leftBracket ( nonNegativeInteger | asterisk ) rightBracket
keyName:
ESIdentifier | doubleQuotedString
doubleAsterisk:
'**'
period:
'.'
asterisk:
'*'
leftBracket:
'['
rightBracket:
']'
Как отмечалось ранее, в MySQL область действия пути всегда является документом, над которым выполняется операция, представленная как $. Вы можете использовать '$' как синоним документа в выражениях путей JSON.
Некоторые реализации поддерживают ссылки на столбцы в качестве областей действия путей JSON; в настоящее время MySQL не поддерживает это.
Дикий символ * и токен ** используются следующим образом:
.*представляет значения всех членов объекта.[*]представляет значения всех ячеек массива.-
[представляет все пути, начинающиеся сprefix]**suffixprefixи заканчивающиесяsuffix.prefixнеобязательно, аsuffixобязательно; другими словами, путь не может заканчиваться на**.Кроме того, путь не может содержать последовательность
***.
Примеры синтаксиса путей см. в описаниях различных функций JSON, которые принимают пути в качестве аргументов, таких как JSON_CONTAINS_PATH(), JSON_SET() и JSON_REPLACE(). Примеры, включающие использование диких символов * и **, см. в описании функции JSON_SEARCH().
Сравнение и упорядочивание значений JSON
Значения JSON могут быть сравнены с помощью операторов =, <, <=, >, >=, <>, != и <=>.
Следующие операторы сравнения и функции пока не поддерживаются со значениями JSON:
Обходным путём для операторов сравнения и функций, перечисленных выше, является приведение значений 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.
-
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, «Числовые литералы».
Правила сравнения собственных числовых типов MySQL обсуждаются в Разделе 12.3, «Преобразование типов в оценке выражений», но правила сравнения чисел внутри значений JSON несколько отличаются:
При сравнении двух столбцов, использующих собственные числовые типы MySQL
INTиDOUBLEсоответственно, известно, что все сравнения включают целое число и double, поэтому целое число преобразуется в double для всех строк. То есть, числа с точным значением преобразуются в числа с приближенным значением.-
С другой стороны, если запрос сравнивает два JSON столбца, содержащие числа, заранее неизвестно, являются ли числа целыми или double. Чтобы обеспечить наиболее согласованное поведение во всех строках, MySQL преобразует числа с приближенным значением в числа с точным значением. Полученный порядок согласован и не теряет точности для чисел с точным значением. Например, для скаляров 9223372036854775805, 9223372036854775806, 9223372036854775807 и 9.223372036854776e18 порядок такой:
9223372036854775805 < 9223372036854775806 < 9223372036854775807 < 9.223372036854776e18 = 9223372036854776000 < 9223372036854776001
Если бы сравнения JSON использовали правила сравнения чисел без JSON, могло бы произойти несогласованное упорядочение. Обычные правила сравнения чисел MySQL дают следующие упорядочения:
-
Сравнение целых чисел:
9223372036854775805 < 9223372036854775806 < 9223372036854775807
(не определено для 9.223372036854776e18)
-
Сравнение double:
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 | Результат — значение типа JSON. | Не применимо. |
| Типы геометрий | Значение геометрии преобразуется в JSON документ с помощью вызова ST_AsGeoJSON(). | Незаконная операция. Решение: передайте результат от CAST( в ST_GeomFromGeoJSON(). |
| Все остальные типы | Результат — JSON документ, содержащий одно скалярное значение. | Успешно, если JSON документ состоит из одного скалярного значения целевого типа, и это скалярное значение может быть преобразовано в целевой тип. В противном случае возвращается NULL и генерируется предупреждение. |
Сортировка ORDER BY и GROUP BY для JSON значений работает по этим принципам:
Порядок скалярных JSON значений использует те же правила, что и в предыдущем обсуждении.
При сортировке по возрастанию SQL
NULLсортирует раньше всех JSON значений, включая JSON null литерал; при сортировке по убыванию SQLNULLсортирует позже всех JSON значений, включая JSON null литерал.Ключи сортировки для 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 значений может не дать осмысленного результата.
© 2025 Oracle
Licensed under the GPLv2 License.