MySQL JSON: How to select MIN() value - mysql

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

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.

How to aggregate array values in JSONB?

I have the following PostgreSQL table:
CREATE TABLE orders
(
id uuid NOT NULL,
order_date timestamp without time zone,
data jsonb
);
Where data contains json documents like this:
{
"screws": [
{
"qty": 1000,
"value": "Wood screw"
},
{
"qty": 500,
"value": "Drywall screw"
},
{
"qty": 500,
"value": Concrete screw"
}
],
"nails": [
{
"qty": 1000,
"value": "Round Nails"
}
]
}
How do I can get an overall quantity for all types of screws across all orders? Something like this :)
select value, sum(qty) from orders where section = 'screws' group by value;
I am not quite sure why you are trying to sum up the qty values, because the GROUP BY value makes only sense if there would be several times the same value which can be summed, e.g. if you would have twice the value Wood screw.
Nevertheless, this would be the query:
step-by-step demo:db<>fiddle
SELECT
elems ->> 'value' AS value,
SUM((elems ->> 'qty')::int) AS qty
FROM
orders,
jsonb_array_elements(data -> 'screws') elems
GROUP BY 1
Expand the screw array into one row per array element by jsonb_array_elements()
Get the qty value by the ->> operator (which gives out a text type) and cast this into type int
If really necessary, aggregate these key/value pairs.

MySql: JSON column to rows

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