In SQLite, json_tree()
ist eine Tabellenwertfunktion, die den als erstes Argument bereitgestellten JSON-Wert durchläuft und eine Tabelle zurückgibt, die aus einer Zeile für jedes Array-Element oder Objektmitglied besteht.
Wir geben den JSON-Wert als Argument an, wenn wir die Funktion aufrufen.
Wir können optional ein zweites Argument übergeben, das einen Startpfad angibt. Wenn wir dies tun, json_tree()
behandelt diesen Pfad als Element der obersten Ebene.
Der json_tree()
-Funktion geht rekursiv durch die JSON-Unterstruktur, beginnend mit dem Element der obersten Ebene. Um nur die unmittelbar untergeordneten Elemente des Arrays oder Objekts der obersten Ebene oder nur das Element der obersten Ebene selbst zu durchlaufen, wenn das Element der obersten Ebene ein primitiver Wert ist, verwenden Sie json_each()
stattdessen funktionieren.
Syntax
Wir können den json_tree()
verwenden funktionieren wie folgt:
json_tree(X)
json_tree(X,P)
Wobei X
steht für JSON und P
ist ein optionales Argument, das den Pfad darstellt, der als oberste Ebene behandelt werden soll.
Beispiel
Hier ist ein Beispiel, um zu demonstrieren, wie es funktioniert:
SELECT * FROM json_tree('{ "name" : "Woof", "age" : 10 }');
Ergebnis:
+------+--------------------------+---------+------+----+--------+---------+------+ | 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 | $ | +------+--------------------------+---------+------+----+--------+---------+------+
Wir können sehen, dass jedes Objektmitglied eine eigene Zeile mit einigen nützlichen Informationen hat, wie z. B. Typ (SQL-Textwert), Pfad usw.
Bezüglich der id
-Spalte, laut SQLite-Dokumentation ist dies eine interne Verwaltungsnummer, deren Berechnung sich in zukünftigen Versionen ändern könnte. Die einzige Garantie ist, dass die id
Spalte wird für jede Zeile anders sein.
Array
In diesem Beispiel ist der JSON-Wert ein Array:
SELECT * FROM json_tree('[ 10, 30, 45 ]');
Ergebnis:
+------+------------+---------+------+----+--------+---------+------+ | 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] | $ | +------+------------+---------+------+----+--------+---------+------+
Geben Sie einen Pfad an
Wir können ein zweites Argument verwenden, um einen Pfad anzugeben, der als oberste Ebene behandelt werden soll.
Beispiel:
SELECT * FROM json_tree('{ "a" : 1, "b" : [ 4, 7, 8 ] }', '$.b');
Ergebnis:
+-----+---------+---------+------+----+--------+---------+------+ | 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 | +-----+---------+---------+------+----+--------+---------+------+
Größeres Dokument
In diesem Beispiel verwenden wir ein größeres JSON-Dokument. Rufen wir zuerst json_tree()
auf ohne Pfadangabe:
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 ]
}
]'
);
Ergebnis:
+--------+--------------------------------------------------------------+---------+-------+------+--------+----------------+-------------+ | 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 diesem Fall ist unser JSON-Wert ein Array, das drei Objekte enthält. Jedes Objekt wird in den Ergebnissen aufgelistet, und alle Mitglieder dieser Objekte werden zusammen mit ihren jeweiligen Werten usw. aufgelistet.
Rufen wir nun json_tree()
auf wieder, aber diesmal geben wir einen Pfad an:
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]'
);
Ergebnis:
+--------+----------------------------------------------+---------+------+----+--------+----------------+-------------+ | 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 diesem Fall habe ich das zweite Array-Element ausgewählt, indem ich [1]
angegeben habe (Arrays sind in SQLite nullbasiert).
Das Ergebnis ist, dass der Baum nur auf das zweite Array-Element beschränkt ist.
Gehen wir tiefer:
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'
);
Ergebnis:
+--------+------------+---------+------+----+--------+----------------+-------------+ | 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 | +--------+------------+---------+------+----+--------+----------------+-------------+
Je tiefer wir gehen, desto weniger Zeilen werden zurückgegeben. Das liegt daran, dass wir nur einen Baum erhalten, der an dem bestimmten Pfad beginnt, den wir angegeben haben.
Filtern der Abfrage
Wir können unsere Abfrage ändern, um die Ergebnisse basierend auf einem bestimmten Kriterium zu filtern. Zum Beispiel:
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%';
Ergebnis:
+-----------+--------------------------------------------------------------+ | 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 | +-----------+--------------------------------------------------------------+
Wir können nur die letzte Zeile zurückgeben, indem wir Folgendes tun:
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';
Ergebnis:
+------+-------+------+------+----+--------+-----------+------+ | key | value | type | atom | id | parent | fullkey | path | +------+-------+------+------+----+--------+-----------+------+ | user | Faye | text | Faye | 13 | 11 | $[1].user | $[1] | +------+-------+------+------+----+--------+-----------+------+
Blattknoten zurückgeben
Wir können die Ergebnisse auf nur Blattknoten beschränken, wenn wir wollen. Mit „Blattknoten“ meine ich nur solche Schlüssel, die keine weiteren Kindelemente haben.
Es gibt ein paar Möglichkeiten, dies zu tun.
Eine Möglichkeit besteht darin, alle Objekte und Arrays herauszufiltern:
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');
Ergebnis:
+------+-------+---------+-------+----+--------+----------------+-------------+ | 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 | +------+-------+---------+-------+----+--------+----------------+-------------+
Eine andere Möglichkeit besteht darin, das atom
zu überprüfen Spalte für Nullwerte. Insbesondere würden wir nur Zeilen zurückgeben, in denen diese Spalte doesn't
ist einen Nullwert enthalten:
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;
Ergebnis:
+------+-------+---------+-------+----+--------+----------------+-------------+ | 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 | +------+-------+---------+-------+----+--------+----------------+-------------+
Das atom
Spalte ist der SQL-Wert, der primitiven Elementen entspricht – anderen Elementen als JSON-Arrays und -Objekten. Diese Spalte ist immer null
für ein JSON-Array oder -Objekt. Der value
Spalte ist dasselbe wie das atom
-Spalte für primitive JSON-Elemente, übernimmt aber den Text-JSON-Wert für Arrays und Objekte.
Ein Datenbankbeispiel
Angenommen, wir haben die folgende Tabelle:
SELECT * FROM scores;
Ergebnis:
+---------+---------------------------------------------------------+ | 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]}] | +---------+---------------------------------------------------------+
Diese Tabelle heißt scores
hat zwei Spalten. Die erste Spalte enthält den Namen des Lehrers und die zweite Spalte enthält ein JSON-Dokument. Das JSON-Dokument enthält Schüler und ihre Ergebnisse.
Hier ist ein Beispiel für die Ausführung einer Abfrage, die json_tree()
verwendet gegen diese Tabelle:
SELECT
teacher,
key AS student,
value
FROM
scores,
json_tree(students, '$[1].Liz')
WHERE json_tree.key = 'Liz';
Ergebnis:
+---------+---------+---------+ | teacher | student | value | +---------+---------+---------+ | Stacy | Liz | [5,8,7] | +---------+---------+---------+
Hier haben wir alle Partituren für Liz zurückgegeben, und wir haben auch ihren Lehrer zurückgegeben.
Die folgende Abfrage gibt ihre zweite Punktzahl zurück:
SELECT
teacher,
key AS student,
value AS score
FROM
scores,
json_tree(students, '$[1].Liz')
WHERE json_tree.key = 1;
Ergebnis:
+---------+---------+-------+ | teacher | student | score | +---------+---------+-------+ | Stacy | 1 | 8 | +---------+---------+-------+