En SQLite, json_each()
es una función con valores de tabla que recorre el valor JSON proporcionado como su primer argumento y devuelve una tabla que consta de una fila para cada elemento de matriz o miembro de objeto.
Proporcionamos el valor JSON como argumento cuando llamamos a la función.
Opcionalmente, podemos pasar un segundo argumento, que especifica una ruta desde la que empezar. Cuando hacemos esto, json_each()
trata esa ruta como el elemento de nivel superior.
El json_each()
La función solo recorre los elementos secundarios inmediatos de la matriz u objeto de nivel superior, o solo el elemento de nivel superior en sí mismo si el elemento de nivel superior es un valor primitivo. Para recorrer recursivamente la subestructura JSON, use json_tree()
en su lugar.
Sintaxis
Podemos usar la función de las siguientes formas:
json_each(X)
json_each(X,P)
Donde X
representa el JSON y P
es un argumento opcional que representa la ruta a tratar como de nivel superior.
Ejemplo
Aquí hay un ejemplo para demostrar cómo funciona:
SELECT * FROM json_each('{ "name" : "Woof", "age" : 10 }');
Resultado:
+------+-------+---------+------+----+--------+---------+------+ | key | value | type | atom | id | parent | fullkey | path | +------+-------+---------+------+----+--------+---------+------+ | name | Woof | text | Woof | 2 | null | $.name | $ | | age | 10 | integer | 10 | 4 | null | $.age | $ | +------+-------+---------+------+----+--------+---------+------+
Podemos ver que cada miembro del objeto tiene su propia fila con información útil, como su tipo (valor de texto SQL), ruta, etc.
Con respecto al id
columna, de acuerdo con la documentación de SQLite, este es un número de mantenimiento interno, cuyo cálculo podría cambiar en versiones futuras. La única garantía es que el id
la columna será diferente para cada fila.
La columna principal siempre es null
al llamar a json_each()
. Esta columna se vuelve más significativa cuando se usa json_tree()
.
Matriz
En este ejemplo, el valor JSON es una matriz:
SELECT * FROM json_each('[ 10, 30, 45 ]');
Resultado:
+-----+-------+---------+------+----+--------+---------+------+ | key | value | type | atom | id | parent | fullkey | path | +-----+-------+---------+------+----+--------+---------+------+ | 0 | 10 | integer | 10 | 1 | null | $[0] | $ | | 1 | 30 | integer | 30 | 2 | null | $[1] | $ | | 2 | 45 | integer | 45 | 3 | null | $[2] | $ | +-----+-------+---------+------+----+--------+---------+------+
Especifique una ruta
Podemos usar un segundo argumento para especificar una ruta para tratar como el nivel superior.
Ejemplo:
SELECT * FROM json_each('{ "a" : 1, "b" : [ 4, 7, 8 ] }', '$.b');
Resultado:
+-----+-------+---------+------+----+--------+---------+------+ | key | value | type | atom | id | parent | fullkey | path | +-----+-------+---------+------+----+--------+---------+------+ | 0 | 4 | integer | 4 | 5 | null | $.b[0] | $.b | | 1 | 7 | integer | 7 | 6 | null | $.b[1] | $.b | | 2 | 8 | integer | 8 | 7 | null | $.b[2] | $.b | +-----+-------+---------+------+----+--------+---------+------+
Documento más grande
En este ejemplo, usaremos un documento JSON más grande. Primero, llamemos a json_each()
sin especificar una ruta:
SELECT * FROM json_each('[
{
"user" : "Spike",
"age" : 30,
"scores" : [ 9, 7, 3 ]
},
{
"user" : "Faye",
"age" : 25,
"scores" : [ 90, 87, 93 ]
},
{
"user" : "Jet",
"age" : 40,
"scores" : [ 50, 38, 67 ]
}
]'
);
Resultado:
+-----+----------------------------------------------+--------+------+----+--------+---------+------+ | key | value | type | atom | id | parent | fullkey | path | +-----+----------------------------------------------+--------+------+----+--------+---------+------+ | 0 | {"user":"Spike","age":30,"scores":[9,7,3]} | object | N/A | 1 | N/A | $[0] | $ | | 1 | {"user":"Faye","age":25,"scores":[90,87,93]} | object | N/A | 11 | N/A | $[1] | $ | | 2 | {"user":"Jet","age":40,"scores":[50,38,67]} | object | N/A | 21 | N/A | $[2] | $ | +-----+----------------------------------------------+--------+------+----+--------+---------+------+
En este caso, nuestro valor JSON es una matriz que contiene tres objetos. Cada objeto se enumera en los resultados.
Ahora, llamemos a json_each()
de nuevo, pero esta vez especificaremos una ruta:
SELECT * FROM json_each('[
{
"user" : "Spike",
"age" : 30,
"scores" : [ 9, 7, 3 ]
},
{
"user" : "Faye",
"age" : 25,
"scores" : [ 90, 87, 93 ]
},
{
"user" : "Jet",
"age" : 40,
"scores" : [ 50, 38, 67 ]
}
]',
'$[1]'
);
Resultado:
+--------+------------+---------+------+----+--------+-------------+------+ | key | value | type | atom | id | parent | fullkey | path | +--------+------------+---------+------+----+--------+-------------+------+ | user | Faye | text | Faye | 13 | null | $[1].user | $[1] | | age | 25 | integer | 25 | 15 | null | $[1].age | $[1] | | scores | [90,87,93] | array | null | 17 | null | $[1].scores | $[1] | +--------+------------+---------+------+----+--------+-------------+------+
En este caso, elegí el segundo elemento de la matriz especificando [1]
(las matrices están basadas en cero en SQLite).
El resultado es que la salida contiene información sobre el segundo elemento de la matriz.
Esta vez podemos ver que la path
la columna contiene $[1]
.
Profundicemos:
SELECT * FROM json_each('[
{
"user" : "Spike",
"age" : 30,
"scores" : [ 9, 7, 3 ]
},
{
"user" : "Faye",
"age" : 25,
"scores" : [ 90, 87, 93 ]
},
{
"user" : "Jet",
"age" : 40,
"scores" : [ 50, 38, 67 ]
}
]',
'$[1].scores'
);
Resultado:
+-----+-------+---------+------+----+--------+----------------+-------------+ | key | value | type | atom | id | parent | fullkey | path | +-----+-------+---------+------+----+--------+----------------+-------------+ | 0 | 90 | integer | 90 | 18 | null | $[1].scores[0] | $[1].scores | | 1 | 87 | integer | 87 | 19 | null | $[1].scores[1] | $[1].scores | | 2 | 93 | integer | 93 | 20 | null | $[1].scores[2] | $[1].scores | +-----+-------+---------+------+----+--------+----------------+-------------+
Ahora obtenemos una fila para cada elemento en las scores
matriz.
Filtrado de la consulta
Podemos modificar nuestra consulta para filtrar los resultados en función de un criterio dado. Por ejemplo:
SELECT
fullkey,
value
FROM json_each('[
{
"user" : "Spike",
"age" : 30,
"scores" : [ 9, 7, 3 ]
},
{
"user" : "Faye",
"age" : 25,
"scores" : [ 90, 87, 93 ]
},
{
"user" : "Jet",
"age" : 40,
"scores" : [ 50, 38, 67 ]
}
]'
)
WHERE json_each.value LIKE '%Faye%';
Resultado:
+---------+----------------------------------------------+ | fullkey | value | +---------+----------------------------------------------+ | $[1] | {"user":"Faye","age":25,"scores":[90,87,93]} | +---------+----------------------------------------------+
Un ejemplo de base de datos
Supongamos que tenemos la siguiente tabla:
SELECT * FROM guests;
Resultado:
+-------+--------------------------------------------------+ | guest | lunch | +-------+--------------------------------------------------+ | Zohan | ["Beef Pie", "Fruit Salad", "Apple Juice"] | | Amy | ["Vegetable Quiche", "Apple", "Fruit Juice"] | | Rohit | ["Beef Curry", "Dragonfruit", "Vegetable Juice"] | | Igor | ["Chicken Pie", "Jackfruit", "Fruit Juice"] | | Stacy | ["Chicken Curry", "Fruit Salad", "Apple Juice"] | | Aisha | ["Chicken Curry", "Apple Pie", "Apple Juice"] | +-------+--------------------------------------------------+
Esta tabla se llama guests
tiene dos columnas. La primera columna contiene el nombre del invitado y la segunda columna contiene su orden de almuerzo. Pueden pedir tres platos para el almuerzo. Su orden de almuerzo tiene la forma de una matriz, donde cada plato es un elemento de la matriz.
Aquí hay un ejemplo de cómo ejecutar una consulta que incorpora json_each()
contra esta mesa:
SELECT DISTINCT
guest,
lunch
FROM
guests,
json_each(lunch)
WHERE json_each.value LIKE 'Apple Juice';
Resultado:
+-------+-------------------------------------------------+ | guest | lunch | +-------+-------------------------------------------------+ | Zohan | ["Beef Pie", "Fruit Salad", "Apple Juice"] | | Stacy | ["Chicken Curry", "Fruit Salad", "Apple Juice"] | | Aisha | ["Chicken Curry", "Apple Pie", "Apple Juice"] | +-------+-------------------------------------------------+
Aquí, devolvimos a todos los invitados que ordenaron jugo de manzana con su almuerzo, junto con su pedido de almuerzo completo.
Si queremos devolver a todos los invitados que pidieron "algo" de manzana, podríamos hacer esto:
SELECT DISTINCT
guest,
lunch
FROM
guests,
json_each(lunch)
WHERE json_each.value LIKE 'Apple%';
Resultado:
+-------+-------------------------------------------------+ | guest | lunch | +-------+-------------------------------------------------+ | Zohan | ["Beef Pie", "Fruit Salad", "Apple Juice"] | | Amy | ["Vegetable Quiche", "Apple", "Fruit Juice"] | | Stacy | ["Chicken Curry", "Fruit Salad", "Apple Juice"] | | Aisha | ["Chicken Curry", "Apple Pie", "Apple Juice"] | +-------+-------------------------------------------------+
Note que usé el DISTINCT
cláusula en mi consulta. Esto asegura que no obtengamos múltiples filas para el mismo invitado. Para demostrar lo que quiero decir, aquí está la consulta de nuevo, pero sin DISTINCT
cláusula:
SELECT
guest,
lunch
FROM
guests,
json_each(lunch)
WHERE json_each.value LIKE 'Apple%';
Resultado:
+-------+-------------------------------------------------+ | guest | lunch | +-------+-------------------------------------------------+ | Zohan | ["Beef Pie", "Fruit Salad", "Apple Juice"] | | Amy | ["Vegetable Quiche", "Apple", "Fruit Juice"] | | Stacy | ["Chicken Curry", "Fruit Salad", "Apple Juice"] | | Aisha | ["Chicken Curry", "Apple Pie", "Apple Juice"] | | Aisha | ["Chicken Curry", "Apple Pie", "Apple Juice"] | +-------+-------------------------------------------------+
Esta vez Aisha aparece dos veces. Eso es porque pidió dos platos de manzana para el almuerzo:pastel de manzana y jugo de manzana.