JSON_EXTRACT for a range of dates (MYSQL) - mysql

I read multiple times the MYSQL guide for JSON (https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-extract)
But I still don't find a way to query a range of dates.
I have the following stored JSON:
{"2014/12/10": [22.12323, 1212312.36], "2014/12/11": [24.983516, 59239590.36], "2014/12/15": [24.353891, 10350984.54], "2014/12/16": [24.756853, 51752318.09], "2014/12/17": [24.782038, 31848161.91]}
And the following query:
SELECT
JSON_EXTRACT(contenido, '$."2014/12/11"', '$."2014/12/16"') AS resultado
FROM
tabla_prueba;
I expect the result of:
[24.983516, 59239590.36], [24.353891, 10350984.54], [24.756853, 51752318.09]
But instead, I am getting only the two mentioned values:
[24.983516, 59239590.36], [24.756853, 51752318.09]
I also tried the key word to (for ranges) but with no results. What I am doing wrong?

Using JSON_TABLE
Try:
SET #json = '{
"2014/12/10": [
22.12323,
1212312.36
],
"2014/12/11": [
24.983516,
59239590.36
],
"2014/12/15": [
24.353891,
10350984.54
],
"2014/12/16": [
24.756853,
51752318.09
],
"2014/12/17": [
24.782038,
31848161.91
]
}';
SELECT a.dateStr, json_extract(#json, concat('$."', a.dateStr, '"')) as vals
FROM json_table(json_keys(#json), '$[*]' COLUMNS (dateStr CHAR(10) PATH '$')) a
WHERE a.dateStr BETWEEN '2014/12/11' AND '2014/12/16';
Result:
dateStr
vals
2014/12/11
[24.983516, 59239590.36]
2014/12/15
[24.353891, 10350984.54]
2014/12/16
[24.756853, 51752318.09]

Related

Read in nested JSON file in SQL Server

I am trying to read the following information taken from a nested json file in SQL Server:
Declare #json nvarchar(max)
SELECT #json =
N'{
"Energy":
{
"Energy-X/A": [
[
100.123456, null
],
[
101.123456, null
]
],
"Energy-X/B": [
[
102.123456, null
],
[
103.123456, null
]
]
}
}'
select
JSON_VALUE(a.value, '$.energy.Energy-X/A') as [Energy-X/A],
JSON_VALUE(b.value, '$.energy.Energy-X/B') as [Energy-X/B]
from OPENJSON(#json, '$.Energy') as a
CROSS APPLY OPENJSON(a.value, '$.energy') as b
The expected output should be that there are two columns with two entries for each row:
Energy-X/A
100.123456, null
101.123456, null
Energy-X/B
102.123456, null
103.123456, null
However, I am encountering two problems which I could not figure out:
If I execute the SQL statement nothing happens which indicates that I am obviously doing something wrong.
I have almost 1000 entries like "Energy-X/A", "Energy-X/B", "Energy-X/AC", etc.. Is there any better approach to extract the information without reusing the "JSON_VALUE()" function and introducing, e.g., b. value?
I am grateful for any help!
SQL Server won't return the data quite like you're expecting. json_value() is used to return scalar values such as strings, numbers and booleans, but when you want to return an array (or array of arrays) or objects you can use json_query() to return a snippet of the JSON data. For example:
select
json_query(Energy, '$."Energy-X/A"') as [Energy-X/A],
json_query(Energy, '$."Energy-X/B"') as [Energy-X/B]
from openjson (#json) with (
Energy nvarchar(max) as json
) as a;
Returns the output:
Energy-X/A Energy-X/B
------------------------ ----------------------------
[ [
[ [
100.123456, null 102.123456, null
], ],
[ [
101.123456, null 103.123456, null
] ]
] ]
The query could be simplified to the following, which yields the same result:
select
json_query(#json, '$.Energy."Energy-X/A"') as [Energy-X/A],
json_query(#json, '$.Energy."Energy-X/B"') as [Energy-X/B];
Edit...
If the JSON snippets of Energy-X/A and Energy-X/B are not sufficient for your purpose then you need to know their structure and parse them manually.
If they will consistently be 2 element arrays of 2 element arrays and you want to produce a row for each outer array that contains a comma-delimited list of the inner array's elements you can use a query such as the following (note: this requires SQL Server 2017 or later to make use of the string_agg() function):
select
commaDelimited.*
from openjson (#json) with (
energyXA nvarchar(max) '$.Energy."Energy-X/A"' as json,
energyXB nvarchar(max) '$.Energy."Energy-X/B"' as json
) as energy
cross apply (
select
(select string_agg(isnull(value, 'null'), ',') from openjson(energyXA, '$[0]')),
(select string_agg(isnull(value, 'null'), ',') from openjson(energyXB, '$[0]'))
union all
select
(select string_agg(isnull(value, 'null'), ',') from openjson(energyXA, '$[1]')),
(select string_agg(isnull(value, 'null'), ',') from openjson(energyXB, '$[1]'))
) commaDelimited ([Energy-X/A], [Energy-X/B]);
Which produces the results...
Energy-X/A
Energy-X/B
100.123456,null
102.123456,null
101.123456,null
103.123456,null

Complex JSON using JSON_MODIFY without nested arrays or escape characters (WITHOUT_ARRAY_WRAPPER)

I am using JSON_MODIFY to build complex JSON. Moving from MySQL I am struggling with the JSON functions provided by SQL Server. The issue I'm having is that SQL Server seems to construct all JSON objects in an array. There is the WITHOUT_ARRAY_WRAPPER mechanism, which seems like it should do what I want, however; there are two undesirable consequences.
It only returns one result depending on how it is used
The result is a single string with escape characters
I have constructed a simple query which illustrates my needs and the issue.
QUERY 1
SELECT JSON_MODIFY(
JSON_QUERY('{"definitions": {"id": "INT", "name": "VARCHAR(23)"}}'),
'append $.data',
(
SELECT * FROM (
SELECT 1 AS id, '123abc' AS "name" UNION
SELECT 2 AS id, '234bcd' AS "name"
) AS "data"
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
) AS "data";
OUTPUT 1
{
"definitions":{
"id":"INT",
"name":"VARCHAR(23)"
},
"data":[
"{\"id\":1,\"name\":\"123abc\"},{\"id\":2,\"name\":\"234bcd\"}"
]
}
QUERY 2
SELECT JSON_MODIFY(
JSON_QUERY('{"definitions": {"id": "INT", "name": "VARCHAR(23)"}}'),
'append $.data',
(
SELECT * FROM (
SELECT 1 AS id, '123abc' AS "name" UNION
SELECT 2 AS id, '234bcd' AS "name"
) AS "data"
FOR JSON PATH
)
) AS "data";
OUTPUT 2
{
"definitions":{
"id":"INT",
"name":"VARCHAR(23)"
},
"data":[
[
{"id":1, "name":"123abc"},
{"id":2, "name":"234bcd"}
]
]
}
QUERY 1
The data object is an array (which is expected), but the problem is what is in the array... A single string with escape characters.
QUERY 2
The data object is an array, which contains an array. In order to access the actual array of data, I would use something like for each obj in data[0].... The problem this poses is, for anyone consuming the JSON object, I would have to tell them:
"In this particular object the data element is an array of
arrays--You'll want to use the first and only the first
element to access the actual array of data."
I've naively tried many different combinations of JSON_MODIFY, JSON_QUERY, and CONCAT to no avail. How can I properly use JSON_MODIFY to get the following output, without the double array in data?
{
"definitions":{
"id":"INT",
"name":"VARCHAR(23)"
},
"data":[
{"id":1, "name":"123abc"},
{"id":2, "name":"234bcd"}
]
}
You are over-thinking this by trying to JSON_MODIFY an existing object.
Construct the definitions and data properties that you need, inside a subquery if necessary.
Then use FOR JSON a second time to get the outer object.
SELECT
definitions = JSON_QUERY('{"id": "INT", "name": "VARCHAR(23)"}'),
data =
(
SELECT id, name
FROM (VALUES
(1, '123abc'),
(2, '234bcd')
) v(id, name)
FOR JSON PATH
)
FOR JSON PATH;
SQL Fiddle
By trial and error, I found the solution.
Removed the append keyword from the path parameter in the JSON_MODIFY statement
Removed the WITHOUT_ARRAY_WRAPPER parameter from the FOR JSON statement.
Now the results are as expected and I don't need to explain to any consumers to "Just use data[0]"
The Query
SELECT JSON_MODIFY(
JSON_QUERY('{"definitions": {"id": "INT", "name": "VARCHAR(23)"}}'),
'$.data',
(
SELECT * FROM (
SELECT 1 AS id, '123abc' AS "name" UNION
SELECT 2 AS id, '234bcd' AS "name"
) AS "data"
FOR JSON PATH
)
) AS "data";
Produces the following output
{
"definitions":{
"id":"INT",
"name":"VARCHAR(23)"
},
"data":[
{"id":1, "name":"123abc"},
{"id":2, "name":"234bcd"}
]
}

Check if an element is contained in the values ​(array) of a json column in MySql

I have the following values ​​inside a cell of a json column in MySql:
{
"produttori": [
"8",
"9"
],
"articoli_alternativi": [
"3",
"9"
],
"articoli_accessori": [
"5",
"6",
"7",
"8"
],
"tecnologie": [],
"fornitori": [
"9",
"8"
],
"classificazioni": [
"3",
"4"
]
}
I would like to make a query that extracts data based on the existence of a value in the array at the fornitori key.
For now I've tried this:
query = 'SELECT nome, formulati_commerciali FROM articolo WHERE JSON_CONTAINS(JSON_EXTRACT(dati, "$.fornitori"), "' + \
value+'", "$")'
Which print is:
SELECT name, data FROM articolo WHERE JSON_CONTAINS(JSON_EXTRACT(data, "$.fornitori"), "8", "$")
Basically the condition is that value ("8") must be inside the fornitori list, otherwise skips the element.
Unfortunately, the query did not produce any results.
I would like to know how you can formulate such a query in MySql. I will need them often!
Thanks in advance!
This should do it:
SELECT name, data
FROM articolo
WHERE JSON_CONTAINS(data, '"8"', '$.fornitori')
The double quotes around 8 are important, in order to properly match the JSON data. On the other hand, the query consistently uses single quotes for string literals.
You can use
SELECT data
FROM
(
SELECT #i := #i + 1 AS rn,
JSON_UNQUOTE(JSON_EXTRACT(data,CONCAT('$.fornitori[',#i-1,']'))) AS elm,
data
FROM information_schema.tables
CROSS JOIN articolo
CROSS JOIN (SELECT #i := 0) r
) q
WHERE elm = 8
in order to search for the spesific value within a spesific
array("fornitori")
Demo

MySQL 8 search JSON key by value in array

I've got MySQL table with JSON field, where I store data in such a format.
{
"fields": {
"1": {
"s": "y"
},
"2": {
"s": "n"
}
}
}
I need to obtain the keys in fields, e.g. 1 or 2 given the value of s.
Example query:
create table mytable ( mycol json );
insert into mytable set mycol = '{"fields": {"1": {"s": "y"},"2": {"s": "n"}}}';
select j.* from mytable, JSON_TABLE(mycol,
'$.fields.*' COLUMNS (
json_key VARCHAR(10) PATH '$',
s VARCHAR(10) PATH '$.s'
)
) AS j where j.s = 'y';
gives:
# json_key, s
null, y
I would expect to get
# json_key, s
1, y
Is it possible to get that data somehow?
I don't need the results in row / table format. I would be happy to get the comma separated list of IDs (json_keys) meeting my criterium.
EDIT:
I was also thinking about getting the paths using JSON_SEARCH and passing that to JSON_EXTRACT, this was achieved here: Combining JSON_SEARCH and JSON_EXTRACT get me: "Invalid JSON path expression."
Unfortunately the difference is that I would need to use JSON_SEARCH in all mode, as I need all results. In such a mode JSON_SEARCH returns list of paths, where as JSON_EXTRACT accepts list of arguments.
Try FOR ORDINALITY (see 12.17.6 JSON Table Functions), this type enumerates rows in the COLUMNS clause:
SELECT
JSON_UNQUOTE(
JSON_EXTRACT(
JSON_KEYS(`mycol` ->> '$.fields'),
CONCAT('$[', `j`.`row` - 1, ']')
)
) `json_key`,
`j`.`s`
FROM
`mytable`,
JSON_TABLE(
`mycol`,
'$.fields.*' COLUMNS (
`row` FOR ORDINALITY,
`s` VARCHAR(10) PATH '$.s'
)
) `j`
WHERE
`j`.`s` = 'y';
See dbfiddle.

How select mysql with condition on nested array json?

i'm create a table have one json column and data of inserted has below structure:
{
"options" : {
"info" : [
{"data" : "data1", "verified" : 0},
{"data" : "data2", "verified" : 1},
... and more
],
"otherkeys" : "some data..."
}
}
i want to run a query to get data of verified = 1 "info"
this is for mysql 5.7 comunity running on windows 10
select id, (meta->"$.options.info[*].data") AS `data`
from tbl
WHERE meta->"$.options.info[*].verified" = 1
is expect the output of "data2" but the actual output is nothing.
below query worked perfectly
select id, (meta->"$.options.info[*].data") AS `data`
from tbl
WHERE meta->"$.options.info[1].verified" = 1
but i need to search all item in array not only index 1
how can fix it ?
(sorry for bad english)
Try:
SELECT `id`, (`meta` -> '$.options.info[*].data') `data`
FROM `tbl`
WHERE JSON_CONTAINS(`meta` -> '$.options.info[*].verified', '1');
See dbfiddle.