Mysql JSON EXTRACT don't work with large key - mysql

I'm trying to check if key-value exist in a JSON document in mysql. This is the query I use:
SELECT (JSON_EXTRACT(saved_stuff, '$.key') IS NOT NULL) FROM table
Now when the key is "test" it works great. It returns either 0 or 1, depending on whether the document exists. When the key is "34f8d790-6e25-4f31-ae8a-a17c04c96045" I get the error:
"Error: Query failed: ER_INVALID_JSON_PATH: Invalid JSON part expression. The error is around character position 38"
I'm thinking it has something to do with the length of the key, but I'm not sure. Please, any help is greatly appreciated.

See 11.5 The JSON Data Type :: Searching and Modifying JSON Values:
...
... The key name must be specified within double quotation marks
if the name without quotes is not legal within path expressions (for
example, if it contains a space).
...
Try:
SELECT
JSON_EXTRACT(
`saved_stuff`,
'$."34f8d790-6e25-4f31-ae8a-a17c04c96045"'
) IS NOT NULL
FROM
`table`;
See dbfiddle.

Related

Parse JSON into PL SQL with poor formatting

I am trying to parse JSON with poorly formatted code into sql table, however some of the values are creating problem.
Database is oracle 19.2
The json data is :
Insert into r_data (id,data)values
(1,'{'"View":"100",
"Assignment Title":"Collect all snippets from the Library",
"Status":"In Progress",
"Active/Not Active":"Depends"}');
I want the result as:
View Assignment_Title Status Active_Not_Active
100 Collect all snippets from Library In progress Depends
When i write the query,
select * from r_data x JSON_TABLE(x.data,'$',
COLUMNS (view NUMBER(10) PATH '$.view')
--for the first column view , it throws error of invalid identifier at the word view.
It only works fine for column Status as probably its single word and because view is keyword it is throwing problem. However i cannot change these names and want column View as View, Assignment Title as Assignment Title and Active/not Active as Active_not_Active.
How can this be done?
The main issue is that view is a reserved keyword, and therefore it can't be used as a column name (unless in double quotes - which is best avoided). You wanted to create a column named view from the data in your JSON - that's why you got the "invalid identifier" error.
But there are numerous other errors in your code; if you even made it as far as the "invalid identifier" error, that means that the code you posted is not the code you ran.
For example, even in the insert statement, you have an extra single-quote after the opening brace. That means that the opening brace is a string (one character) and the rest is who-knows-what. I had to remove that errant single-quote to make the insert work. How were you able to use that obviously syntactically incorrect statement?
In the select statement you are missing a comma after the alias x (before the keyword JSON_TABLE). No way you would get the "invalid identifier" error with that syntax error in the code.
In the JSON_TABLE function, there should be no comma between '$' and the COLUMNS clause. With that comma there, you would get a different error, not "invalid identifier" - so I don't believe that what you posted is your real code.
Etc. If all you got was an "invalid identifier" error, just choose a different name for the column (view won't work) and see what happens. Although... there is one more mistake, and it will result in an unexpected result. JSON is case sensitive. The attribute name in the JSON is View, with a capital V. So you must reference it as $.View in JSON_TABLE; you have $.view, which doesn't correspond to any attribute in your JSON, so you will get null for that column (if you don't change it to match capitalization from the JSON).
Here is the complete example, with all the errors corrected.
First, create the table. I do it all in one step:
create table r_data (id,data) as select 1,'{"View":"100",
"Assignment Title":"Collect all snippets from the Library",
"Status":"In Progress",
"Active/Not Active":"Depends"}' from dual;
Then, here is the query and its output. Notice the double-quotes around property names with embedded spaces (and forward slash, etc.).
select x.id,
j.view_, assignment_title, j.status, j.active_not_active
from r_data x,
json_table(x.data,'$'
columns (view_ number(10) path '$.View',
assignment_title varchar2(50) path '$."Assignment Title"',
status varchar2(20) path '$.Status',
active_not_active varchar2(20) path '$."Active/Not Active"'
)
) j
;
ID VIEW_ ASSIGNMENT_TITLE STATUS ACTIVE_NOT_ACTIVE
-- ----- ------------------------------------- ----------- ------------------
1 100 Collect all snippets from the Library In Progress Depends

Count data in mysql json by key

I work in mysql 8 and have a problem on counting data in json format field. This is my table:
I want to count data in absensi field where the key is "657" and the value is "0". So, by this table it must give me result 4.
I tried to use JSON_EXTRACT(absensi, '$.657') but always give me some error [42000][3143] Invalid JSON path expression. The error is around character position 6.
Can you help me how to solved this problem?
Thank's in advance...
Your key value is a string. Treat it as string instead of integer.
select json_extract(absensi, '$."657"')
If you are using your field as key value, you can build the parameter using concat() function.
select json_extract(absensi, concat('$."', fieldA, '"')) from test;
see dbfiddle.

How to extract values from a numeric-keyed nested JSON field in MySQL

I have a MySQL table with a JSON column called sent. The entries in the column have information like below:
{
"data": {
"12":"1920293"
}
}
I'm trying to use the mysql query:
select sent->"$.data.12" from mytable
but I get an exception:
Invalid JSON path expression. The error is around character position 9.
Any idea How I can extract the information? The query works fine for non-numeric subfields.
#Ibrahim,
You have an error in your code. If you use number (or spaced words) as key in a JSON data type in MySQL, you'll need to double-quote it.
Therefore, the correct MySQL statement in your case is:
select sent->'$.data."12"' FROM mytable;
Thanks,
#JeffreyKilelo

Getting the Primary key of the row which can not be parsed

I am trying to parse a json value from a column in Azure Sql Database with the following query
select Key, JSON_VALUE(JsonField, '$.Total')
from MyTable
However I am encountering some error in parsing that produces the following message
[12:37:32] Started executing query at Line 12
Msg 13609, Level 16, State 2, Line 1
JSON text is not properly formatted. Unexpected character '.' is found at position 0.
Is there any way to understand which rows have the following problem by, for example, having the column set to NULL by default in the return?
This way I can make a direct check on the resulting field.
You can use the T-SQL ISJSON function to identify problem values:
SELECT
Key
, JsonField
FROM dbo.MyTable
WHERE ISJSON(JsonField) = 0;

Handling Unicode sequences in postgresql

I have some JSON data stored in a JSON (not JSONB) column in my postgresql database (9.4.1). Some of these JSON structures contain unicode sequences in their attribute values. For example:
{"client_id": 1, "device_name": "FooBar\ufffd\u0000\ufffd\u000f\ufffd" }
When I try to query this JSON column (even if I'm not directly trying to access the device_name attribute), I get the following error:
ERROR: unsupported Unicode escape sequence
Detail: \u0000 cannot be converted to text.
You can recreate this error by executing the following command on a postgresql server:
select '{"client_id": 1, "device_name": "FooBar\ufffd\u0000\ufffd\u000f\ufffd" }'::json->>'client_id'
The error makes sense to me - there is simply no way to represent the unicode sequence NULL in a textual result.
Is there any way for me to query the same JSON data without having to perform "sanitation" on the incoming data? These JSON structures change regularly so scanning a specific attribute (device_name in this case) would not be a good solution since there could easily be other attributes that might hold similar data.
After some more investigations, it seems that this behavior is new for version 9.4.1 as mentioned in the changelog:
...Therefore \u0000 will now also be rejected in json values when conversion to de-escaped form is required. This change does not break the ability to store \u0000 in json columns so long as no processing is done on the values...
Was this really the intention? Is a downgrade to pre 9.4.1 a viable option here?
As a side note, this property is taken from the name of the client's mobile device - it's the user that entered this text into the device. How on earth did a user insert NULL and REPLACEMENT CHARACTER values?!
\u0000 is the one Unicode code point which is not valid in a string. I see no other way than to sanitize the string.
Since json is just a string in a specific format, you can use the standard string functions, without worrying about the JSON structure. A one-line sanitizer to remove the code point would be:
SELECT (regexp_replace(the_string::text, '\\u0000', '', 'g'))::json;
But you can also insert any character of your liking, which would be useful if the zero code point is used as some form of delimiter.
Note also the subtle difference between what is stored in the database and how it is presented to the user. You can store the code point in a JSON string, but you have to pre-process it to some other character before processing the value as a json data type.
The solution by Patrick didn't work out of the box for me. Regardless there was always an error thrown. I then researched a little more and was able to write a small custom function that fixed the issue for me.
First I could reproduce the error by writing:
select json '{ "a": "null \u0000 escape" }' ->> 'a' as fails
Then I added a custom function which I used in my query:
CREATE OR REPLACE FUNCTION null_if_invalid_string(json_input JSON, record_id UUID)
RETURNS JSON AS $$
DECLARE json_value JSON DEFAULT NULL;
BEGIN
BEGIN
json_value := json_input ->> 'location';
EXCEPTION WHEN OTHERS
THEN
RAISE NOTICE 'Invalid json value: "%". Returning NULL.', record_id;
RETURN NULL;
END;
RETURN json_input;
END;
$$ LANGUAGE plpgsql;
To call the function do this. You should not receive an error.
select null_if_invalid_string('{ "a": "null \u0000 escape" }', id) from my_table
Whereas this should return the json as expected:
select null_if_invalid_string('{ "a": "null" }', id) from my_table
You can fix all entries with SQL like this:
update ___MY_TABLE___
set settings = REPLACE(settings::text, '\u0000', '' )::json
where settings::text like '%\u0000%'
I found solution that works for me
SELECT (regexp_replace(the_string::text, '(?<!\\)\\u0000', '', 'g'))::json;
Note the match pattern '(?<!\)\u0000'.
Just for websearchers, who strand here:
This is not a solution to the exact question, but in some similar cases the solution, if you just don't want those datasets containing nullbytes in your json. Just add:
AND json NOT LIKE '%\u0000%'
in your WHERE statement.
You could also use the REPLACE SQL-syntax to sanitize the data:
REPLACE(source_field, '\u0000', '' );