MySql: JSON column to rows - mysql

I have a column in my table that is in json format. The json contains multiple records:
[{
"id": "1",
"name": "person 1"
}, {
"id": "2",
"name": "person 2"
}]
I want the result of my query to be like this:
id | name
1 person 1
2 person 2
How can I achieve this? I tried json_extract(json_column, '$[*].id') but it only returns all the id in an array format in one row

Related

mysql 5.7.12 json extract sum

I need the sum of the "total" value. But my query always returns 0
My json field:
{'damage_budget': [{"id": 1, "name": "test-one", "value": 131, "quantity": 1}, {"id": 10, "name": "test-two", "value": 460, "quantity": 1}]}
My query:
select id, sum(column ->>'$.damage_budget[*].value') from table
Your extract returns a JSON array, not a scalar.
mysql> set #j = '{"damage_budget": [{"id": 1, "name": "test-one", "value": 131, "quantity": 1}, {"id": 10, "name": "test-two", "value": 460, "quantity": 1}]}';
mysql> select json_unquote(json_extract(#j, '$.damage_budget[*].value')) as v;
+------------+
| v |
+------------+
| [131, 460] |
+------------+
The argument to SUM() must be a scalar.
There's no simple way to do a SUM() against a JSON array in MySQL 5.7. Solutions exist, but they involve coding complex procedures.
You should either upgrade to MySQL 8.0 so you can use JSON_TABLE() (for example see my answer to MySql join by json key and multiply quantity for each order item and get total price), or else store your data in normal rows and columns, not JSON.
In fact, there's no reason to store the data you show in JSON regardless of which version of MySQL you use. You should just store it in normal rows and columns.

psql equivalent of pandas .to_dict('index')

I want to return a psql table, but I want to return it in json format.
Let's say the table looks like this...
id
name
value
1
joe
6
2
bob
3
3
joey
2
But I want to return it as an object like this...
{
"1": {
"name": "joe",
"value": 6
},
"2": {
"name": "bob",
"value": 3
},
"3": {
"name": "joey",
"value": 2
}
}
So if I were doing this with pandas and the table existed as a dataframe, I could transform it like this...
df.set_index('id').to_dict('index')
But I want to be able to do this inside the psql code.
The closest I've gotten is by doing something like this
select
json_build_object (
id,
json_build_object (
'name', name,
'value', value
)
)
from my_table
But instead of aggregating this all into one object, the result is a bunch of separate objects separated by rows at the key level... that being said, it's kinda the same idea...
Any ideas?
You want jsonb_object_agg() to get this:
select jsonb_object_agg(id, jsonb_build_object('name', name, 'value', value))
from my_table
But this is not going to work well for any real-world sized tables. There is a limit of roughly 1GB for a single value. So this might fail with an out-of-memory error with larger tables (or values inside the columns)

SUM the current column for many rows, return only one

I have a problem with my query.
I tried different ways and searched a lot but I got no luck.
All I want is to SUM(), the column item_price WHERE order_id=2, and show its result along with its other rows.
I've 2 rows under order_id=2, so when I try the below query, I get only 1 row.
SELECT *, SUM(`item_price`) AS `item_total`
FROM `order_items`
WHERE `order_id` = '2'
Ouput
{
"id": "1",
"order_id": "2",
"item_name": "Loshan",
"item_price": "10.000",
"description": "Don Company Loshan was good",
"image": "Loshan-1612740664.png",
"status": "approved",
"updated_at": "2021-02-08 04:31:04",
"created_at": "2021-02-08 04:31:04",
"item_total": "20.000"
}
I tried to use GROUP BY `id`, So I get 2 rows but the result of item_total is not valid, it do not sum the whole column where order_id=2
I can handle it in PHP but I want it to do it with a SQL query.

MySQL JSON: How to select MIN() value

I have a MySQL table:
The combo column is a JSON datatype
id | combo
1 | {"qty": "2", "variations": [{"name": "Cover", "value": "Paperback"}], "price": "14.00"}
2 | {"qty": "1", "variations": [{"name": "Cover", "value": "Hardback"}], "price": "7.00"}
3 | {"qty": "1", "variations": [{"name": "Cover", "value": "Paperback"}], "price": "15.00"}
I'm trying to get the MIN() price of 7.00 but as they're strings, it returns 14.00.
Can this be done? Here's what I tried:
SELECT
JSON_UNQUOTE(MIN(combo->'$.price')) AS min_price
FROM itemListings
GROUP BY id
I also tried removing the quotes around the stored prices but it gave the same results.
Your code is giving you the lexicographical minimum; when sorting strings a "1" comes before a "7", despite the strings being "14.00" and "7:00", just like "apple" comes before "bat", despite "apple" being longer than "bat".
You want the numerical minimum, so cast the value to a decimal number:
SELECT
id, -- you probably want the select the grouped by value too
MIN(CAST(combo->'$.price' AS DECIMAL(10,2))) AS min_price
FROM itemListings
GROUP BY id

Retrieve first N records of a JSON array with a Postgresql query

PostgreSQL has some native JSON operations since verison 9.3. Suppose you have a table, my_table, with a json column, my_json_col, structured as follows:
[
{ "id": 1, "some_field": "blabla" },
{ "id": 2, "some_field": "foo" }
...
]
To retrieve the n-th element of my_json_col, you would execute something like: SELECT my_json_col->n FROM my_table WHERE .... So if n = 1, the query would return the "id": 2 record in my example.
I want to retrieve the first n elements, e.g. if n = 2 the query should return the first two records in my example. Is this possible?
In PostgreSQL 12, you can do:
SELECT jsonb_path_query_array('["a","b","c","d","e","f"]', '$[0 to 3]');
jsonb_path_query_array
------------------------
["a", "b", "c", "d"]
(1 row)
I think you need to convert the JSON array to a regular Postgres array, then take a slice of it:
select (array_agg(e))[2:3]
from (select json_array_elements('[{"id":1},{"id":2},{"id":3},{"id":4}]'::json)) x(e);
If you need the result to be JSON, you can use array_to_json:
select array_to_json((array_agg(e))[2:3])
from (select json_array_elements('[{"id":1},{"id":2},{"id":3},{"id":4}]'::json)) x(e);
For anyone who will stumble here trying the same thing. Here is what I faced
I had a similar problem, I needed the N result from jsonb field which was containing an array. The result I needed was all the fields of the table and N number of data from the data field where the condition satisfies.
After going through this again and again I found out that the accepted answer aggregates the rows. So if you have a table
id
type
data
status
1
employee
{{"age": 29, "name": "EMP 1"}, {"age": 30, "name": "EMP 2"},...}
Active
2
manager
{{"age": 28, "name": "MNG 1"}, {"age": 30, "name": "MNG 2"},...}
Active
and you run the query
select (array_agg(e))[2:3]
from (select json_array_elements(data::json) from <table>) x(e);
then the output will be
data
{{"age": 30, "name": "EMP 2"}, {"age": 28, "name": "MNG 1"}}
which was not needed in my case, What I needed was n data for each individual row where the condition satisfies e.g.
data
{{"age": 29, "name": "EMP 1"},{"age": 30, "name": "EMP 2"}}
{{"age": 28, "name": "MNG 1"},{"age": 30, "name": "MNG 2"}}
so after searching a little and going through the link provided by #Paul A Jungwirth
in the accepted answer. I found out that this can also be achieved by
select (ARRAY(select json_array_elements_text(data::json)))[0:2]
and the result will give you the n number of data from the jsonb field where the condition satisfies, you can also access other fields with it as well. Like let's say you want id and n number of data out of this table then you can do that just by adding id in the select query. (I was unable to get "id" in the query in the accepted answer)
select id, (ARRAY(select json_array_elements(data::json)))[0:2] from table where condition
will give output
id
data
1
{{"age": 29, "name": "EMP 1"},{"age": 30, "name": "EMP 2"}}
2
{{"age": 28, "name": "MNG 1"},{"age": 30, "name": "MNG 2"}}
Hope this will be helpful to someone.