For example: create a JSON Array:
select JSON_ARRAY(JSON_OBJECT('check1', "false", 'check2', 'false'),
JSON_OBJECT('check2', "true", 'check3', 'true'),
JSON_OBJECT('check3', "false", 'check4', 'false')) as c1;
[{"check1": "false", "check2": "false"}, {"check2": "true", "check3": "true"}, {"check3": "false", "check4": "false"}]
The key is dynamic in each object. How to count how many value is false for each object once only?
I am using JSON_SEARCH(array, 'all', 'false'); It returns
["$[0].check1", "$[0].check2", "$[2].check3", "$[2].check4"]
I would like to get something like
[$[0], $[1]]
to get length is 2.
Thanks.
WITH
-- source data
cte1 AS ( SELECT JSON_ARRAY(JSON_OBJECT('check1', "false", 'check2', 'false'),
JSON_OBJECT('check2', "true", 'check3', 'true'),
JSON_OBJECT('check3', "false", 'check4', 'false')) c1),
-- search for specified value
cte2 AS ( SELECT JSON_SEARCH(c1, 'all', 'false') c1
FROM cte1 )
-- parse searching result, count distinct elements
SELECT COUNT(DISTINCT SUBSTRING_INDEX(value, '.', 1)) cnt
FROM cte2
CROSS JOIN JSON_TABLE(CAST(cte2.c1 AS JSON),
"$[*]" COLUMNS ( value VARCHAR(254) PATH "$" )) jsontable;
GROUP BY SUBSTRING_INDEX(value, '.', 1)
Related
I have a requirement to select column values in Oracle in a JSON structure. Let me explain the requirement in detail
We have a table called "dept" that has the following rows
There is another table called "emp" that has the following rows
The output we need is as follows
{"Data": [{
"dept": "Sports",
"City": "LA",
"employees": {
"profile":[
{"name": "Ben John", "salary": "15000"},
{"name": "Carlos Moya", "salary": "19000"}]
}},
{"dept": "Sales",
"City": "Miami",
"employees": {
"profile":[
{"name": "George Taylor", "salary": "9000"},
{"name": "Emma Thompson", "salary": "8500"}]
}}
]
}
The SQL that I issued is as follows
select json_object('dept' value b.deptname,
'city' value b.deptcity,
'employees' value json_object('employee name' value a.empname,
'employee salary' value a.salary)
format json) as JSONRETURN
from emp a, dept b where
a.deptno=b.deptno
However, the result looks like the following and not what we expected.
Please note the parent data is repeated. What is the mistake I am making?
Thanks for the help
Bala
You can do something like this. Note the multiple (nested) calls to json_object and json_arrayagg. Tested in Oracle 12.2; other versions may have other tools that can make the job easier.
select json_object(
'Data' value
json_arrayagg(
json_object (
'dept' value deptname,
'City' value deptcity,
'employees' value
json_object(
'profile' value
json_arrayagg(
json_object(
'name' value empname,
'salary' value salary
) order by empid -- or as needed
)
)
) order by deptno -- or as needed
)
) as jsonreturn
from dept join emp using (deptno)
group by deptno, deptname, deptcity
;
I have in mysql json field with the values:
{"a": true, "b":true, "c":false, "d":true}
I want to retrieve in SQL, for each row, only the keys and values that are true.
For example in the row:
{"a": true, "b":true, "c":false, "d":true}
the result will be:
{"a": true, "b":true, "d":true}
How can I do it?
Thank you!
Using string (regex) functions:
SELECT id,
val,
REGEXP_REPLACE(REGEXP_REPLACE(val, '(, *)?"[^"]+": *false', ''), '\\{ *, *', '\\{') without_false
FROM test
Using recursive CTE:
WITH RECURSIVE
cte AS ( SELECT id, val src, val FROM test
UNION ALL
SELECT id,
src,
JSON_REMOVE(val, JSON_UNQUOTE(JSON_SEARCH(REPLACE(val, 'false', '"false"'), 'one', 'false')))
FROM cte
WHERE JSON_SEARCH(REPLACE(val, 'false', '"false"'), 'one', 'false') IS NOT NULL
)
SELECT id, src val, val without_false
FROM cte
WHERE JSON_SEARCH(REPLACE(val, 'false', '"false"'), 'one', 'false') IS NULL
fiddle
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.
I'm using MySQL in a Node.JS API, so I need to get data from the database as JSON objects/arrays.
I'm trying to get a JSON Array nested within the result JSON as one of the values, so this is my current query:
SELECT
l.id AS id, l.description AS description, l.parent AS parent,
(
SELECT CONCAT(
'[',
GROUP_CONCAT(
JSON_OBJECT(
'id', a.id, 'description', a.description,
'ip', a.ip, 'lastmovementdetected', a.lastmovementdetected
)
),
']'
)
FROM airconditioners AS a WHERE location = l.id
) AS airconditioners
FROM locations as l`
However, this is the query result (actual output is an array of these JSON objects):
{
"id": 1,
"description": "Meu quarto",
"parent": 0,
"airconditioners": "[{\"id\": 1, \"ip\": \"192.168.137.96\", \"description\": \"Ar-condicionado\", \"lastmovementdetected\": null},{\"id\": 2, \"ip\": \"192.168.0.1\", \"description\": \"Ar-condicionado\", \"lastmovementdetected\": null},{\"id\": 3, \"ip\": \"192.168.0.1\", \"description\": \"Ar-condicionado\", \"lastmovementdetected\": null}]"
}
SQL is returning the JSON Array as a String and it's also escaping the double quotes from within the JSON.
This is the expected return:
"id": 1,
"description": "Meu quarto",
"parent": 0,
"airconditioners": [
{
"id":1,
"ip":"192.168.137.96",
"description":"Ar-condicionado",
"lastmovementdetected":null
},
{
"id":2,
"ip":"192.168.0.1",
"description":"Ar-condicionado",
"lastmovementdetected":null
},
{
"id":3,
"ip":"192.168.0.1",
"description":"Ar-condicionado",
"lastmovementdetected":null
}
]
Can this be done using a SQL query only? Or I'll have to treat the result before sending the response on the API?
I've tried surrounding the column with a CAST((SELECT...) AS JSON) AS airconditioners and also putting JSON_UNQUOTE() in many places, with no success whatsoever.
EDIT
I couldn't get to a conclusion whether MySQL is compatible with what I want or not. But, for instance, I'm using the following Javascript code to work around it:
Object.keys(result).forEach(key => {
let airconditioners = result[key].airconditioners;
if(airconditioners == null) {
// If the airconditioner field is null, then we replace it with an empty array
result[key].airconditioners = [];
} else {
result[key].airconditioners = JSON.parse(airconditioners);
}
});
use JSON_EXTRACT then get result as you expect
SELECT
l.id AS id, l.description AS description, l.parent AS parent,
(
SELECT JSON_EXTRACT( IFNULL(
CONCAT(
'[',
GROUP_CONCAT(
JSON_OBJECT(
'id', a.id, 'description', a.description,
'ip', a.ip, 'lastmovementdetected', a.lastmovementdetected
)
),
']'
)
,'[]'),'$')
FROM airconditioners AS a WHERE location = l.id
) AS airconditioners
FROM locations as l`
We recently upgraded our backend DB from SQL Server 2012 to SQL Server 2016 which I realized supports JSON objects. One of our web services return data in the below format, and I am trying to consume it directly using OPENJSON function.
{
"RESULT_1": {
"columns": ["col1", "col2", "col3", "col4"],
"data": [
["0", null, "12345", "other"],
["1", "a", "54321", "MA"],
["0", null, "76543", "RI"]
]
}
}
I want to make sure that I read the column names from the "columns section" and make sure that the correct data is read and pushed in SQL Server 2016.
DECLARE #Json_Array2 nvarchar(max) = '{
"RESULT_1": {
"columns": ["col1", "col2", "col3", "col4"],
"data": [
["0", null, "12345", "other"],
["1", "a", "54321", "MA"],
["0", null, "76543", "RI"]
]
} }';
SELECT [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.columns')
SELECT [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.data')
With above statements, I am able to extract the columns and the data array. Would it be possible to dump this data in a flat table (already existing) with the same column names?
I am able to see all the values of one particular row by:
SELECT [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.data[0]')
key value
0 0
1 NULL
2 12345
3 other
Any pointers are appreciated.
Thank you
If I understand correctly you are trying to extract all elements from the "data" array
Col1 Col2 Col3 Col4
0 NULL 12345 other
1 a 54321 MA
0 NULL 76543 RI
Suppose your Json Structure will not change you can achieve that using the following query:
SET NOCOUNT ON
IF OBJECT_ID ('tempdb..##ToPvt') IS NOT NULL DROP TABLE ##ToPvt
DECLARE #Cmd NVARCHAR(MAX)=''
DECLARE #Table TABLE (Col1 nvarchar(100), Col2 nvarchar(100), Col3 nvarchar(100) , Col4 nvarchar(100))
DECLARE #Json_Array2 nvarchar(max) = '{
"RESULT_1": {
"columns": ["col1", "col2", "col3", "col4"],
"data": [
["0", null, "12345", "other"],
["1", "a", "54321", "MA"],
["0", null, "76543", "RI"]
]
} }';
;WITH Cols ([Key], [Value]) as
(
SELECT [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.columns')
)
, [Rows] as
(
SELECT ROW_NUMBER () OVER (ORDER BY [Key]) Seq, [key], value
FROM OPENJSON(#Json_Array2,'$.RESULT_1.data')
)
,ToPvt as
(
SELECT c.[Key]+1 Cols, x.Value , 'col'+CONVERT(VARCHAR(10),ROW_NUMBER () OVER (PARTITION BY c.Value ORDER BY t.[Key])) Seq
FROM [Rows] t
INNER JOIN Cols C
ON t.[key] = c.[key]
CROSS APPLY OPENJSON(t.value) X
)
SELECT *
INTO ##ToPvt
FROM ToPvt
;WITH Final (Cmd) as
(
SELECT DISTINCT 'SELECT [col1], [col2], [col3],[col4] FROM ##ToPvt
PIVOT
(
MAX([Value]) FOR Seq IN ([col1], [col2], [col3],[col4])
) T
WHERE Cols = '+CONVERT(VARCHAR(10),Cols)+'
;'
FROM ##ToPvt
)
SELECT #Cmd += Cmd
FROM Final
INSERT INTO #Table
EXEC sp_executesql #Cmd
SELECT *
FROM #Table