Проверка, запрос и изменение данных JSON со встроенными функциями (SQL Server)
Область применения: SQL Server 2016 (13.x) и более поздних версий База данных SQL Azure Управляемый экземпляр SQL Azure
Встроенная поддержка JSON включает следующие встроенные функции, описанные в этой статье.
- ISJSON проверяет наличие допустимых данных JSON в строке.
- JSON_VALUE извлекает скалярное значение из строки JSON.
- JSON_QUERY извлекает объект или массив из строки JSON.
- JSON_MODIFY обновляет значение свойства в строке JSON и возвращает обновленную строку JSON.
Для всех функций JSON просмотрите функции JSON.
Примеры кода Transact-SQL в этой статье используют AdventureWorks2022
базу данных или AdventureWorksDW2022
пример базы данных, которую можно скачать с домашней страницы примеров и проектов сообщества Microsoft SQL Server.
Текст JSON для примеров на этой странице
В примерах на этой странице используется текст JSON, аналогичный содержимому в следующем примере:
{
"id": "DesaiFamily",
"parents": [
{ "familyName": "Desai", "givenName": "Prashanth" },
{ "familyName": "Miller", "givenName": "Helen" }
],
"children": [
{
"familyName": "Desai",
"givenName": "Jesse",
"gender": "female",
"grade": 1,
"pets": [
{ "givenName": "Goofy" },
{ "givenName": "Shadow" }
]
},
{
"familyName": "Desai",
"givenName": "Lisa",
"gender": "female",
"grade": 8
}
],
"address": {
"state": "NY",
"county": "Manhattan",
"city": "NY"
},
"creationDate": 1431620462,
"isRegistered": false
}
Этот документ JSON, содержащий вложенные сложные элементы, хранится в следующем образце таблицы:
CREATE TABLE Families (
id INT identity CONSTRAINT PK_JSON_ID PRIMARY KEY,
[doc] NVARCHAR(MAX)
);
Функции JSON работают одинаково, хранится ли документ JSON в varchar, nvarchar или в собственном типе данных JSON.
Проверка строки JSON с помощью функции ISJSON
Функция ISJSON
проверяет, содержит ли строка допустимый JSON.
В приведенном ниже примере возвращаются строки, в которых столбец JSON содержит допустимый текст JSON. Без явного ограничения JSON можно ввести любой текст в столбце nvarchar :
SELECT *
FROM Families
WHERE ISJSON(doc) > 0;
Дополнительные сведения см. в разделе ISJSON.
Для извлечения значения из строки JSON используется функция JSON_VALUE
Функция JSON_VALUE
извлекает скалярное значение из строки JSON. Следующий запрос возвращает документы, в которых id
поле JSON соответствует значениюDesaiFamily
, упорядоченным по полям city
JSON:state
SELECT JSON_VALUE(f.doc, '$.id') AS Name,
JSON_VALUE(f.doc, '$.address.city') AS City,
JSON_VALUE(f.doc, '$.address.county') AS County
FROM Families f
WHERE JSON_VALUE(f.doc, '$.id') = N'DesaiFamily'
ORDER BY JSON_VALUE(f.doc, '$.address.city') DESC,
JSON_VALUE(f.doc, '$.address.state') ASC
Результаты этого запроса показаны в приведенной ниже таблице.
Имя. | Город | Округ |
---|---|---|
DesaiFamily |
NY |
Manhattan |
Дополнительные сведения см. в JSON_VALUE.
Для извлечения объекта или массива из строки JSON используется функция JSON_QUERY
Функция JSON_QUERY
извлекает объект или массив из строки JSON. В следующем примере показано, как можно вернуть фрагмент JSON в результатах запроса.
SELECT JSON_QUERY(f.doc, '$.address') AS Address,
JSON_QUERY(f.doc, '$.parents') AS Parents,
JSON_QUERY(f.doc, '$.parents[0]') AS Parent0
FROM Families f
WHERE JSON_VALUE(f.doc, '$.id') = N'DesaiFamily';
Результаты этого запроса показаны в приведенной ниже таблице.
Адрес | Родители | Parent0 |
---|---|---|
{ "state": "NY", "county": "Manhattan", "city": "NY" } |
[ { "familyName": "Desai", "givenName": "Prashanth" }, { "familyName": "Miller", "givenName": "Helen" } ] |
{ "familyName": "Desai", "givenName": "Prashanth" } |
Дополнительные сведения см. в JSON_QUERY.
Анализ вложенных коллекций JSON
OPENJSON
функция позволяет преобразовать вложенный объект JSON в набор строк, а затем присоединить его к родительскому элементу. Например, можно вернуть все документы о семьях и присоединить их к объектам children
, которые хранятся в виде внутреннего массива JSON:
SELECT JSON_VALUE(f.doc, '$.id') AS Name,
JSON_VALUE(f.doc, '$.address.city') AS City,
c.givenName,
c.grade
FROM Families f
CROSS APPLY OPENJSON(f.doc, '$.children') WITH (
grade INT,
givenName NVARCHAR(100)
) c
Результаты этого запроса показаны в приведенной ниже таблице.
Имя. | Город | givenName | Оценка |
---|---|---|---|
DesaiFamily |
NY |
Jesse |
1 |
DesaiFamily |
NY |
Lisa |
8 |
Возвращаются две строки, так как одна родительская строка объединяется с двумя дочерними строками, созданными путем синтаксического анализа двух элементов дочерних дочерних элементов. Функция OPENJSON
анализирует фрагмент children
из столбца doc
и возвращает grade
и givenName
из каждого элемента в виде набора строк. Этот набор строк можно объединить с родительским документом.
Запрос вложенных вложенных вложенных вложенных фрагментов JSON
Вы можете использовать несколько вызовов CROSS APPLY OPENJSON
для запроса вложенных структур JSON. В документе JSON, используемом в этом примере, есть вложенный массив с именем children
, каждый дочерний элемент которого имеет вложенный массив pets
. Следующий запрос анализирует дочерние элементы из каждого документа, возвращает каждый объект массива в виде строки, а затем анализирует pets
массив:
SELECT c.familyName,
c.givenName AS childGivenName,
p.givenName AS petName
FROM Families f
CROSS APPLY OPENJSON(f.doc) WITH (
familyName NVARCHAR(100),
children NVARCHAR(MAX) AS JSON
) AS a
CROSS APPLY OPENJSON(children) WITH (
familyName NVARCHAR(100),
givenName NVARCHAR(100),
pets NVARCHAR(max) AS JSON
) AS c
OUTER APPLY OPENJSON(pets) WITH (givenName NVARCHAR(100)) AS p;
Первый OPENJSON
вызов возвращает фрагмент массива children
с помощью предложения AS JSON. Этот фрагмент массива предоставляется второй OPENJSON
функции, возвращающей givenName
каждый firstName
дочерний объект, а также массив pets
. Массив pets
предоставляется OPENJSON
третьей функции, возвращающей givenName
животного.
Результаты этого запроса показаны в приведенной ниже таблице.
familyName | childGivenName | petName |
---|---|---|
Desai |
Jesse |
Goofy |
Desai |
Jesse |
Shadow |
Desai |
Lisa |
NULL |
Корневой документ объединяется с двумя строками children
, возвращаемыми при первом вызове OPENJSON(children)
, в результате чего получаются две строки (или два кортежа). Затем каждая строка объединяется с новыми строками, созданными функцией OPENJSON(pets)
, с помощью оператора OUTER APPLY
. Джесси имеет двух домашних животных, поэтому (Desai, Jesse)
присоединены к двум строкам, созданным для Goofy
и Shadow
. Лиза не имеет домашних животных, поэтому нет строк, возвращаемых OPENJSON(pets)
для этого кортежа. Тем не менее, так как мы используем OUTER APPLY
, мы получаем NULL
в столбце. Если мы ставим CROSS APPLY
вместо OUTER APPLY
этого, Лиза не будет возвращена в результате, потому что нет строк домашних животных, которые могут быть присоединены с этим кортежем.
Сравнение JSON_VALUE и JSON_QUERY
Ключевое различие между и JSON_QUERY
заключается в JSON_VALUE
том, что JSON_VALUE
возвращает скалярное значение, а JSON_QUERY
возвращает объект или массив.
Рассмотрим следующий пример данных в формате JSON.
{
"a": "[1,2]",
"b": [1, 2],
"c": "hi"
}
В приведенном примере элементы "а" и "c" являются строковыми значениями, а элемент "b" — массивом. JSON_VALUE
и JSON_QUERY
возвращает следующие результаты:
Путь | Возвращаемые значения JSON_VALUE |
Возвращаемые значения JSON_QUERY |
---|---|---|
$ |
NULL или ошибка |
{ "a": "[1,2]", "b": [1, 2], "c": "hi" } |
$.a |
[1,2] |
NULL или ошибка |
$.b |
NULL или ошибка |
[1,2] |
$.b[0] |
1 |
NULL или ошибка |
$.c |
hi |
NULL или ошибка |
Тестирование JSON_VALUE и JSON_QUERY на образце базы данных AdventureWorks
Проверьте встроенные функции, описанные в этой статье, выполнив следующие примеры с примерами AdventureWorks2022
базы данных. Дополнительные сведения о добавлении данных JSON для тестирования с помощью скрипта см. в статье "Поддержка тестового диска JSON".
В следующих примерах столбец Info
таблицы SalesOrder_json
содержит текст в формате JSON.
Пример 1. Возвращение стандартных столбцов и данных JSON
Следующий запрос возвращает значения и из стандартных реляционных столбцов, и из столбца JSON.
SELECT SalesOrderNumber,
OrderDate,
Status,
ShipDate,
AccountNumber,
TotalDue,
JSON_QUERY(Info, '$.ShippingInfo') ShippingInfo,
JSON_QUERY(Info, '$.BillingInfo') BillingInfo,
JSON_VALUE(Info, '$.SalesPerson.Name') SalesPerson,
JSON_VALUE(Info, '$.ShippingInfo.City') City,
JSON_VALUE(Info, '$.Customer.Name') Customer,
JSON_QUERY(OrderItems, '$') OrderItems
FROM Sales.SalesOrder_json
WHERE ISJSON(Info) > 0;
Пример 2. Агрегирование и фильтрация значений JSON
Следующий запрос рассчитывает промежуточные итоги по имени клиента (хранятся в формате JSON) и состояние (хранится в обычном столбце). Затем результаты фильтруются по городу (в формате JSON) и по дате заказа OrderDate (в обычном столбце).
DECLARE @territoryid INT;
DECLARE @city NVARCHAR(32);
SET @territoryid = 3;
SET @city = N'Seattle';
SELECT JSON_VALUE(Info, '$.Customer.Name') AS Customer,
Status,
SUM(SubTotal) AS Total
FROM Sales.SalesOrder_json
WHERE TerritoryID = @territoryid
AND JSON_VALUE(Info, '$.ShippingInfo.City') = @city
AND OrderDate > '1/1/2015'
GROUP BY JSON_VALUE(Info, '$.Customer.Name'),
Status
HAVING SUM(SubTotal) > 1000;
Обновление значений свойств в тексте JSON с помощью функции JSON_MODIFY
Функция JSON_MODIFY
обновляет значение свойства в строке JSON и возвращает обновленную строку JSON.
В следующем примере показано изменение значения свойства JSON в переменной, содержащей JSON-данные.
SET @info = JSON_MODIFY(@jsonInfo, '$.info.address[0].town', 'London');
Дополнительные сведения см. в JSON_MODIFY.