Si está utilizando OPENJSON()
, pero está tratando de recordar cómo seleccionar un fragmento interno del documento JSON, siga leyendo.
El OPENJSON()
La sintaxis le permite convertir documentos JSON en una vista tabular. También le permite seleccionar un fragmento JSON anidado del documento JSON.
La forma de hacerlo es con rutas .
Caminos
Una ruta consta de lo siguiente:
- Un signo de dólar (
$
), que representa el elemento de contexto. - Un conjunto de pasos de ruta. Los pasos de ruta pueden contener los siguientes elementos y operadores:
- Nombres clave. Por ejemplo,
$.pets
y$.pets.dogs
. Si el nombre de la clave comienza con un signo de dólar o contiene caracteres especiales, como espacios, debe estar entre comillas (por ejemplo,$."my pets"
). - Elementos de matriz. Por ejemplo,
$.pets.dogs[1]
. Los índices de matriz están basados en cero, por lo que este ejemplo selecciona el segundo elemento de la matriz. - El operador punto (
.
) indica un miembro de un objeto. Por ejemplo, en$.pets.dogs
,dogs
es miembro depets
.
- Nombres clave. Por ejemplo,
Ejemplo básico
Aquí hay un ejemplo simple para demostrarlo.
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, '$.pets.dogs')
WITH (
[id] int,
[name] varchar(60),
[sex] varchar(6)
);
Resultado:
+------+--------+--------+ | id | name | sex | |------+--------+--------| | 1 | Fetch | Male | | 2 | Fluffy | Male | | 3 | Wag | Female | +------+--------+--------+
En este caso, el segundo argumento de OPENJSON()
es '$.pets.dogs'
, lo que significa que estamos seleccionando el valor de los dogs
key, que en sí misma es hija de pets
.
El signo de dólar ($
) representa el elemento de contexto.
Tenga en cuenta que en este ejemplo, también uso WITH
cláusula para definir el esquema. Si no incluyera eso, se usaría el esquema predeterminado en su lugar.
Así es como se ve usando el esquema predeterminado.
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, '$.pets.dogs');
Resultado:
+-------+-------------------------------------------------+--------+ | key | value | type | |-------+-------------------------------------------------+--------| | 0 | { "id" : 1, "name" : "Fetch", "sex" : "Male" } | 5 | | 1 | { "id" : 2, "name" : "Fluffy", "sex" : "Male" } | 5 | | 2 | { "id" : 3, "name" : "Wag", "sex" : "Female" } | 5 | +-------+-------------------------------------------------+--------+
Así que seguimos seleccionando el mismo JSON anidado, solo que estamos usando un esquema diferente.
El esquema predeterminado siempre devuelve tres columnas; clave , valor y tipo .
Selección de elementos de matriz
Como se mencionó, puede usar la notación de corchetes para seleccionar un elemento específico en una matriz.
He aquí un ejemplo.
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, '$.pets.dogs[0]')
WITH (
[id] int,
[name] varchar(60),
[sex] varchar(6)
);
Resultado:
+------+--------+-------+ | id | name | sex | |------+--------+-------| | 1 | Fetch | Male | +------+--------+-------+
Al ver que los índices de matriz están basados en cero, se especifica un valor de 0
devuelve el primer elemento de la matriz.
Así es como se ve este ejemplo cuando se usa el esquema predeterminado (es decir, sin el WITH
cláusula).
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, '$.pets.dogs[0]');
Resultado:
+-------+---------+--------+ | key | value | type | |-------+---------+--------| | id | 1 | 2 | | name | Fetch | 1 | | sex | Male | 1 | +-------+---------+--------+
Modo de ruta
Al usar rutas, tiene la opción de declarar el modo de ruta.
El modo de ruta determina lo que sucede cuando una expresión de ruta contiene un error.
El modo de ruta puede ser lax
o strict
.
- En
lax
modo, la función devuelve valores vacíos si no se puede encontrar la ruta. Por ejemplo, si solicita el valor$.pets.cows
, pero el JSON no contiene esa clave, la función devuelve nulo, pero no genera un error. - En
strict
modo, la función genera un error si no se puede encontrar la ruta.
El modo de ruta predeterminado es lax
, así que si no lo declaras, lax
se usa
Ejemplo
Aquí hay un ejemplo para demostrar cómo cada modo de ruta maneja las rutas faltantes.
Modo relajado
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, 'lax $.pets.cows');
Resultado:
(0 rows affected)
Entonces, el modo laxo no arrojó ningún error. Simplemente resultó en que cero filas se vieron afectadas.
Si especificamos nuestro propio esquema y seleccionamos el subobjeto correcto, pero usamos una ruta faltante para asignar a un nombre de columna, devolvería NULL
en esa columna.
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}'
SELECT *
FROM OPENJSON(@json, 'lax $.pets.dogs')
WITH (
[id] int 'lax $.id',
[name] varchar(60) 'lax $.name',
[color] varchar(6) 'lax $.color'
);
Resultado:
+------+--------+---------+ | id | name | color | |------+--------+---------| | 1 | Fetch | NULL | | 2 | Fluffy | NULL | | 3 | Wag | NULL | +------+--------+---------+
Modo estricto
Esto es lo que sucede cuando usamos el modo estricto.
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, 'strict $.pets.cows');
Resultado:
Msg 13608, Level 16, State 3, Line 16 Property cannot be found on the specified JSON path.
Como era de esperar, resultó en un error.
El mismo error ocurre cuando seleccionamos la clave JSON correcta, pero asignamos una columna a una clave inexistente.
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, 'strict $.pets.dogs')
WITH (
[id] int 'strict $.id',
[name] varchar(60) 'strict $.name',
[color] varchar(6) 'strict $.color'
);
Resultado:
Msg 13608, Level 16, State 6, Line 16 Property cannot be found on the specified JSON path.
Rutas duplicadas
Si su documento JSON contiene rutas duplicadas en el mismo nivel de anidamiento, OPENJSON()
puede devolverlos todos.
Esto contrasta con JSON_VALUE()
y JSON_QUERY()
, los cuales devuelven solo el primer valor que coincide con la ruta.
Aquí hay un ejemplo del uso de OPENJSON()
para devolver rutas duplicadas.
DECLARE @json NVARCHAR(4000) = N'{
"dog": {
"names": {
"name": "Fetch",
"name": "Good Dog"
}
}
}';
SELECT * FROM OPENJSON(@json, '$.dog.names');
Resultado:
+-------+----------+--------+ | key | value | type | |-------+----------+--------| | name | Fetch | 1 | | name | Good Dog | 1 | +-------+----------+--------+
Subobjetos anidados
Al definir su propio esquema, puede usar el AS JSON
opción para devolver un subobjeto completo como su propio documento JSON.
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, '$.pets')
WITH (
[dogs] nvarchar(max) '$.dogs' AS JSON
);
Resultado:
+--------+ | dogs | |--------| | [ { "id" : 1, "name" : "Fetch", "sex" : "Male" }, { "id" : 2, "name" : "Fluffy", "sex" : "Male" }, { "id" : 3, "name" : "Wag", "sex" : "Female" } ] | +--------+
Si no hubiéramos usado el AS JSON
opción, habríamos recibido un error o NULL, dependiendo de si habíamos especificado lax
o strict
modo.
Aquí está en cada modo al omitir el AS JSON
opción.
Modo relajado
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, '$.pets')
WITH (
[dogs] nvarchar(max) 'lax $.dogs'
);
Resultado:
+--------+ | dogs | |--------| | NULL | +--------+
Modo estricto
DECLARE @json NVARCHAR(4000) = N'{
"pets" : {
"cats" : [
{ "id" : 1, "name" : "Fluffy", "sex" : "Female" },
{ "id" : 2, "name" : "Long Tail", "sex" : "Female" },
{ "id" : 3, "name" : "Scratch", "sex" : "Male" }
],
"dogs" : [
{ "id" : 1, "name" : "Fetch", "sex" : "Male" },
{ "id" : 2, "name" : "Fluffy", "sex" : "Male" },
{ "id" : 3, "name" : "Wag", "sex" : "Female" }
]
}
}';
SELECT *
FROM OPENJSON(@json, '$.pets')
WITH (
[dogs] nvarchar(max) 'strict $.dogs'
);
Resultado:
Msg 13624, Level 16, State 1, Line 16 Object or array cannot be found in the specified JSON path.