In SQLite, json_each()
è una funzione con valori di tabella che esamina il valore JSON fornito come primo argomento e restituisce una tabella composta da una riga per ogni elemento dell'array o membro dell'oggetto.
Forniamo il valore JSON come argomento quando chiamiamo la funzione.
Possiamo opzionalmente passare un secondo argomento, che specifica un percorso da cui partire. Quando lo facciamo, json_each()
considera quel percorso come l'elemento di primo livello.
Il json_each()
la funzione percorre solo i figli immediati dell'array o dell'oggetto di livello superiore, o solo l'elemento di livello superiore stesso se l'elemento di livello superiore è un valore primitivo. Per scorrere in modo ricorsivo la sottostruttura JSON, utilizza json_tree()
invece.
Sintassi
Possiamo utilizzare la funzione nei seguenti modi:
json_each(X)
json_each(X,P)
Dove X
rappresenta il JSON e P
è un argomento facoltativo che rappresenta il percorso da considerare come di livello superiore.
Esempio
Ecco un esempio per dimostrare come funziona:
SELECT * FROM json_each('{ "name" : "Woof", "age" : 10 }');
Risultato:
+------+-------+---------+------+----+--------+---------+------+ | key | value | type | atom | id | parent | fullkey | path | +------+-------+---------+------+----+--------+---------+------+ | name | Woof | text | Woof | 2 | null | $.name | $ | | age | 10 | integer | 10 | 4 | null | $.age | $ | +------+-------+---------+------+----+--------+---------+------+
Possiamo vedere che ogni membro dell'oggetto ha una propria riga con alcune informazioni utili, come il tipo (valore del testo SQL), il percorso, ecc.
Per quanto riguarda l'id
colonna, secondo la documentazione di SQLite si tratta di un numero di pulizia interno, il cui calcolo potrebbe cambiare nelle versioni future. L'unica garanzia è che l'id
la colonna sarà diversa per ogni riga.
La colonna principale è sempre null
quando si chiama json_each()
. Questa colonna diventa più significativa quando si utilizza json_tree()
.
Matrice
In questo esempio, il valore JSON è un array:
SELECT * FROM json_each('[ 10, 30, 45 ]');
Risultato:
+-----+-------+---------+------+----+--------+---------+------+ | 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] | $ | +-----+-------+---------+------+----+--------+---------+------+
Specifica un percorso
Possiamo usare un secondo argomento per specificare un percorso da trattare come di livello superiore.
Esempio:
SELECT * FROM json_each('{ "a" : 1, "b" : [ 4, 7, 8 ] }', '$.b');
Risultato:
+-----+-------+---------+------+----+--------+---------+------+ | 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 più grande
In questo esempio useremo un documento JSON più grande. Per prima cosa, chiamiamo json_each()
senza specificare un percorso:
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 ]
}
]'
);
Risultato:
+-----+----------------------------------------------+--------+------+----+--------+---------+------+ | 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] | $ | +-----+----------------------------------------------+--------+------+----+--------+---------+------+
In questo caso, il nostro valore JSON è un array che contiene tre oggetti. Ogni oggetto è elencato nei risultati.
Ora chiamiamo json_each()
di nuovo, ma questa volta specificheremo un percorso:
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]'
);
Risultato:
+--------+------------+---------+------+----+--------+-------------+------+ | 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] | +--------+------------+---------+------+----+--------+-------------+------+
In questo caso ho scelto il secondo elemento dell'array specificando [1]
(gli array sono basati su zero in SQLite).
Il risultato è che l'output contiene informazioni sul secondo elemento dell'array.
Questa volta possiamo vedere che il path
la colonna contiene $[1]
.
Andiamo più a fondo:
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'
);
Risultato:
+-----+-------+---------+------+----+--------+----------------+-------------+ | 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 | +-----+-------+---------+------+----+--------+----------------+-------------+
Ora otteniamo una riga per ogni elemento nei scores
matrice.
Filtraggio della query
Possiamo modificare la nostra query per filtrare i risultati in base a un determinato criterio. Ad esempio:
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%';
Risultato:
+---------+----------------------------------------------+ | fullkey | value | +---------+----------------------------------------------+ | $[1] | {"user":"Faye","age":25,"scores":[90,87,93]} | +---------+----------------------------------------------+
Un esempio di database
Supponiamo di avere la seguente tabella:
SELECT * FROM guests;
Risultato:
+-------+--------------------------------------------------+ | 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"] | +-------+--------------------------------------------------+
Questa tabella chiamata guests
ha due colonne. La prima colonna contiene il nome dell'ospite e la seconda colonna contiene l'ordine del pranzo. Possono ordinare tre piatti per pranzo. Il loro ordine per il pranzo è sotto forma di una matrice, in cui ogni piatto è un elemento della matrice.
Ecco un esempio di esecuzione di una query che incorpora json_each()
contro questa tabella:
SELECT DISTINCT
guest,
lunch
FROM
guests,
json_each(lunch)
WHERE json_each.value LIKE 'Apple Juice';
Risultato:
+-------+-------------------------------------------------+ | guest | lunch | +-------+-------------------------------------------------+ | Zohan | ["Beef Pie", "Fruit Salad", "Apple Juice"] | | Stacy | ["Chicken Curry", "Fruit Salad", "Apple Juice"] | | Aisha | ["Chicken Curry", "Apple Pie", "Apple Juice"] | +-------+-------------------------------------------------+
Qui, abbiamo restituito tutti gli ospiti che hanno ordinato il succo di mela con il loro pranzo, insieme al loro ordine completo per il pranzo.
Se vogliamo restituire tutti gli ospiti che hanno ordinato "qualcosa" di Apple, potremmo farlo:
SELECT DISTINCT
guest,
lunch
FROM
guests,
json_each(lunch)
WHERE json_each.value LIKE 'Apple%';
Risultato:
+-------+-------------------------------------------------+ | 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"] | +-------+-------------------------------------------------+
Nota che ho usato il DISTINCT
clausola nella mia domanda. Ciò garantisce che non vengano restituite più righe per lo stesso ospite. Per dimostrare cosa intendo, ecco di nuovo la query, ma senza DISTINCT
clausola:
SELECT
guest,
lunch
FROM
guests,
json_each(lunch)
WHERE json_each.value LIKE 'Apple%';
Risultato:
+-------+-------------------------------------------------+ | 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"] | +-------+-------------------------------------------------+
Questa volta Aisha appare due volte. Questo perché ha ordinato due piatti di mele per pranzo:torta di mele e succo di mela.