Validación, consulta y cambio de datos JSON con funciones integradas (SQL Server)
Se aplica a: SQL Server 2016 (13.x) y versiones posteriores Azure SQL Database Azure SQL Managed Instance
La compatibilidad integrada con JSON incluye las siguientes funciones integradas que se describen brevemente en este artículo.
- ISJSON prueba si una cadena contiene un valor JSON válido.
- JSON_VALUE extrae un valor escalar de una cadena JSON.
- JSON_QUERY extrae un objeto o una matriz de una cadena JSON.
- JSON_MODIFY actualiza el valor de una propiedad en una cadena JSON y devuelve la cadena JSON actualizada.
Para todas las funciones JSON, revisa Funciones JSON.
Los ejemplos de código de Transact-SQL de este artículo utilizan la base de datos de ejemplo AdventureWorks2022
o AdventureWorksDW2022
, que se puede descargar desde la página principal de Ejemplos y proyectos de la comunidad de Microsoft SQL Server.
Texto de JSON para los ejemplos de esta página
En los ejemplos de esta página se usa el texto JSON similar al contenido que se muestra en el ejemplo siguiente:
{
"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
}
Este documento JSON, que contiene elementos complejos anidados, se almacena en la tabla de ejemplo siguiente:
CREATE TABLE Families (
id INT identity CONSTRAINT PK_JSON_ID PRIMARY KEY,
[doc] NVARCHAR(MAX)
);
Las funciones JSON funcionan igual si el documento JSON se almacena en varchar, nvarchar o en el tipo de datos json nativo.
Validar texto JSON mediante la función ISJSON
La función ISJSON
prueba si una cadena contiene un valor JSON válido.
En el ejemplo siguiente, se devuelven las filas en las que la columna JSON contiene texto JSON válido. Sin una restricción JSON explícita, puede escribir cualquier texto en la columna nvarchar:
SELECT *
FROM Families
WHERE ISJSON(doc) > 0;
Para obtener más información, consulta ISJSON.
Extraer un valor de texto JSON mediante la función JSON_VALUE
La función JSON_VALUE
extrae un valor escalar de una cadena JSON. La consulta siguiente devuelve los documentos en los que el campo JSON id
coincida con el valor DesaiFamily
, ordenados por city
y los campos 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
Los resultados de esta consulta se muestran en la tabla siguiente:
Nombre | City | Condado |
---|---|---|
DesaiFamily |
NY |
Manhattan |
Para obtener más información, consulta JSON_VALUE.
Extraer un objeto o una matriz de texto JSON mediante la función JSON_QUERY
La función JSON_QUERY
extrae un objeto o una matriz de una cadena JSON. En el ejemplo siguiente se muestra cómo devolver un fragmento de JSON en los resultados de la consulta.
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';
Los resultados de esta consulta se muestran en la tabla siguiente:
Dirección | Parents | Parent0 |
---|---|---|
{ "state": "NY", "county": "Manhattan", "city": "NY" } |
[ { "familyName": "Desai", "givenName": "Prashanth" }, { "familyName": "Miller", "givenName": "Helen" } ] |
{ "familyName": "Desai", "givenName": "Prashanth" } |
Para obtener más información, consulta JSON_QUERY.
Análisis de colecciones JSON anidadas
La función OPENJSON
permite transformar la submatriz JSON en el conjunto de filas y, después, combinarlo con el elemento primario. Como ejemplo, puede devolver todos los documentos de la familia y "unirlos" con sus objetos children
que se almacenan como una matriz de JSON interna:
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
Los resultados de esta consulta se muestran en la tabla siguiente:
Nombre | Ciudad | givenName | grade |
---|---|---|---|
DesaiFamily |
NY |
Jesse |
1 |
DesaiFamily |
NY |
Lisa |
8 |
Se devuelven dos filas, porque una fila primaria se combina con dos filas secundarias generadas mediante el análisis de dos elementos de la submatriz secundaria. La función OPENJSON
analiza el fragmento children
de la columna doc
y devuelve grade
y givenName
de cada elemento como un conjunto de filas. Este conjunto de filas se puede combinar con el documento primario.
Consulta de submatrices JSON jerárquicas anidadas
Puede aplicar varias llamadas CROSS APPLY OPENJSON
para consultar estructuras JSON anidadas. El documento JSON que se usa en este ejemplo tiene una matriz anidada denominada children
, donde cada elemento secundario tiene una matriz anidada de pets
. La consulta siguiente analiza los elementos secundarios de cada documento, devuelve cada objeto de matriz como una fila y, después, analiza la matriz 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;
La primera llamada a OPENJSON
devuelve un fragmento de la matriz children
mediante la cláusula AS JSON. Este fragmento de matriz se proporciona a la segunda función OPENJSON
que devuelve givenName
, firstName
de cada elemento secundario, así como la matriz de pets
. La matriz de pets
se proporciona a la tercera función OPENJSON
, que devuelve el valor givenName
de la mascota.
Los resultados de esta consulta se muestran en la tabla siguiente:
familyName | childGivenName | petName |
---|---|---|
Desai |
Jesse |
Goofy |
Desai |
Jesse |
Shadow |
Desai |
Lisa |
NULL |
El documento raíz se combina con dos filas children
devueltas por la primera llamada a OPENJSON(children)
, lo que genera dos filas (o tuplas). Después, cada fila se combina con las filas nuevas generadas por OPENJSON(pets)
mediante el operador OUTER APPLY
. Jesse tiene dos mascotas, por lo que (Desai, Jesse)
se combina con dos filas generadas para Goofy
y Shadow
. Lisa no tiene mascotas, por lo que OPENJSON(pets)
no devuelve filas para esta tupla. Pero como usamos OUTER APPLY
, obtenemos NULL
en la columna. Si se coloca CROSS APPLY
en lugar de OUTER APPLY
, Lisa no se devolvería en el resultado, porque no hay ninguna fila de mascotas que se pueda combinar con esta tupla.
Comparación de JSON_VALUE y JSON_QUERY
La diferencia clave entre JSON_VALUE
y JSON_QUERY
es que JSON_VALUE
devuelve un valor escalar, mientras que JSON_QUERY
devuelve un objeto o una matriz.
Observe el siguiente ejemplo de texto JSON.
{
"a": "[1,2]",
"b": [1, 2],
"c": "hi"
}
En este ejemplo de texto JSON, los miembros de datos "a" y "c" son valores de cadena, mientras que el miembro de datos "b" es una matriz. JSON_VALUE
y JSON_QUERY
devuelven los resultados siguientes:
Path | JSON_VALUE devuelve |
JSON_QUERY devuelve |
---|---|---|
$ |
NULL o error |
{ "a": "[1,2]", "b": [1, 2], "c": "hi" } |
$.a |
[1,2] |
NULL o error |
$.b |
NULL o error |
[1,2] |
$.b[0] |
1 |
NULL o error |
$.c |
hi |
NULL o error |
Probar JSON_VALUE y JSON_QUERY con la base de datos de ejemplo AdventureWorks
Pruebe las funciones integradas que se describen en este artículo al ejecutar los ejemplos siguientes con la base de datos de ejemplo AdventureWorks2022
. A fin de obtener información sobre cómo agregar datos JSON para pruebas ejecutando un script, vea Compatibilidad con la versión limitada de prueba integrada de JSON.
En los ejemplos siguientes, la columna Info
de la tabla SalesOrder_json
contiene texto JSON.
Ejemplo 1: devolver columnas estándar y datos JSON
La consulta siguiente devuelve valores de las columnas relacionales estándar y de una columna 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;
Ejemplo 2: agregar y filtrar valores JSON
La consulta siguiente agrega subtotales por nombre de cliente (almacenados en JSON) y estado (almacenado en una columna normal). Luego, filtra los resultados por ciudad (almacenados en JSON) y OrderDate (almacenados en una columna normal).
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;
Actualizar valores de propiedad en texto JSON mediante la función JSON_MODIFY
La función JSON_MODIFY
actualiza el valor de una propiedad en una cadena JSON y devuelve la cadena JSON actualizada.
En el ejemplo siguiente, se actualiza el valor de una propiedad JSON en una variable que contiene JSON.
SET @info = JSON_MODIFY(@jsonInfo, '$.info.address[0].town', 'London');
Para obtener más información, consulta JSON_MODIFY.