SQLite
 sql >> Database >  >> RDS >> SQLite

SQLite JSON_TREE()

In SQLite, json_tree() è 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_tree() considera quel percorso come l'elemento di primo livello.

Il json_tree() La funzione percorre ricorsivamente la sottostruttura JSON a partire dall'elemento di livello superiore. Per visualizzare 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, usa json_each() funzione invece.

Sintassi

Possiamo usare json_tree() funzionare nei seguenti modi:

json_tree(X)
json_tree(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_tree('{ "name" : "Woof", "age" : 10 }');

Risultato:

+------+--------------------------+---------+------+----+--------+---------+------+
| key  |          value           |  type   | atom | id | parent | fullkey | path |
+------+--------------------------+---------+------+----+--------+---------+------+
| null | {"name":"Woof","age":10} | object  | null | 0  | null   | $       | $    |
| name | Woof                     | text    | Woof | 2  | 0      | $.name  | $    |
| age  | 10                       | integer | 10   | 4  | 0      | $.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.

Matrice

In questo esempio, il valore JSON è un array:

SELECT * FROM json_tree('[ 10, 30, 45 ]');

Risultato:

+------+------------+---------+------+----+--------+---------+------+
| key  |   value    |  type   | atom | id | parent | fullkey | path |
+------+------------+---------+------+----+--------+---------+------+
| null | [10,30,45] | array   | null | 0  | null   | $       | $    |
| 0    | 10         | integer | 10   | 1  | 0      | $[0]    | $    |
| 1    | 30         | integer | 30   | 2  | 0      | $[1]    | $    |
| 2    | 45         | integer | 45   | 3  | 0      | $[2]    | $    |
+------+------------+---------+------+----+--------+---------+------+

Specifica un percorso

Possiamo usare un secondo argomento per specificare un percorso da trattare come di livello superiore.

Esempio:

SELECT * FROM json_tree('{ "a" : 1, "b" : [ 4, 7, 8 ] }', '$.b');

Risultato:

+-----+---------+---------+------+----+--------+---------+------+
| key |  value  |  type   | atom | id | parent | fullkey | path |
+-----+---------+---------+------+----+--------+---------+------+
| b   | [4,7,8] | array   | null | 4  | null   | $.b     | $    |
| 0   | 4       | integer | 4    | 5  | 4      | $.b[0]  | $.b  |
| 1   | 7       | integer | 7    | 6  | 4      | $.b[1]  | $.b  |
| 2   | 8       | integer | 8    | 7  | 4      | $.b[2]  | $.b  |
+-----+---------+---------+------+----+--------+---------+------+

Documento più grande

In questo esempio useremo un documento JSON più grande. Per prima cosa, chiamiamo json_tree() senza specificare un percorso:

SELECT * FROM json_tree('[
        { 
        "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     |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| null   | [{"user":"Spike","age":30,"scores":[9,7,3]},{"user":"Faye"," | array   | null  | 0    | null   | $              | $           |
| null   | age":25,"scores":[90,87,93]},{"user":"Jet","age":40,"scores  | null    | null  | null | null   | null           | null        |
| null   | ":[50,38,67]}]                                               | null    | null  | null | null   | null           | null        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 0      | {"user":"Spike","age":30,"scores":[9,7,3]}                   | object  | null  | 1    | 0      | $[0]           | $           |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| user   | Spike                                                        | text    | Spike | 3    | 1      | $[0].user      | $[0]        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| age    | 30                                                           | integer | 30    | 5    | 1      | $[0].age       | $[0]        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| scores | [9,7,3]                                                      | array   | null  | 7    | 1      | $[0].scores    | $[0]        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 0      | 9                                                            | integer | 9     | 8    | 7      | $[0].scores[0] | $[0].scores |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 1      | 7                                                            | integer | 7     | 9    | 7      | $[0].scores[1] | $[0].scores |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 2      | 3                                                            | integer | 3     | 10   | 7      | $[0].scores[2] | $[0].scores |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 1      | {"user":"Faye","age":25,"scores":[90,87,93]}                 | object  | null  | 11   | 0      | $[1]           | $           |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| user   | Faye                                                         | text    | Faye  | 13   | 11     | $[1].user      | $[1]        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| age    | 25                                                           | integer | 25    | 15   | 11     | $[1].age       | $[1]        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| scores | [90,87,93]                                                   | array   | null  | 17   | 11     | $[1].scores    | $[1]        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 0      | 90                                                           | integer | 90    | 18   | 17     | $[1].scores[0] | $[1].scores |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 1      | 87                                                           | integer | 87    | 19   | 17     | $[1].scores[1] | $[1].scores |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 2      | 93                                                           | integer | 93    | 20   | 17     | $[1].scores[2] | $[1].scores |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 2      | {"user":"Jet","age":40,"scores":[50,38,67]}                  | object  | null  | 21   | 0      | $[2]           | $           |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| user   | Jet                                                          | text    | Jet   | 23   | 21     | $[2].user      | $[2]        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| age    | 40                                                           | integer | 40    | 25   | 21     | $[2].age       | $[2]        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| scores | [50,38,67]                                                   | array   | null  | 27   | 21     | $[2].scores    | $[2]        |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 0      | 50                                                           | integer | 50    | 28   | 27     | $[2].scores[0] | $[2].scores |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 1      | 38                                                           | integer | 38    | 29   | 27     | $[2].scores[1] | $[2].scores |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
| 2      | 67                                                           | integer | 67    | 30   | 27     | $[2].scores[2] | $[2].scores |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+

In questo caso, il nostro valore JSON è un array che contiene tre oggetti. Ogni oggetto è elencato nei risultati e ciascuno dei membri di tali oggetti è elencato, insieme ai rispettivi valori e così via.

Ora chiamiamo json_tree() di nuovo, ma questa volta specificheremo un percorso:

SELECT * FROM json_tree('[
        { 
        "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     |
+--------+----------------------------------------------+---------+------+----+--------+----------------+-------------+
| null   | {"user":"Faye","age":25,"scores":[90,87,93]} | object  | null | 11 | null   | $[0]           | $           |
| user   | Faye                                         | text    | Faye | 13 | 11     | $[0].user      | $[0]        |
| age    | 25                                           | integer | 25   | 15 | 11     | $[0].age       | $[0]        |
| scores | [90,87,93]                                   | array   | null | 17 | 11     | $[0].scores    | $[0]        |
| 0      | 90                                           | integer | 90   | 18 | 17     | $[0].scores[0] | $[0].scores |
| 1      | 87                                           | integer | 87   | 19 | 17     | $[0].scores[1] | $[0].scores |
| 2      | 93                                           | integer | 93   | 20 | 17     | $[0].scores[2] | $[0].scores |
+--------+----------------------------------------------+---------+------+----+--------+----------------+-------------+

In questo caso ho scelto il secondo elemento dell'array specificando [1] (gli array sono basati su zero in SQLite).

Il risultato è che l'albero è limitato solo al secondo elemento dell'array.

Andiamo più a fondo:

SELECT * FROM json_tree('[
        { 
        "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     |
+--------+------------+---------+------+----+--------+----------------+-------------+
| scores | [90,87,93] | array   | null | 17 | null   | $[0].scores    | $[0]        |
| 0      | 90         | integer | 90   | 18 | 17     | $[0].scores[0] | $[0].scores |
| 1      | 87         | integer | 87   | 19 | 17     | $[0].scores[1] | $[0].scores |
| 2      | 93         | integer | 93   | 20 | 17     | $[0].scores[2] | $[0].scores |
+--------+------------+---------+------+----+--------+----------------+-------------+

Più andiamo in profondità, meno righe vengono restituite. Questo perché stiamo ottenendo solo un albero che inizia nel percorso specifico che abbiamo specificato.

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_tree('[
        { 
        "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_tree.value LIKE '%Faye%';

Risultato:

+-----------+--------------------------------------------------------------+
|  fullkey  |                            value                             |
+-----------+--------------------------------------------------------------+
| $         | [{"user":"Spike","age":30,"scores":[9,7,3]},{"user":"Faye"," |
| null      | age":25,"scores":[90,87,93]},{"user":"Jet","age":40,"scores  |
| null      | ":[50,38,67]}]                                               |
+-----------+--------------------------------------------------------------+
| $[1]      | {"user":"Faye","age":25,"scores":[90,87,93]}                 |
+-----------+--------------------------------------------------------------+
| $[1].user | Faye                                                         |
+-----------+--------------------------------------------------------------+

Possiamo restituire solo l'ultima riga in questo modo:

SELECT *
FROM json_tree('[
        { 
        "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_tree.value = 'Faye';

Risultato:

+------+-------+------+------+----+--------+-----------+------+
| key  | value | type | atom | id | parent |  fullkey  | path |
+------+-------+------+------+----+--------+-----------+------+
| user | Faye  | text | Faye | 13 | 11     | $[1].user | $[1] |
+------+-------+------+------+----+--------+-----------+------+

Restituisci i nodi foglia

Se vogliamo, possiamo limitare i risultati ai soli nodi foglia. Per "nodi foglia", intendo solo quelle chiavi che non hanno ulteriori elementi figlio.

Ci sono un paio di modi per farlo.

Un'opzione consiste nel filtrare tutti gli oggetti e gli array:

SELECT * 
FROM json_tree('[
        { 
        "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_tree.type NOT IN ('object','array');

Risultato:

+------+-------+---------+-------+----+--------+----------------+-------------+
| key  | value |  type   | atom  | id | parent |    fullkey     |    path     |
+------+-------+---------+-------+----+--------+----------------+-------------+
| user | Spike | text    | Spike | 3  | 1      | $[0].user      | $[0]        |
| age  | 30    | integer | 30    | 5  | 1      | $[0].age       | $[0]        |
| 0    | 9     | integer | 9     | 8  | 7      | $[0].scores[0] | $[0].scores |
| 1    | 7     | integer | 7     | 9  | 7      | $[0].scores[1] | $[0].scores |
| 2    | 3     | integer | 3     | 10 | 7      | $[0].scores[2] | $[0].scores |
| user | Faye  | text    | Faye  | 13 | 11     | $[1].user      | $[1]        |
| age  | 25    | integer | 25    | 15 | 11     | $[1].age       | $[1]        |
| 0    | 90    | integer | 90    | 18 | 17     | $[1].scores[0] | $[1].scores |
| 1    | 87    | integer | 87    | 19 | 17     | $[1].scores[1] | $[1].scores |
| 2    | 93    | integer | 93    | 20 | 17     | $[1].scores[2] | $[1].scores |
| user | Jet   | text    | Jet   | 23 | 21     | $[2].user      | $[2]        |
| age  | 40    | integer | 40    | 25 | 21     | $[2].age       | $[2]        |
| 0    | 50    | integer | 50    | 28 | 27     | $[2].scores[0] | $[2].scores |
| 1    | 38    | integer | 38    | 29 | 27     | $[2].scores[1] | $[2].scores |
| 2    | 67    | integer | 67    | 30 | 27     | $[2].scores[2] | $[2].scores |
+------+-------+---------+-------+----+--------+----------------+-------------+

Un altro modo per farlo è controllare atom colonna per valori nulli. In particolare, restituiremmo solo le righe in cui questa colonna doesn't contengono un valore nullo:

SELECT * 
FROM json_tree('[
        { 
        "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 atom IS NOT NULL;

Risultato:

+------+-------+---------+-------+----+--------+----------------+-------------+
| key  | value |  type   | atom  | id | parent |    fullkey     |    path     |
+------+-------+---------+-------+----+--------+----------------+-------------+
| user | Spike | text    | Spike | 3  | 1      | $[0].user      | $[0]        |
| age  | 30    | integer | 30    | 5  | 1      | $[0].age       | $[0]        |
| 0    | 9     | integer | 9     | 8  | 7      | $[0].scores[0] | $[0].scores |
| 1    | 7     | integer | 7     | 9  | 7      | $[0].scores[1] | $[0].scores |
| 2    | 3     | integer | 3     | 10 | 7      | $[0].scores[2] | $[0].scores |
| user | Faye  | text    | Faye  | 13 | 11     | $[1].user      | $[1]        |
| age  | 25    | integer | 25    | 15 | 11     | $[1].age       | $[1]        |
| 0    | 90    | integer | 90    | 18 | 17     | $[1].scores[0] | $[1].scores |
| 1    | 87    | integer | 87    | 19 | 17     | $[1].scores[1] | $[1].scores |
| 2    | 93    | integer | 93    | 20 | 17     | $[1].scores[2] | $[1].scores |
| user | Jet   | text    | Jet   | 23 | 21     | $[2].user      | $[2]        |
| age  | 40    | integer | 40    | 25 | 21     | $[2].age       | $[2]        |
| 0    | 50    | integer | 50    | 28 | 27     | $[2].scores[0] | $[2].scores |
| 1    | 38    | integer | 38    | 29 | 27     | $[2].scores[1] | $[2].scores |
| 2    | 67    | integer | 67    | 30 | 27     | $[2].scores[2] | $[2].scores |
+------+-------+---------+-------+----+--------+----------------+-------------+

L'atom colonna è il valore SQL corrispondente agli elementi primitivi, elementi diversi dagli array e dagli oggetti JSON. Questa colonna è sempre null per un array o un oggetto JSON. Il value la colonna è la stessa di atom colonna per elementi JSON primitivi ma assume il valore JSON di testo per matrici e oggetti.

Un esempio di database

Supponiamo di avere la seguente tabella:

SELECT * FROM scores;

Risultato:

+---------+---------------------------------------------------------+
| teacher |                        students                         |
+---------+---------------------------------------------------------+
| Zohan   | [{"Amy":[10,8,9]},{"Josh":[3,2,4]},{"Igor":[7,6,5]}]    |
| Stacy   | [{"Pete":[5,3,1]},{"Liz":[5,8,7]},{"Jet":[9,5,7]}]      |
| Aisha   | [{"Zolton":[4,6,7]},{"Bree":[7,7,4]},{"Rohit":[9,8,8]}] |
+---------+---------------------------------------------------------+

Questa tabella ha chiamato scores ha due colonne. La prima colonna contiene il nome dell'insegnante e la seconda colonna contiene un documento JSON. Il documento JSON contiene gli studenti e i loro punteggi.

Ecco un esempio di esecuzione di una query che utilizza json_tree() contro questa tabella:

SELECT
    teacher,
    key AS student,
    value
FROM 
    scores, 
    json_tree(students, '$[1].Liz')
WHERE json_tree.key = 'Liz';

Risultato:

+---------+---------+---------+
| teacher | student |  value  |
+---------+---------+---------+
| Stacy   | Liz     | [5,8,7] |
+---------+---------+---------+

Qui abbiamo restituito tutti i punteggi di Liz e abbiamo anche restituito il suo insegnante.

La seguente query restituisce il suo secondo punteggio:

SELECT
    teacher,
    key AS student,
    value AS score
FROM 
    scores, 
    json_tree(students, '$[1].Liz')
WHERE json_tree.key = 1;

Risultato:

+---------+---------+-------+
| teacher | student | score |
+---------+---------+-------+
| Stacy   | 1       | 8     |
+---------+---------+-------+