looking for "Sum and combine" json columns - json

In PostgreSql I can't find in the docs a function that could allow me to combine n json entities, whilst summing the value part in case of existing key/value pair
English not being my main language, I suspect I don't know how to search with the right terms
In other words
from a table with 2 columns
name data
'didier' {'vinyl': 2, 'cd': 3)
'Anne' {'cd' : 1, 'tape' : 4}
'Pierre' {'cd' : 1, 'tape': 9, 'mp3':2}
I want to produce the following result :
{ 'vinyl' : 2, 'cd' : 5, 'tape':13, mp3 : 2}
With is a "combine and sum" function
Thanks in advance for any idea
Didier

Using the_table CTE for illustration, first 'normalize' data column then sum per item type (k) and finally aggregate into a JSONB object.
with the_table("name", data) as
(
values
('didier', '{"vinyl": 2, "cd": 3}'::jsonb),
('Anne', '{"cd" : 1, "tape" : 4}'),
('Pierre', '{"cd" : 1, "tape": 9, "mp3":2}')
)
select jsonb_object_agg(k, v) from
(
select lat.k, sum((lat.v)::integer) v
from the_table
cross join lateral jsonb_each(data) as lat(k, v)
group by lat.k
) t;
-- {"cd": 5, "mp3": 2, "tape": 13, "vinyl": 2}

Related

Count on CROSS APPLY with JSON Data

I have the following DB structure:
ID, Datetime, JsonData
Within JsonData there is a field called party which is "," delimited and another field called Source.
I'm trying to run a simple select where I get the data grouped by (Source, Time)...
Datetime, Source, SourceCount, CountParty
12/12/2021, 1, 4, 7
12/12/2021, 2, 3, 5
I'm trying to run the following SQL, however, I'm struggling to get CountParty. I always tend to get SourceCount. Can anyone please shed some light on what Im doing wrong?
I always end up with
12/12/2021, 1, 4, 4
12/12/2021, 2, 3, 3
Thanks
select
json_value(JsonData,'$.Info.source') as Source
, Party.value
,count(json_value(JsonData,'$.Info.Party'))
, count(*)
from test
CROSS APPLY
STRING_SPLIT(json_value(JsonData,'$.Info.Party'), ',') Party
group by json_value(JsonData,'$.Info.Source'), value
order by [Source]
{ "cID": "CID1","Info": {"Party": "A,B,C","Source" : "1"}}
{ "cID": "CID2","Info": {"Party": "A, C","Source" : "2" }}
{ "cID": "CID3","Info": {"Party": "B, C","Source" : "2" }}
{ "cID": "CID4","Info": {"Party": "B","Source" : "1" }}
{ "cID": "CID5","Info": {"Party": "C,A","Source" : "1" }}
{ "cID": "CID6","Info": {"Party": "A","Source" : "1" }}
{ "cID": "CID7","Info": {"Party": "C","Source" : "2" }}
select
json_value(JsonData,'$.Info.source') as Source
, Party.value
,count(json_value(JsonData,'$.Info.Party'))
, count(*)
from test
CROSS APPLY
STRING_SPLIT(json_value(JsonData,'$.Info.Party'), ',') Party
group by json_value(JsonData,'$.Info.Source'), value
order by [Source]
Your problem is that you because you are grouping by value as well, which refers to the value from STRING_SPLIT. So you get a new group for each individual split party value. You should remove that from the grouping. Instead, you can get the count of Party values in a subquery, then SUM that.
Note also, that count(json_value(JsonData,'$.Info.Party')) does not count distinct values, it counts how many non-null values there are, which probably wasn't your intention.
You can also use OPENJSON to pull out all the values at once, instead of using JSON_VALUE again and again.
SELECT
t.Datetime,
j.Source,
COUNT(*) SourceCount,
SUM(p.PartyCount) PartyCount
FROM test t
CROSS APPLY
OPENJSON(t.JsonData, '$.Info')
WITH (
Party nvarchar(500),
Source nvarchar(100)
) j
CROSS APPLY (
SELECT COUNT(*) PartyCount
FROM STRING_SPLIT(j.Party, ',')
) p
group by
t.Datetime,
j.Source
order by
j.Source;

MySQL JSON - group by JSON array index

I'm trying to count number of nested JSON array elements grouped by parent index using MySQL 8 JSON type field. My JSON string looks like
{
"a": [
{
"b": [
1,
2,
3
]
},
{
"b": [
1
]
}
]
}
I'm trying to get the count of elements under "b" key for each "a" element. I need an output similar to:
{0: 3, 1: 1}
Meaning that a[0] has 3 elements under "b", while a[1] has 1.
This query counts total number of "b" elements across all "a"s (yields 4):
select JSON_LENGTH(json->>'$.a[*].b[*]') from myTable
Is it possible to somehow group it by a's index?
Thank you!
One option is JSON_TABLE and JSON_OBJECTAGG:
SELECT
JSON_OBJECTAGG(
`rowid` - 1,
JSON_LENGTH(`count`)
)
FROM JSON_TABLE(
'{"a":[{"b":[1,2,3]},{"b":[1]}]}',
'$.a[*]'
COLUMNS(
`rowid` FOR ORDINALITY,
`count` JSON PATH '$.b'
)
) `der`;
See db-fiddle.

How to get rows from table as json array list format in mySQL

I want to select rows information from table in MySQL. Rather than getting as it is, I want to get this information as JSON array list type.
For example,
A B C
=========
1 2 3
2 3 4
I want it to become data like the followings.
{ rows: [
{ "A" : 1, "B" : 2, "C" : 3},
{ "A" : 2, "B" : 3, "C" : 4}
]}
In MySQL you can achieve as below:
SELECT CONCAT('{ rows:[', result, ']}') AS result1 FROM
(
SELECT GROUP_CONCAT('{', jsondata, '}' SEPARATOR ',') AS result FROM
(
SELECT
CONCAT
(
'"A":' , A , ','
'"B":', B, ','
'"C":' , C
) AS jsondata
FROM test
) AS jsondata
) AS jsonsdata1;
SQL Demo link: http://sqlfiddle.com/#!9/95bbbc/2

How to select data from jsonb column?

I have got one column with type jsonb. The data in this column looks as below
{
"random_number1":
{
"random_number2":
{
"Param1": 2,
"Param2": 0,
"Param3": 0,
"Param4": 6,
"Param5": 3
}
}
}
How to write select for this column if I want f.e. all rows where "Param3"=6 ?
I tried something like that
SELECT * FROM table WHERE column->'Param3' #> '6'::jsonb;
It depends on your expectations.
Get the value of a specified path:
select *
from my_table
where my_col->'random_number1'->'random_number2'->>'Param3' = '6'
Get the value of the key Param3 of any object on the third level:
select t.*
from my_table t,
jsonb_each(my_col) as value1(key1, value1),
jsonb_each(value1) as value2(key2, value2)
where jsonb_typeof(my_col) = 'object'
and jsonb_typeof(value1) = 'object'
and value2->>'Param3' = '6';
In the second case you may want to use distinct as the query may yield duplicated rows.

How to use to_jsonb as row_to_jsonb? Where the details about "how much"?

I was testing some queries at pg9.4 in "JSON mode", and now I am checking if pg9.5 will bring all same JSONB functionality... But there are no row_to_jsonb() function (!). (why it is not orthogonal instruction set in the basic parameters?)
The guide only says "the to_jsonb function supplies much the same functionality". Where we can check "how much"? There are other specific JSONB guide about this details?
((Year 2022 update and pg upgrade))
The phrase "supplies much the same functionality" was removed on the version 13. The current Guide does not use the phrase neither the word "much".
Now row_to_json is an alias for to_json except when the optional boolean parameter is true — the result will be the inclusion of line feeds like in jsonb_pretty().
Now the functions to_jsonb and to_json are orthogonal (!), and typical use is the same:
SELECT t.a, t.b, to_jsonb(r) json_info
-- or to_json(r)
FROM t, LATERAL (SELECT t.c,t.d,t.f) r;
-- or SELECT to_jsonb(r) FROM (SELECT c,d,f FROM t) r;
You can just use to_jsonb() instead of row_to_json(), example:
with the_table(a, b, c) as (
select 1, 'alfa', '2016-01-01'::date
)
select to_jsonb(t), row_to_json(t)
from the_table t;
to_jsonb | row_to_json
------------------------------------------+-------------------------------------
{"a": 1, "b": "alfa", "c": "2016-01-01"} | {"a":1,"b":"alfa","c":"2016-01-01"}
(1 row)
The first has a wider application than the other because of the type of arguments (anyelement versus record). For example, you can convert a Postgres array to json array using to_jsonb(), that cannot be done with row_to_json():
select to_jsonb(array['a', 'b', 'c']);
to_jsonb
-----------------
["a", "b", "c"]
(1 row)
In case of the use of two arguments in row_to_json() you should additionally use jsonb_pretty():
with the_table(a, b, c) as (
select 1, 'alfa', '2016-01-01'::date
)
select jsonb_pretty(to_jsonb(t)), row_to_json(t, true)
from the_table t;
jsonb_pretty | row_to_json
-----------------------+--------------------
{ +| {"a":1, +
"a": 1, +| "b":"alfa", +
"b": "alfa", +| "c":"2016-01-01"}
"c": "2016-01-01"+|
} |
(1 row)
You can use to_jsonb as a drop-in replacement for row_to_json.
SELECT to_jsonb(rows) FROM (SELECT * FROM table) rows;
you can cast json to jsonb row_to_json(...)::jsonb, not ideal but often does the trick