В SQLite, json_each()
е функция с таблична стойност, която обхожда стойността на JSON, предоставена като първи аргумент, и връща таблица, състояща се от един ред за всеки елемент на масива или член на обекта.
Ние предоставяме стойността на JSON като аргумент, когато извикаме функцията.
Можем по избор да предадем втори аргумент, който посочва път, от който да започнем. Когато направим това, json_each()
третира този път като елемент от най-високо ниво.
json_each()
функцията обхожда само непосредствените деца на масива или обекта от най-високо ниво или само на самия елемент от най-високо ниво, ако елементът от най-високо ниво е примитивна стойност. За да преминете рекурсивно през JSON подструктурата, използвайте json_tree()
вместо това.
Синтаксис
Можем да използваме функцията по следните начини:
json_each(X)
json_each(X,P)
Къде X
представлява JSON и P
е незадължителен аргумент, който представлява пътя, който да се третира като най-високо ниво.
Пример
Ето пример, за да демонстрирате как работи:
SELECT * FROM json_each('{ "name" : "Woof", "age" : 10 }');
Резултат:
+------+-------+---------+------+----+--------+---------+------+ | key | value | type | atom | id | parent | fullkey | path | +------+-------+---------+------+----+--------+---------+------+ | name | Woof | text | Woof | 2 | null | $.name | $ | | age | 10 | integer | 10 | 4 | null | $.age | $ | +------+-------+---------+------+----+--------+---------+------+
Можем да видим, че всеки член на обекта има свой собствен ред с полезна информация, като например неговия тип (SQL текстова стойност), път и т.н.
Относно id
колона, според документацията на SQLite това е вътрешен номер за домакинство, чието изчисляване може да се промени в бъдещи издания. Единствената гаранция е, че id
колоната ще бъде различна за всеки ред.
Родителската колона винаги е null
при извикване на json_each()
. Тази колона става по-смислена, когато използвате json_tree()
.
Масив
В този пример стойността на JSON е масив:
SELECT * FROM json_each('[ 10, 30, 45 ]');
Резултат:
+-----+-------+---------+------+----+--------+---------+------+ | 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] | $ | +-----+-------+---------+------+----+--------+---------+------+
Посочете път
Можем да използваме втори аргумент, за да посочим път, който да третираме като най-високо ниво.
Пример:
SELECT * FROM json_each('{ "a" : 1, "b" : [ 4, 7, 8 ] }', '$.b');
Резултат:
+-----+-------+---------+------+----+--------+---------+------+ | 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 | +-----+-------+---------+------+----+--------+---------+------+
По-голям документ
В този пример ще използваме по-голям JSON документ. Първо, нека извикаме json_each()
без посочване на път:
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 ]
}
]'
);
Резултат:
+-----+----------------------------------------------+--------+------+----+--------+---------+------+ | 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] | $ | +-----+----------------------------------------------+--------+------+----+--------+---------+------+
В този случай нашата JSON стойност е масив, който съдържа три обекта. Всеки обект е посочен в резултатите.
Сега нека извикаме json_each()
отново, но този път ще посочим път:
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]'
);
Резултат:
+--------+------------+---------+------+----+--------+-------------+------+ | 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] | +--------+------------+---------+------+----+--------+-------------+------+
В този случай избрах втория елемент от масива, като посочих [1]
(масивите са нулеви, базирани в SQLite).
Резултатът е, че изходът съдържа информация за втория елемент на масива.
Този път можем да видим, че path
колоната съдържа $[1]
.
Да отидем по-дълбоко:
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'
);
Резултат:
+-----+-------+---------+------+----+--------+----------------+-------------+ | 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 | +-----+-------+---------+------+----+--------+----------------+-------------+
Сега получаваме ред за всеки елемент в scores
масив.
Филтриране на заявката
Можем да модифицираме нашата заявка, за да филтрираме резултатите въз основа на даден критерий. Например:
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%';
Резултат:
+---------+----------------------------------------------+ | fullkey | value | +---------+----------------------------------------------+ | $[1] | {"user":"Faye","age":25,"scores":[90,87,93]} | +---------+----------------------------------------------+
Пример за база данни
Да предположим, че имаме следната таблица:
SELECT * FROM guests;
Резултат:
+-------+--------------------------------------------------+ | 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"] | +-------+--------------------------------------------------+
Тази таблица се нарича guests
има две колони. Първата колона съдържа името на госта, а втората колона съдържа тяхната поръчка за обяд. Могат да поръчат три ястия за обяд. Редът им за обяд е под формата на масив, където всяко ястие е елемент от масива.
Ето пример за изпълнение на заявка, която включва json_each()
срещу тази таблица:
SELECT DISTINCT
guest,
lunch
FROM
guests,
json_each(lunch)
WHERE json_each.value LIKE 'Apple Juice';
Резултат:
+-------+-------------------------------------------------+ | guest | lunch | +-------+-------------------------------------------------+ | Zohan | ["Beef Pie", "Fruit Salad", "Apple Juice"] | | Stacy | ["Chicken Curry", "Fruit Salad", "Apple Juice"] | | Aisha | ["Chicken Curry", "Apple Pie", "Apple Juice"] | +-------+-------------------------------------------------+
Тук върнахме всички гости, които поръчаха ябълков сок с обяда си, заедно с пълната си поръчка за обяд.
Ако искаме да върнем всички гости, които са поръчали ябълково „нещо“, можем да направим това:
SELECT DISTINCT
guest,
lunch
FROM
guests,
json_each(lunch)
WHERE json_each.value LIKE 'Apple%';
Резултат:
+-------+-------------------------------------------------+ | 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"] | +-------+-------------------------------------------------+
Забележете, че използвах DISTINCT
клауза в моето запитване. Това гарантира, че няма да получим връщане на няколко реда за един и същ гост. За да демонстрирам какво имам предвид, ето отново заявката, но без DISTINCT
клауза:
SELECT
guest,
lunch
FROM
guests,
json_each(lunch)
WHERE json_each.value LIKE 'Apple%';
Резултат:
+-------+-------------------------------------------------+ | 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"] | +-------+-------------------------------------------------+
Този път Айша се появява два пъти. Това е така, защото тя поръча две ястия с ябълки за обяд – ябълков пай и ябълков сок.