sql >> Databasteknik >  >> RDS >> SQLite

SQLite JSON_TREE()

I SQLite, json_tree() är en tabellvärderad funktion som följer JSON-värdet som det första argumentet och returnerar en tabell som består av en rad för varje arrayelement eller objektmedlem.

Vi tillhandahåller JSON-värdet som ett argument när vi anropar funktionen.

Vi kan valfritt skicka ett andra argument, som anger en sökväg att börja från. När vi gör detta, json_tree() behandlar den banan som elementet på toppnivå.

json_tree() funktion går rekursivt genom JSON-understrukturen med början på toppnivåelementet. Använd json_each() för att bara gå de omedelbara underordnade av arrayen eller objektet på översta nivån, eller bara själva toppnivåelementet om elementet på översta nivån är ett primitivt värde funktion istället.

Syntax

Vi kan använda json_tree() fungerar på följande sätt:

json_tree(X)
json_tree(X,P)

Där X representerar JSON och P är ett valfritt argument som representerar sökvägen att behandla som den översta nivån.

Exempel

Här är ett exempel för att visa hur det fungerar:

SELECT * FROM json_tree('{ "name" : "Woof", "age" : 10 }');

Resultat:

+------+--------------------------+---------+------+----+--------+---------+------+
| 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   | $    |
+------+--------------------------+---------+------+----+--------+---------+------+

Vi kan se att varje objektmedlem har sin egen rad med lite användbar information, såsom dess typ (SQL-textvärde), sökväg, etc.

Angående id enligt SQLite-dokumentationen är detta ett internt hushållsnummer, vars beräkning kan ändras i framtida utgåvor. Den enda garantin är att id kolumnen kommer att vara olika för varje rad.

Array

I det här exemplet är JSON-värdet en array:

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

Resultat:

+------+------------+---------+------+----+--------+---------+------+
| 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]    | $    |
+------+------------+---------+------+----+--------+---------+------+

Ange en sökväg

Vi kan använda ett andra argument för att ange en sökväg som ska behandlas som den översta nivån.

Exempel:

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

Resultat:

+-----+---------+---------+------+----+--------+---------+------+
| 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  |
+-----+---------+---------+------+----+--------+---------+------+

Större dokument

I det här exemplet kommer vi att använda ett större JSON-dokument. Låt oss först anropa json_tree() utan att ange en sökväg:

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 ]
        }
        ]'
    );

Resultat:

+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+
|  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 |
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+

I det här fallet är vårt JSON-värde en array som innehåller tre objekt. Varje objekt listas i resultaten, och var och en av dessa objekts medlemmar listas, tillsammans med deras respektive värden, och så vidare.

Låt oss nu anropa json_tree() igen, men den här gången anger vi en sökväg:

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]'
    );

Resultat:

+--------+----------------------------------------------+---------+------+----+--------+----------------+-------------+
|  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 |
+--------+----------------------------------------------+---------+------+----+--------+----------------+-------------+

I det här fallet valde jag det andra matriselementet genom att ange [1] (matriser är nollbaserade i SQLite).

Resultatet är att trädet är begränsat till endast det andra arrayelementet.

Låt oss gå djupare:

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'
    );

Resultat:

+--------+------------+---------+------+----+--------+----------------+-------------+
|  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 |
+--------+------------+---------+------+----+--------+----------------+-------------+

Ju djupare vi går, desto färre rader returneras. Det beror på att vi bara får ett träd som börjar på den specifika sökvägen som vi angav.

Filtrera frågan

Vi kan modifiera vår fråga för att filtrera resultaten baserat på ett givet kriterium. Till exempel:

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%';

Resultat:

+-----------+--------------------------------------------------------------+
|  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                                                         |
+-----------+--------------------------------------------------------------+

Vi kan bara returnera den sista raden genom att göra så här:

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';

Resultat:

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

Returbladsnoder

Vi kan begränsa resultaten till bara lövnoder om vi vill. Med "bladnoder" menar jag bara de nycklar som inte har några ytterligare underordnade element.

Det finns ett par sätt att göra detta.

Ett alternativ är att filtrera bort alla objekt och arrayer:

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');

Resultat:

+------+-------+---------+-------+----+--------+----------------+-------------+
| 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 |
+------+-------+---------+-------+----+--------+----------------+-------------+

Ett annat sätt att göra det är att kontrollera atom kolumn för nollvärden. Specifikt skulle vi bara returnera rader där denna kolumn doesn't gör det innehålla ett nullvärde:

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;

Resultat:

+------+-------+---------+-------+----+--------+----------------+-------------+
| 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 |
+------+-------+---------+-------+----+--------+----------------+-------------+

atom kolumn är det SQL-värde som motsvarar primitiva element – ​​andra element än JSON-matriser och -objekt. Den här kolumnen är alltid null för en JSON-array eller ett objekt. value kolumnen är samma som atom kolumn för primitiva JSON-element men antar textens JSON-värde för arrayer och objekt.

Ett databasexempel

Anta att vi har följande tabell:

SELECT * FROM scores;

Resultat:

+---------+---------------------------------------------------------+
| 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]}] |
+---------+---------------------------------------------------------+

Den här tabellen kallas scores har två kolumner. Den första kolumnen innehåller namnet på läraren och den andra kolumnen innehåller ett JSON-dokument. JSON-dokumentet innehåller elever och deras poäng.

Här är ett exempel på att köra en fråga som använder json_tree() mot denna tabell:

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

Resultat:

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

Här returnerade vi alla poäng för Liz, och vi gav också tillbaka hennes lärare.

Följande fråga returnerar hennes andra poäng:

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

Resultat:

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

  1. Infoga JSON-data i SQLite-databasen i Android

  2. Exportera data från en MySQL-databas

  3. SQL Server - brist på NATURAL JOIN / x JOIN y USING(fält)

  4. MySQL hög CPU-användning