JSON QUERY: примеры (SQL)

Использование JSON_QUERY для извлечения объектов JSON в SQL Server
Раздел: JSON функции, JSON
JSON_QUERY(json_expression, path): nvarchar

Функция JSON_QUERY

Функция JSON_QUERY в Microsoft SQL Server предназначена для извлечения объекта или массива из строки JSON. В отличие от функции JSON_VALUE, которая возвращает скалярное значение, JSON_QUERY возвращает фрагмент JSON, который сам по себе является валидным JSON. Это позволяет работать с вложенными структурами.

Функция используется в сценариях, когда требуется сохранить структуру извлекаемых данных: объекты с несколькими свойствами, массивы значений или сложные вложенные конструкции. Типичные применения включают извлечение подмассивов, вложенных объектов для последующего анализа или передачи в другие функции, работающие с JSON.

Синтаксис: JSON_QUERY ( expression [ , path ] )

Аргументы:

  • expression – Выражение, содержащее строку JSON. Может быть столбцом, переменной или литералом. Если строка не является валидным JSON, функция возвращает ошибку.
  • path – Необязательный аргумент. Путь JSON к извлекаемому объекту или массиву. Синтаксис пути следует стандарту JSON Path, поддерживая ключи и индексы массива (например, '$.store.book[0]'). Если путь не указан, функция возвращает весь входной JSON.

Возвращаемое значение: Возвращает фрагмент JSON типа nvarchar(max). Если значение по указанному пути является скаляром (строка, число, boolean, null), функция возвращает NULL. Если путь не найден в исходном JSON, также возвращается NULL. В случае невалидного входного JSON генерируется ошибка.

Примеры использования

Базовые примеры демонстрируют различные сценарии вызова функции.

Извлечение объекта:

DECLARE @json NVARCHAR(MAX) = N'{"info": {"address": {"city": "Moscow", "street": "Tverskaya"}}}';
SELECT JSON_QUERY(@json, '$.info.address') AS AddressObject;
AddressObject
---------------------------------
{"city": "Moscow", "street": "Tverskaya"}

Извлечение массива:

DECLARE @json NVARCHAR(MAX) = N'{"orders": [100, 200, 300]}';
SELECT JSON_QUERY(@json, '$.orders') AS OrdersArray;
OrdersArray
-------------------
[100, 200, 300]

Использование без указания пути (возврат всего JSON):

DECLARE @json NVARCHAR(MAX) = N'{"id": 1, "active": true}';
SELECT JSON_QUERY(@json) AS FullJson;
FullJson
------------------------
{"id": 1, "active": true}

Попытка извлечь скалярное значение (возвращает NULL):

DECLARE @json NVARCHAR(MAX) = N'{"name": "Ivan"}';
SELECT JSON_QUERY(@json, '$.name') AS ScalarResult;
ScalarResult
-------------
NULL

Похожие функции в MS SQL

В T-SQL существуют другие функции для работы с JSON, каждая решает свою задачу.

  • JSON_VALUE – Извлекает скалярное значение из строки JSON (строку, число, boolean). Возвращает nvarchar(4000). Используется, когда необходим именно единичный, простой элемент, а не объект или массив.
  • JSON_MODIFY – Обновляет значение свойства, добавляет новое свойство или удаляет существующее в строке JSON. Работает с любыми типами значений, включая объекты и массивы, передаваемые как строки JSON.
  • OPENJSON – Табличная функция, преобразующая массив или объект JSON в набор строк. Позволяет выполнять реляционные операции (JOIN, WHERE) над данными JSON. Предпочтительна для парсинга и массового преобразования JSON в табличный формат.

JSON_QUERY применяют, когда требуется сохранить составную структуру данных (объект/массив) для дальнейшей обработки как JSON, например, для передачи в другой вызов JSON_MODIFY или клиентскому приложению.

Типичные ошибки

Ошибки обычно связаны с непониманием типа данных по указанному пути.

Ожидание объекта при скалярном значении:

DECLARE @json NVARCHAR(MAX) = N'{"count": 42}';
SELECT JSON_QUERY(@json, '$.count') AS Result; -- NULL, так как 42 - скаляр
Result
------
NULL

Невалидный JSON на входе:

SELECT JSON_QUERY('{invalid json}', '$');
Ошибка: Ожидался объект JSON или массив.

Некорректный синтаксис пути:

DECLARE @json NVARCHAR(MAX) = N'{"data": {}}';
SELECT JSON_QUERY(@json, '$invalid.path') AS Result;
Ошибка: Недопустимый escape-символ в пути JSON.

Игнорирование NULL результата при последующей обработке:

DECLARE @json NVARCHAR(MAX) = N'{"name": "Anna"}';
SELECT JSON_MODIFY(@json, '$.new', JSON_QUERY(@json, '$.name')) AS Result;
-- Поле 'new' будет удалено, так как JSON_QUERY вернул NULL
Result
------------------------
{"name": "Anna"}

Изменения в последних версиях

В SQL Server 2016 (13.x) функция была введена. Существенных изменений в синтаксисе или поведении в более поздних версиях SQL Server (2017, 2019, 2022) не было. Однако, с обновлениями ядра СУБД могут улучшаться производительность и обработка ошибок. В SQL Server 2022 продолжается развитие JSON-функциональности, например, улучшена поддержка типов данных TIME и DATETIME в функциях JSON. Для функции JSON QUERY специфичных нововведений не зафиксировано.

Расширенные примеры

Рекурсивное извлечение вложенных структур для последующего парсинга.

Пример sql
DECLARE @catalog NVARCHAR(MAX) = N'
{
  "store": {
    "books": [
      {"title": "Book A", "tags": ["fiction", "novel"]},
      {"title": "Book B", "tags": ["science"]}
    ]
  }
}';
SELECT 
  JSON_QUERY(book.value, '$.tags') AS BookTags
FROM OPENJSON(@catalog, '$.store.books') AS book;
BookTags
-------------------
["fiction", "novel"]
["science"]

Использование JSON_QUERY для безопасной вставки объекта в JSON_MODIFY.

Пример sql
DECLARE @old_json NVARCHAR(MAX) = N'{"id": 1}';
DECLARE @new_object NVARCHAR(MAX) = N'{"code": "X1", "active": false}';

SELECT JSON_MODIFY(@old_json, '$.data', JSON_QUERY(@new_object)) AS ModifiedJson;
ModifiedJson
---------------------------------------------------
{"id": 1, "data": {"code": "X1", "active": false}}

Извлечение и агрегация данных из массива объектов с использованием OPENJSON.

Пример sql
DECLARE @data NVARCHAR(MAX) = N'
{
  "results": [
    {"score": 85, "subject": "Math"},
    {"score": 90, "subject": "Physics"}
  ]
}';

SELECT 
  AVG(CAST(JSON_VALUE(value, '$.score') AS INT)) as AvgScore
FROM OPENJSON(JSON_QUERY(@data, '$.results'));
AvgScore
---------
87

Динамическое построение пути для извлечения данных.

Пример sql
DECLARE @config NVARCHAR(MAX) = N'{"ui": {"theme": "dark", "settings": {"lang": "ru"}}}';
DECLARE @path NVARCHAR(200) = '$.ui.settings';

SELECT JSON_QUERY(@config, @path) as DynamicPathResult;
DynamicPathResult
-------------------
{"lang": "ru"}

Обработка отсутствующего пути с ISNULL.

Пример sql
DECLARE @profile NVARCHAR(MAX) = N'{"name": "Alex"}';
SELECT 
  ISNULL(JSON_QUERY(@profile, '$.address'), '{}') AS Address
INTO #temp;
SELECT * FROM #temp;
Address
-------
{}

Аналоги в других СУБД

MySQL: Функция JSON_EXTRACT() возвращает элемент JSON, который может быть как скаляром, так и объектом/массивом. Для получения именно строкового представления часто комбинируют с JSON_UNQUOTE().

SELECT JSON_EXTRACT('{"a": [1,2]}', '$.a');
[1, 2]

PostgreSQL: Оператор -> возвращает тип json, а ->> – текст. Для извлечения объекта по пути используют комбинацию операторов.

SELECT ('{"x": {"y": 10}}'::json) -> 'x';
{"y": 10}

Oracle: Метод JSON_QUERY() в SQL стандартен и похож на MS SQL. Возвращает строку с фрагментом JSON.

SELECT JSON_QUERY('{"a": {"b": 5}}', '$.a') FROM dual;
{"b": 5}

SQLite: Функция json_extract() ведет себя аналогично MySQL, возвращая элемент JSON.

SELECT json_extract('{"id": [7]}', '$.id');
[7]

Основное отличие MS SQL – явное разделение на JSON_VALUE для скаляров и JSON_QUERY для объектов/массивов, тогда как в других СУБД одна функция часто возвращает значение любого типа JSON.

MS SQL JSON_QUERY function comments

En
JSON QUERY Extracts an object or an array from a JSON string