I have a DB field called data of type is MEDIUMTEXT, which stores values in JSON format. I'm using extract_json_value method from common_schema.
When JSON is not nested, it works fine. For example, when applications_data table's data field is
{
"key": "value"
}
This query works fine:
SELECT data into #json from applications_data;
SELECT common_schema.extract_json_value(#json, 'key') as result;
and gives result: key
However, when the data field is a nested JSON, it fails. For example, JSON is:
{
"key": {
"overview": "sample"
}
}
Using the same query as above and result is empty, not NULL:
Remember:
extract_json_value
...
This function internally relies on json_to_xml(): it first
converts the JSON data to XML, then uses ExtractValue to apply
XPath.
...
and
ExtractValue(xml_frag, xpath_expr)
...
If no matching text node is found for the expression (including the
implicit /text())—for whatever reason, as long as xpath_expr is valid, and xml_frag consists of elements which are properly nested and closed—an empty string is returned. No distinction is made between a match on an empty element and no match at all. This is by design.
If you need to determine whether no matching element was found in
xml_frag or such an element was found but contained no child text
nodes, you should test the result of an expression that uses the XPath
count() function.
...
Test:
mysql> SET #`json` := '
'> {
'> "key": {
'> "overview": "sample"
'> }
'> }
'> ';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT
-> common_schema.extract_json_value(#`json`, 'key') AS result0,
-> common_schema.extract_json_value(#`json`, count('key')) AS result1,
-> common_schema.extract_json_value(#`json`, 'key/overview') AS result2,
-> common_schema.extract_json_value(#`json`, count('key/overview')) AS result3;
+---------+---------+---------+---------+
| result0 | result1 | result2 | result3 |
+---------+---------+---------+---------+
| | 1 | sample | 1 |
+---------+---------+---------+---------+
1 row in set (0.03 sec)
Related
I can't get the data from a nested json using json_table
My MariaDB server is 10.6.0
set #json='
{
"id":"9696e1ac-e173-4905-ac51-c47c0ef8c90b",
"username":"demo#demo.com",
"firstName":"DEMO",
"lastName":"DEMO",
"email":"demo#demo.com",
"isEnabled":true,
"attributes":{
"ASSOCIATED_COMPANY":"CLCORP001,CLCORP002,CLCORP003,CLCORP004,PECORP001,PECORP002,PECORP003,PECORP004,PECORP005,DECORP001",
"ROLES":"[\"Super Admin\",\"Admin\",\"Executive\"]",
},
}';
I tried this but it doesn't work
SELECT
*
FROM
SELECT * FROM json_table(#json, '$.*' COLUMNS(NESTED PATH '$.attributes.ROLES[*]' COLUMNS (roles varchar(250) PATH '$'))) roles
TEXT PATH '$'))) roles
No matter if MySQL or MariaDB: If your json string is not valid, json_object will always fail.
In both MySQL and MariaDB you can use json_valid() function to check your json:
set #json='
{
"id":"9696e1ac-e173-4905-ac51-c47c0ef8c90b",
"username":"demo#demo.com",
"firstName":"DEMO",
"lastName":"DEMO",
"email":"demo#demo.com",
"isEnabled":true,
"attributes":{
"ASSOCIATED_COMPANY":"CLCORP001,CLCORP002,CLCORP003,CLCORP004,PECORP001,PECORP002,PECORP003,PECORP004,PECORP005,DECORP001",
"ROLES":"[\"Super Admin\",\"Admin\",\"Executive\"]",
},
}';
SELECT JSON_VALID(#json);
+-------------------+
| JSON_VALID(#json) |
+-------------------+
| 0 |
+-------------------+
On success JSON_VALID will return 1.
I didn't check in detail, but looks like the extra quotation marks in attributes.ROLES are not allowed.
I need to count true and false words in a JSON datatype.
I have this JSON in the cell:
{"1": true, "2": false, "3": true}
The number of values may vary. I realize that I can count the total number of values in the array but how can I count true and false separately?
For total count I used JSON_LENGTH()
One option would be using below approach containing JSON_LENGTH(), JSON_EXTRACT() and JSON_SEARCH() functions together even for the version 5.7 (5.7.13+) where an array(js) extracted in the subquery and they're splitted to individual array for each values (true and false) by using JSON_SEARCH() function containing all as the second argument, and then counted by JSON_LENGTH() function :
SELECT ID,
JSON_LENGTH( JSON_SEARCH(js, 'all', 'true') ) AS Cnt_True,
JSON_LENGTH( JSON_SEARCH(js, 'all', 'false') ) AS Cnt_False
FROM ( SELECT *, JSON_EXTRACT(jsdata, '$.*') AS js
FROM tab ) t
provided JSON field has quoted values such as "true" and "false"
JSON_EXTRACT(jsdata, '$.*') still can be used in case that the boolean values are unquoted as in your case. But, this time some string operations would be needed. Here, I preferred using CHAR_LENGTH() function :
SELECT ID,
CHAR_LENGTH(js) - CHAR_LENGTH(REPLACE(js, 'true', SPACE(LENGTH('true')-1)))
AS Cnt_True,
CHAR_LENGTH(js) - CHAR_LENGTH(REPLACE(js, 'false', SPACE(LENGTH('false')-1)))
AS Cnt_False
FROM
( SELECT *, JSON_EXTRACT(jsdata, '$.*') AS js
FROM tab ) t
Demo
Here is one option using json_table(), availabe in MySQL 8.0.
You can first turn each json object to an array of values using path $.*'. Then, you can pass the resulting json array to json_table(), which will put each value on a separate row. The final step is conditional aggregation.
Assuming that the json column is called js, that would be:
select sum(x.val = 'true') cnt_true, sum(x.val = 'false') cnt_false
from mytable t
cross join json_table(js -> '$.*', '$[*]' columns (val varchar(5) path '$')) x
Demo on DB Fiddle
Sample data (I added another row to make this more meaningful):
| js |
| :--------------------------------- |
| {"1": true, "2": false, "3": true} |
| {"bar": false, "foo": true} |
Results:
cnt_true | cnt_false
-------: | --------:
3 | 2
I am using json_search to search the json formatted data from the column. For normal json data, it's working fine. But it's not working if string has a double quote.
MySQL Query
SELECT JSON_SEARCH(user_information, 'one', '%name%', null, '$[*].label');
It's working fine for regular json data but it's not working for below data which is stored in the single column database.
Data Example on which query is not working:
[{
"name":"John Smith",
"value":"John",
"label":"Sm"ith"
}]
Here is db-fiddle for this example.
As you can see in the data, for label key the string is sm"ith, I've just added one double quote middle of the string and then it's showing below error on db-fiddle.
Invalid JSON text in argument 1 to function json_search: "Missing a
comma or '}' after an object member."
But on my local host it's showing below error.
2014 - Commands out of sync; you can't run this command now
You must use the double backslash escape sequence, see Creating JSON Values.
mysql> SELECT JSON_VALID('
'> [
'> {
'> "name":"John Smith",
'> "value":"John",
'> "label":"Sm"ith"
'> }
'> ]
'> ') `is_json_valid?`;
+----------------+
| is_json_valid? |
+----------------+
| 0 |
+----------------+
1 row in set (0.00 sec)
mysql> SELECT JSON_VALID('
'> [
'> {
'> "name":"John Smith",
'> "value":"John",
'> "label":"Sm\\"ith"
'> }
'> ]
'> ') `is_json_valid?`;
+----------------+
| is_json_valid? |
+----------------+
| 1 |
+----------------+
1 row in set (0.00 sec)
I created a SQL Server Table with 25 columns. One of my columns is actually JSON text, stored as nvarchar(max).
Now I need to able to query this JSON column and parse out the various attributes. I have tried applying JSON_VALUE to my column but am doing something wrong; my query runs but returns NULL for all the values.
The JSON itself looks like:
[
{
"lineName":"GHjr",
"pipeDiameter":"12",
"pipeLength":"52000",
"pressure":"15",
"volume":"107"
},
{
"lineName":"Ks3R",
"pipeDiameter":"9",
"pipeLength":"40000",
"pressure":"15",
"volume":"80"
}
]
The SQL I am using is:
select
DOC_ID, LINE_SPECS,
JSON_VALUE(LINE_SPECS, '$.lineName') as line_name,
JSON_VALUE(LINE_SPECS, '$.pipe_Diameter') as diameter
from dbo.MY_TEST_DOCS
where ISJSON(LINE_SPECS) > 0
and len(LINE_SPECS) > 3
However, my 2 "parsed" columns are returning all NULL. How do I parse the five attributes from this column?
Without the [] ISJSON is returning false
With [] ISJSON retuns true
Without the [] JSON_VALUE returns NULLs
With [] JSON_VALUE returns values
dbfddle.uk has sql server 2016 available....
create table test (LINE_SPECS nvarchar(max));
insert into test values (N'
{
"lineName":"GHjr",
"pipeDiameter":"12",
"pipeLength":"52000",
"pressure":"15",
"volume":"107"
},
{
"lineName":"Ks3R",
"pipeDiameter":"9",
"pipeLength":"40000",
"pressure":"15",
"volume":"80"
}
');
select *
from test
where ISJSON(LINE_SPECS) > 0
;
GO
| LINE_SPECS |
| :--------- |
select
JSON_VALUE(LINE_SPECS, '$.lineName') as line_name
, JSON_VALUE(LINE_SPECS, '$.pipeDiameter') as diameter
from test
;
GO
line_name | diameter
:-------- | :-------
GHjr | 12
dbfiddle here
Having a problem with JSON / MEMSQL. Here's my table:
CREATE TABLE `MEMSQLPOLYGLOT` (
ID BIGINT AUTO_INCREMENT,
`DATA` JSON NULL,
PRIMARY KEY (ID)
);
Here's the record I'm trying to read:
insert into MEMTEST (DATA) values
('
{
"EnterpriseMessage" :
{
"Body" :
[
{
"AccountNumber":"ABCD",
"AdminCompany":null,
"BrokerNumber":"WWonka"
},
{
"AccountNumber":"CSNE",
"AdminCompany":null,
"BrokerNumber":"ZWiza"
}
],
"Header" :
{
"mimetye":"application/vnd.ms-powerpoint",
"destinationsystem":"ETL",
"requiresack":"FALSE",
"SimpArr":
[
"BYTS6181",
"EVU98124",
"Genesys"
],
"EmptyFile":1
}
}
}
');
I can read the SimpArr array in the header.
SELECT DATA::EnterpriseMessage::Header::SimpArr from MEMTEST;
Returns:
["BYTS6181","EVU98124","Genesys"]
I can also pass in a key index to get a specific value, such as:
select JSON_EXTRACT_JSON(DATA::EnterpriseMessage::Body, 1) from MEMTEST;
This returns the 2nd value of the SimpArr since it's a zero-based index.
I can also read the array of objects in the Body:
select JSON_EXTRACT_JSON(DATA::EnterpriseMessage::Body, 0) from MEMTEST;
which returns the first object in that array:
{
"AccountNumber":"ABCD",
"AdminCompany":null,
"BrokerNumber":"WWonka"
}
However, I am unable to find a way to read the individual attributes of this object.
Anyone have any ideas?
You can just pass the key as an extra argument to JSON_EXTRACT_JSON:
mysql> select JSON_EXTRACT_JSON(DATA::EnterpriseMessage::Body, 0, "AccountNumber") from MEMTEST;
+----------------------------------------------------------------------+
| JSON_EXTRACT_JSON(DATA::EnterpriseMessage::Body, 0, "AccountNumber") |
+----------------------------------------------------------------------+
| "ABCD" |
+----------------------------------------------------------------------+
1 row in set (0.08 sec)
JSON_EXTRACT_JSON takes any number of arguments, either string keys or integer array indices. For example, we can unroll the :: syntax in your example above:
select JSON_EXTRACT_JSON(DATA, "EnterpriseMessage", "Body", 0, "AccountNumber") from MEMTEST;
Also note that the return value has double quotes in it. That's because you extract JSON, and the JSON representation of a string has double quotes. If you actually want to get the string, use JSON_EXTRACT_STRING:
mysql> select JSON_EXTRACT_STRING(DATA, "EnterpriseMessage", "Body", 0, "AccountNumber") from MEMTEST;
+----------------------------------------------------------------------------+
| JSON_EXTRACT_STRING(DATA, "EnterpriseMessage", "Body", 0, "AccountNumber") |
+----------------------------------------------------------------------------+
| ABCD |
+----------------------------------------------------------------------------+
1 row in set (0.07 sec)