I have a table where one column is a json, like this:
{"type":"select","description":"Rota","default":"",
"required":"0","listOptions":[{"text": "1 - Jardins", "value": "1"}, {"text": "2 - Praia do Canto/Shop Vix", "value": "2"}, {"text": "3 - Hotéis Vitória/Serra", "value": "3"}, {"text": "6 - Hotéis Vila Velha/Padarias Praia da Costa", "value": "6"}, {"text": "9 - Cariacica", "value": "9"}, {"text": "5 - Vitória/Vila Velha", "value": "5"}, {"text": "10 - Baú/Reboque", "value": "10"}}
I can select like this: select atributos->"$.listOptions" from table
My question is, how can I select the values from listOptions?
Use [*] to extract all the array item values.
SELECT atributos->"$.listOptions[*].value" FROM test;
To extract a specify item use e.g first item value.
SELECT atributos->"$.listOptions[0].value" FROM test;
Refer to Runnable DBFiddle instance.
In mysql 8 you can use JSON_TABLE
CREATE tABLE TAB1 (atributos json);
INSERT INTO TAB1 VALUES ('{"type":"select","description":"Rota","default":"",
"required":"0","listOptions":[{"text": "1 - Jardins", "value": "1"}, {"text": "2 - Praia do Canto/Shop Vix", "value": "2"}, {"text": "3 - Hotéis Vitória/Serra", "value": "3"}, {"text": "6 - Hotéis Vila Velha/Padarias Praia da Costa", "value": "6"}, {"text": "9 - Cariacica", "value": "9"}, {"text": "5 - Vitória/Vila Velha", "value": "5"}, {"text": "10 - Baú/Reboque", "value": "10"}]}');
SELECT atributos->"$.description", tt1.*
FROM TAB1,
JSON_TABLE(
atributos,
"$.listOptions[*]"
COLUMNS (
mytext VARCHAR(100) PATH "$.text" DEFAULT '0' ON EMPTY DEFAULT '-99' ON ERROR,
myvalue INT PATH "$.value"
) ) tt1;
atributos->"$.description" | mytext | myvalue
:------------------------- | :--------------------------------------------- | ------:
"Rota" | 1 - Jardins | 1
"Rota" | 2 - Praia do Canto/Shop Vix | 2
"Rota" | 3 - Hotéis Vitória/Serra | 3
"Rota" | 6 - Hotéis Vila Velha/Padarias Praia da Costa | 6
"Rota" | 9 - Cariacica | 9
"Rota" | 5 - Vitória/Vila Velha | 5
"Rota" | 10 - Baú/Reboque | 10
db<>fiddle here
mysql Server (since Version 8.0):
SELECT [field with json blob]->>"$.json_field" FROM mytable;
mariaDB Server (since Version 10.26)
SELECT JSON_EXTRACT([field with json blob], "$.json_field") from mytable
Related
Basically I want to itrate JSON till its length from table but rest of values of remains same till current JSON ends.
My Table format is like this
id
line
txndate
metadata
docnumber
363
[{"Id": "0", "Amount": 135000.0, "DetailType": "JournalEntryLineDetail", "Description": "Paid Office Rent Of Office", "JournalEntryLineDetail": {"AccountRef": {"name": "Rent or lease payments", "value": "57"}, "PostingType": "Debit"}}, {"Id": "1", "Amount": 135000.0, "DetailType": "JournalEntryLineDetail", "Description": "Paid Office Rent Of Office", "JournalEntryLineDetail": {"AccountRef": {"name": "Cash and cash equivalents:Bank", "value": "83"}, "PostingType": "Credit"}}]
2021-08-16 00:00:00.000000 +00:00
{"CreateTime": "2021-08-20T05:39:38.000000Z", "LastUpdatedTime": "2021-08-20T05:39:38.000000Z"}
332
610
[{"Id": "0", "Amount": 4138088.25, "DetailType": "JournalEntryLineDetail", "Description": "Deposit in Bank", "JournalEntryLineDetail": {"AccountRef": {"name": "Cash and cash equivalents:Bank", "value": "83"}, "PostingType": "Debit"}}, {"Id": "1", "Amount": 4138088.25, "DetailType": "JournalEntryLineDetail", "Description": "Deposit in Bank", "JournalEntryLineDetail": {"AccountRef": {"name": "Share capital", "value": "8"}, "PostingType": "Credit"}}, {"Id": "2", "DetailType": "DescriptionOnly", "Description": "Deposit in Bank"}]
2021-10-11 00:00:00.000000 +00:00
{"CreateTime": "2021-10-13T10:44:09.000000Z", "LastUpdatedTime": "2021-10-13T10:44:09.000000Z"}
560
381
[{"Id": "0", "Amount": 30000.0, "DetailType": "JournalEntryLineDetail", "Description": "Paid to Punkish", "JournalEntryLineDetail": {"AccountRef": {"name": "Advance Against Salary", "value": "103"}, "PostingType": "Debit"}}, {"Id": "1", "Amount": 30000.0, "DetailType": "JournalEntryLineDetail", "Description": "Paid to Punkish", "JournalEntryLineDetail": {"AccountRef": {"name": "Cash and cash equivalents:Bank", "value": "83"}, "PostingType": "Credit"}}]
2021-07-01 00:00:00.000000 +00:00
{"CreateTime": "2021-08-23T05:31:42.000000Z", "LastUpdatedTime": "2021-08-23T05:47:03.000000Z"}
521
But I want to extract information like following table
id
line_id
Amount
Description
name
value
posting_type
txndate
CreatedTime
LastUpdatedTime
363
0
13500
Paid Office Rent Of Office
Rent or lease payments
57
Debit
2021-08-16 00:00:00.000000 +00:00
2021-08-20T05:39:38.000000Z
2021-08-20T05:39:38.000000Z
363
1
13500
Paid Office Rent Of Office
Cash and cash equivalents:Bank
83
Cebit
2021-08-16 00:00:00.000000 +00:00
2021-08-20T05:39:38.000000Z
2021-08-20T05:39:38.000000Z
610
0
4138088.25
Deposit in Bank
Cash and cash equivalents:Bank
83
Debit
2021-10-11 00:00:00.000000 +00:00
2021-10-13T10:44:09.000000Z
2021-10-13T10:44:09.000000Z
610
1
4138088.25
..........
..
...
...
2021-10-11 00:00:00.000000 +00:00
2021-10-13T10:44:09.000000Z
2021-10-13T10:44:09.000000Z
610
2
4138088.25
..........
..
...
...
2021-10-11 00:00:00.000000 +00:00
2021-10-13T10:44:09.000000Z
2021-10-13T10:44:09.000000Z
610
3
4138088.25
..........
..
...
...
2021-10-11 00:00:00.000000 +00:00
2021-10-13T10:44:09.000000Z
2021-10-13T10:44:09.000000Z
I want to convert JSON column enteries into rows but want preserve id, txndate, CreatedTime, and LastUpdatedTime same till the length of JSON column which is line in my case.
Please guide me with solution if possible.
Note: I am using Postgresql and datatype of line column is jsonb
Here you go, You can use jsonb_array_elements function to convert an array of JSON to row and then query on each row
Demo
select
t.id,
e.value ->> 'Id' as line_id,
e.value ->> 'Amount' as amount,
e.value ->> 'Description' as description,
e.value -> 'JournalEntryLineDetail' -> 'AccountRef' ->> 'name' as name,
e.value -> 'JournalEntryLineDetail' -> 'AccountRef' ->> 'value' as value,
e.value -> 'JournalEntryLineDetail' ->> 'PostingType' as posting_type,
t.txndate,
t.metadata ->> 'CreateTime' as CreatedTime,
t.metadata ->> 'LastUpdatedTime' as LastUpdatedTime
from
test t
cross join jsonb_array_elements(t.line) e
I have a table with the name mainapp_project_data which has a jsonb column project_user_data
TABLE
public | mainapp_project_data | table | admin
select project_user_data from mainapp_project_data;
project_user_data
-----------------------------------------------------------------------------------------------------------------
[{"name": "john", "age": "21", "gender": "M"}, {"name": "randy", "age": "23", "gender": "M"}]
[{"name": "donald", "age": "31", "gender": "M"}, {"name": "wick", "age": "32",
"gender": "M"}]
[{"name": "orton", "age": "18", "gender": "M"}, {"name": "russel", "age": "55",
"gender": "M"}]
[{"name": "angelina", "age": "open", "gender": "F"}, {"name": "josep", "age": "21",
"gender": "M"}]
(4 rows)
(END)
I would like to count the distinct values of keys gender and age of JSON.
output format : [{key:count(repeated_values)}]
filtering on `gender` : [{"M":7},{"F":1}]
filtering on `age` : [{"21":2},{"23":1},{"31":1}.....]
WITH flat AS (
SELECT
kv.key,
-- make into a JSON object with a single value and count, e.g., '{"M": 7}'
jsonb_build_object(kv.value, COUNT(*)) AS val_count
FROM mainapp_project_data AS mpd
-- Flatten the JSON arrays into single objects per row
CROSS JOIN LATERAL jsonb_array_elements(mpd.project_user_data) AS unarrayed(udata)
-- Convert to a long, flat list of key-value pairs
CROSS JOIN LATERAL jsonb_each_text(unarrayed.udata) AS kv(key, value)
GROUP BY kv.key, kv.value
)
SELECT
-- de-deplicated object keys
flat.key,
-- aggregation of all values and counts per key
jsonb_agg(flat.val_count) AS value_counts
FROM flat
GROUP BY flat.key
Returns
key | value_counts
--------+---------------------------------------------------------------------------------------------------------------------
gender | [{"M": 7}, {"F": 1}]
name | [{"josep": 1}, {"russel": 1}, {"orton": 1}, {"donald": 1}, {"wick": 1}, {"john": 1}, {"randy": 1}, {"angelina": 1}]
age | [{"18": 1}, {"32": 1}, {"21": 2}, {"23": 1}, {"open": 1}, {"31": 1}, {"55": 1}]
This will provide any key-value pair instance count. If you just want genders and ages, just add a where clause before the first GROUP BY clause.
WHERE kv.key IN ('gender', 'age')
Does something like this work for you?
postgres=# select count(*), (foo->'gender')::text as g from (select json_array_elements(project_user_data) as foo from mainapp_project_data) as j group by (foo->'gender')::text;
count | g
-------+-----
7 | "M"
1 | "F"
(2 rows)
postgres=# select count(*), (foo->'age')::text as g from (select json_array_elements(project_user_data) as foo from mainapp_project_data) as j group by (foo->'age')::text;
count | g
-------+--------
2 | "21"
1 | "32"
1 | "open"
1 | "23"
1 | "18"
1 | "55"
1 | "31"
(7 rows) ```
My table contains string in json format. I need to get the sum and average of each key.
+----+------------------------------------------------------------------------------------+------------+
| id | json_data | subject_id |
+----+------------------------------------------------------------------------------------+------------+
| 1 | {"id": "a", "value": "30"}, {"id": "b", "value": "20"}, {"id": "c", "value": "30"} | 1 |
+----+------------------------------------------------------------------------------------+------------+
| 2 | {"id": "a", "value": "40"}, {"id": "b", "value": "50"}, {"id": "c", "value": "60"} | 1 |
+----+------------------------------------------------------------------------------------+------------+
| 3 | {"id": "a", "value": "20"} | 1 |
+----+------------------------------------------------------------------------------------+------------+
Expected result is
{"id": "a", "sum": 90, "avg": 30},
{"id": "b", "sum": 70, "avg": 35},
{"id": "c", "sum": 120, "avg": 40}
I've tried
SELECT (
JSON_OBJECT('id', id, 'sum', sum_data, 'avg', avg_data)
) FROM (
SELECT
JSON_EXTRACT(json_data, "$.id") as id,
SUM(JSON_EXTRACT(json_data, "$.sum_data")) as sum_data,
AVG(JSON_EXTRACT(json_data, "$.avg_data")) as avg_data
FROM Details
GROUP BY JSON_EXTRACT(json_data, "$.id")
) as t
But no luck. How can I sort this out?
Input json needs to correct
create table json_sum (id int primary key auto_increment, json_data json);
insert into json_sum values (0,'[{"id": "a", "value": "30"}, {"id": "b", "value": "20"}, {"id": "c", "value": "30"}]');
insert into json_sum values (0,'[{"id": "a", "value": "40"}, {"id": "b", "value": "50"}, {"id": "c", "value": "60"}]');
insert into json_sum values (0,'[{"id": "a", "value": "20"}]');
select
json_object("id", jt.id, "sum", sum(jt.value), "avg", avg(jt.value))
from json_sum, json_table(json_data, "$[*]" columns (
row_id for ordinality,
id varchar(10) path "$.id",
value varchar(10) path "$.value")
) as jt
group by jt.id
Output:
json_object("id", jt.id, "sum", sum(jt.value), "avg", avg(jt.value))
{"id": "a", "avg": 30.0, "sum": 90.0}
{"id": "b", "avg": 35.0, "sum": 70.0}
{"id": "c", "avg": 45.0, "sum": 90.0}
A PostgreSQL instance stores data in JSONB format:
CREATE TABLE myschema.mytable (
id BIGSERIAL PRIMARY KEY,
data JSONB NOT NULL
)
The data array might contain objects like:
{
"observations": {
"temperature": {
"type": "float",
"unit": "C",
"value": "23.1"
},
"pressure": {
"type": "float",
"unit": "mbar",
"value": "1011.3"
}
}
}
A selected row should be returned as key-value pairs in a format like:
temperature,type,float,value,23.1,unit,C,pressure,type,float,value,1011.3,unit,mbar
The following query returns at least each object, while still JSON:
SELECT id, value FROM mytable JOIN jsonb_each_text(mytable.data->'observations') ON true;
1 | {"type": "float", "unit": "mbar", "value": 1140.5}
1 | {"type": "float", "unit": "C", "value": -0.9}
5 | {"type": "float", "unit": "mbar", "value": "1011.3"}
5 | {"type": "float", "unit": "C", "value": "23.1"}
But the results are splitted and not in text format.
How can I return key-value pairs of all objects in data?
This will flatten the json structure and effectively just concatenate the values, along with the top-level key names (e.g. temperature and pressure), for the expected "depth" level. See if this is what you had in mind.
SELECT
id,
(
SELECT STRING_AGG(conc, ',')
FROM (
SELECT CONCAT_WS(',', key, STRING_AGG(value, ',')) AS conc
FROM (
SELECT key, (jsonb_each_text(value)).value
FROM jsonb_each(data->'observations')
) AS x
GROUP BY key
) AS csv
) AS csv
FROM mytable
Result:
| id | csv |
| --- | --------------------------------------------------- |
| 1 | pressure,float,mbar,1011.3,temperature,float,C,23.1 |
| 2 | pressure,bigint,unk,455,temperature,int,F,45 |
https://www.db-fiddle.com/f/ada5mtMgYn5acshi3WLR7S/0
We have official documentation which unclear for me without examples.
I have JSON loke this structure, its a bit bigger but the same structure, more JSONs inside the array:
WITH
responses AS (
SELECT *
FROM (VALUES ((1,
'[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "5",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "yes",
"question": "quest",
"answer_id": 10094
}
]' :: JSON),
(2,
'[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "-1",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "no",
"question": "quest",
"answer_id": 10094
}
]' :: JSON))
) TEST(id,val)
)
SELECT * from responses
I could transform to flat structure:
id| question| answer
-----------
1, 'r1', 5
1, 'q6', yes
2, 'r1', -1
2, 'q6', no
But I need to get result in this way
id| r1| q6
----------
1, 5, yes
2, -1, no
How can I get result like last one?
There are some issues with your WITH query.
First, there is no need to do "select * from (values (..))" – VALUES is itself a query which you can use without SELECT:
test=# values (1, 'zz'), (2, 'bbb');
column1 | column2
---------+---------
1 | zz
2 | bbb
(2 rows)
Next, there is an issue with parentheses. Compare the previous query with this one:
test=# values ((1, 'zz'), (2, 'bbb'));
column1 | column2
---------+---------
(1,zz) | (2,bbb)
(1 row)
If you place additional parentheses like this, you got just one row of two columns, and values in these columns being of "anonymous" record type (its Postgres type magic, very powerful, but it's different story, not needed here).
So let's fix the first part of your CTE:
with responses(id, val) AS (
values
(1, '
[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "5",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "yes",
"question": "quest",
"answer_id": 10094
}
]'::json
), (2, '
[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "-1",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "no",
"question": "quest",
"answer_id": 10094
}
]'::json
)
)
select * from responses;
Now we can use json_array_elements(..) function to extract JSON elements from the JSON arrays:
with responses(id, val) AS (
values
...
)
select id, json_array_elements(val)
from responses;
Let's use it to construct the "second stage" of our CTE:
...
), extra(id, elem) as (
select id, json_array_elements(val)
from responses
)
...
And finally, we'll get the needed result like this:
...
select
id,
elem->>'id' as json_id,
elem->>'alias' as alias,
elem->>'question' as question,
elem->>'answer' as answer
from extra;
Entire query:
with responses(id, val) AS (
values
(1, '
[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "5",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "yes",
"question": "quest",
"answer_id": 10094
}
]'::json
), (2, '
[
{
"id": "13",
"alias": "r1",
"title": "quest",
"answer": "-1",
"question": "qq",
"answer_id": 10048
},
{
"id": "24",
"alias": "q6",
"title": "quest",
"answer": "no",
"question": "quest",
"answer_id": 10094
}
]'::json
)
), extra(id, elem) as (
select id, json_array_elements(val)
from responses
)
select
id as row_id,
elem->>'id' as json_id,
elem->>'alias' as alias,
elem->>'question' as question,
elem->>'answer' as answer
from extra;
Result:
row_id | id | alias | question | answer
--------+----+-------+----------+--------
1 | 13 | r1 | qq | 5
1 | 24 | q6 | quest | yes
2 | 13 | r1 | qq | -1
2 | 24 | q6 | quest | no
(4 rows)
This is a bit different from what you wanted. What you wanted cannot be achieved with pure SQL since you want to have dynamic column names in the output -- those "r1" and "q6" must be extracted from JSON data dynamically. It's possible with plpgsql though, or with tablefunc extension to create a pivoted table, let me know if you need it.