MySQL join json - mysql

To avoid using temporary tables, I hoped to store some data as a json array within a variable and join on it. The data looks something like this:
[
{
"CarID": "9",
"Tank": "11.4",
"Distance": "120",
"From": "Brussels",
"To": "Bruges"
},
{
"CarID": "22",
"Tank": "15.9",
"Distance": "70",
"From": "Eupen",
"To": "Cologne"
}
]
I would like to set a variable in mysql to that value and be able to do something like the following:
SELECT
(
Cars.Consumption
* JSON_UNQUOTE(JSON_something('???','$.Distance'))
) - JSON_UNQUOTE(JSON_something('???','$.Tank')) AS neededRefuel
FROM Cars
WHERE JSON_SEARCH(
#myJson,
'one',
CAST(Cars.CarID AS JSON),
NULL,
'$[*].CarID'
) IS NOT NULL
This is just a simplified example.
Apparently json values as integer are not easy to detect in mysql, so I set quotes.
I wanted to use this kind of filter within a view, so temporary tables are not really an option.
Using MySQL 8.0.11

I just humbled upon JSON_TABLE and it seems to do exactly what I want :)

Related

Select rows with specific value in JSON column

I have a column in MySQL which has an array of JSON with multi objects, this is one of its values:
[
{
"date": "2014-01-17T00:00:00.000Z",
"price": "56.89845204047926330304107978008687496185302734375",
"total": "105774.2223432509504803533673",
"amount": 1859,
"symbol": "fb",
"transaction_code": "buy"
},
{
"date": "2015-04-20T00:00:00.000Z",
"price": "121.497274059658224132363102398812770843505859375",
"total": "962865.8969227914262489775865",
"amount": 7925,
"symbol": "aapl",
"transaction_code": "buy"
},
{
"date": "2013-11-06T00:00:00.000Z",
"price": "49.18047492858931235559794004075229167938232421875",
"total": "330738.6938947631255913961468",
"amount": 6725,
"symbol": "fb",
"transaction_code": "sell"
}
]
I want to extract objects with "transaction_code": "sell" and find the average price of them.
In MySQL 8.0, you can use the JSON_TABLE() function to transform the data so you can apply a WHERE clause to it.
SELECT AVG(j.price)
FROM mytable CROSS JOIN JSON_TABLE(mytable.example_json, '$[*]' COLUMNS(
date DATETIME PATH '$.date',
price DOUBLE PATH '$.price',
total DOUBLE PATH '$.total',
amount INT PATH '$.amount',
symbol VARCHAR(10) PATH '$.symbol',
transaction_code VARCHAR(10) PATH '$.transaction_code'
)
) AS j
WHERE j.transaction_code = 'sell';
This works all right, but it will be bound to have poor performance, and it's more work to write the code every time you want to do this.
In versions of MySQL before 8.0, you're out of luck. Fetch the whole JSON document into a client application, deserialize it into a data structure, and write custom code to loop over it.
It would be better to talk to whomever decided to use JSON to store this data, and convince them to use normal rows and columns. The queries will be easier, and you can create indexes to optimize them.
Also use the DECIMAL type for currency values, not DOUBLE. No one wants to make exact change for 56.89845204047926330304107978008687496185302734375!

Azure Insert multiple rows to table from the json

I want to automate the process of bulk inserting a json from API to SQL table. Json will look something like below with array.
[
{
"Id": "1",
"Name": "Orlando",
"Age": "23"
},
{
"Id": "2",
"Name": "Keith",
"Age": "24"
},
{
"Id": "3",
"Name": "Donna",
"Age": "23"
}
]
I will have same columns in table as well Id, Name and Age. I have many json array response from different APIs in this json format with different column names. So I am looking for more generic way of inserting the records to the tables since json node name and column in table are maintained same. I am planning to keep response type to table name mapping in some configurations, So deciding the table to which record need to be inserted is not the problem.
I just want a approach where I can insert a json to table without specifying all the column names etc. I saw few articles which suggests to use OPENJSON where I need specify the column names, If I follow this approach I will end up creating multiple stored procedures for each json to tables. So suggest me a good approach for handling the scenario using Azure logic apps or functions.
There is no silver bullet here. SQL Server is declarative by design and does not support macro substitution. This leaves Dynamic SQL.
Assuming you know the Destination Table and the Columns of the destination AND your JSON is rather simple:
Example or dbFiddle
Declare #JSON varchar(max) = '
[
{
"Id": "1",
"Name": "Orlando",
"Age": "23"
},
{
"Id": "2",
"Name": "Keith",
"Age": "24"
},
{
"Id": "3",
"Name": "Donna",
"Age": "23"
}
]
'
Declare #Dest varchar(max) = 'YourTable'
Declare #Cols varchar(max) = '[Id],[Name],[Age]'
Declare #SQL varchar(max) ='
Insert Into ' +#Dest+' (' +#Cols+ ')
Select '+#Cols+'
From (
Select RN = A.[Key]
,B.[key]
,B.[value]
From OpenJson('''+#JSON+''') A
Cross Apply OpenJson(A.Value) B
) src
Pivot (max(value) for [key] in ( '+#Cols+' ) ) pvt
'
Exec(#SQL)
Results

How to retrieve multiple data from jsonb column in postgres?

In PostgreSQL database I have a json column called json. Data inside look like below:
{
"Version": "0.0.0.1",
"Items": [
{
"Id": "40000000-0000-0000-0000-000000141146",
"Name": "apple",
"Score": 64,
"Value": 1430000
},
{
"Id": "40000000-0000-0000-0000-000000141147",
"Name": "grapefruit",
"Score": 58,
"Value": 1190000
},
{
"Id": "40000000-0000-0000-0000-000000141148",
"Name": "mango",
"Score": 41,
"Value": 170000
}
]
}
What I would like to do is retrieving all Score data from Items elements.
I was trying to use SQL code:
select
substring(json ->> 'Items' from '"Score": (\d*),') as score
from vegetables;
However that returns just the score from first element instead of 3. I was trying to use '\g' flag which supposed to find all results globally, but the code was not working.
Could anyone advise how to do that properly? Thanks in advance!
Considering that the data type of json field is jsonb then no need to use substring or regex, simply lateral join with jsonb_array_elements will do the required things for you. Try below query.
select x->>'Score' "Score" from vegetables
cross join lateral jsonb_array_elements(json->'Items') x
DEMO

Accessing an Array Inside JSON with a Postgres Query

I have a table with a data_type of json that I need to query one of the properties inside of it.
This is what the data in the column looks like:
{
"id": 7008,
"access_links": [
{
"product_code": "PRODUCT-1",
"link": "https://some.url"
},
{
"product_code": "PRODUCT-2",
"link": "https://someOther.url"
}
],
"library_id": "2d1203db-75b3-43a5-947c-8555b48371db"
}
I need to be able to pull out and filter by the product_code nested inside of the access_links.
I can get one layer deep by using this query:
SELECT
courses.course_metadata -> 'access_links' as access_links
FROM
courses
This seems to get me into the column, but I can't query any further.
The output I receive from the query looks like:
[{"product_code":"PRODUCT-1","link":"https://some.url"},{"product_code":"PRODUCT-2","link":"https://someOther.url"}]
I've tried using the ->> and #>> operators, but they both complain about the array not starting with a {. Also worth noting that the column is a data type of JSON not JSONB, so the #> operator doesn't work.
What am I missing here?
Does this help?
select
json_array_elements (x->'access_links')->'product_code' as product_code
from
(select '{
"id": 7008,
"access_links": [
{
"product_code": "PRODUCT-1",
"link": "https://some.url"
},
{
"product_code": "PRODUCT-2",
"link": "https://someOther.url"
}
],
"library_id": "2d1203db-75b3-43a5-947c-8555b48371db"
}'::json x
) as v
;
product_code
"PRODUCT-1"
"PRODUCT-2"

How to query JSON array in MYSQL with AND

If i have json like the following in a column in a mysql database
[
{
"name": "John",
"checked": true
},
{
"name": "Lucy",
"checked": false
}
]
how can I select in mysql all rows where in the same object name = 'John' and checked = true.
The json objects may have more keys and keys may not be in a specific order.
Just use JSON_CONTAINS:
SELECT * from `users`
WHERE JSON_CONTAINS(`data`, '{"name": "John","checked": true}');
You can try to match the string if the keys are always in the same order. Assuming your column is called people
SELECT
IF(people LIKE '%[
{
\"name\": \"John\",
\"checked\": true%', TRUE, FALSE) AS 'john_checked'
FROM table
WHERE (people LIKE '%[
{
\"name\": \"John\",
\"checked\": true%')
With the knowledge of this solution, you could create a shorter SQL such as the following. You may use this alone, or use it as a subquery within the where clause of a query that will return all the rows.
SELECT
IF(people LIKE '%\"checked\": true%', TRUE, FALSE) AS 'john_checked'
FROM table
WHERE (people LIKE '%\"name\": \"John\"%')
You can probably see in this that JSON is not ideal for storing in mySQL.
The better solution is to design your database as a relational one, i.e. have an additional table called people and a column(s) that link the data. Saying how to design this would require me to know much more about your data/subject, but you should learn about SQL "joins" and normalisation.
There are other questions that discuss JSON in mySQL, such as Storing JSON in database vs. having a new column for each key and Storing Data in MySQL as JSON
As of mySQL 5.7 there are some json related functions. See this wagon article, and the mySQL documentation.
Here is how it can be done in postgresql:
create table users (data jsonb);'
insert into users values ('[{"name": "John", "checked": "true"}, {"name": "Lucy", "checked": "false"}]'),('[{"name": "John", "checked": "false"}, {"name": "Lucy", "checked": "false"}]'),('[{"name": "John", "checked": "false"}, {"name": "Lucy", "checked": "true"}]');
select * from users, jsonb_array_elements(users.data) obj
where obj->>'name' = 'John' and obj->>'checked' = 'true';
data | value
-----------------------------------------------------------------------------+-------------------------------------
[{"name": "John", "checked": "true"}, {"name": "Lucy", "checked": "false"}] | {"name": "John", "checked": "true"}
(1 row)