Mysql JSON_EXTRACT with double quotes in path not working - mysql

I have the following table def:
`CREATE TABLE `TestInfo` (
`Info` json DEFAULT NULL
) ;
`
Am inserting two rows with json values.
INSERT INTO `TestInfo` (`Info`)
VALUES
('{
"statusCode": 200,
"result": {
"summary": {
"area": 0.0009904206008286565
}
}
} '
);
INSERT INTO `TestInfo` (`Info`)
VALUES
(
'{
"statusCode": 200,
"result": {
"summary": {
"area": 0.0009904206008286565,
"realty-society": {
"price-min": {
"property": "price-min",
"min": 110000.00000000001,
"max": 150000000,
"average": 31184468.085106384,
"sum": 1465670000
}
}
}
}
} '
);
When I run the query:
SELECT JSON_EXTRACT(Info, '$.result.summary')
FROM TestInfo ;
it returns the 2 rows. This is fine.
But when I run the same query with double quotes around the path like this:
SELECT JSON_EXTRACT(Info, '$."result.summary"')
FROM TestInfo;
it returns the 2 rows (with the single column) as NULLs.
Ultimately I need to use double quotes for keys that have a hyphen (dash) in them.
I am using MySQL 5.7 on AWS.
Pl help.

Don't put double quotes around the whole path, just around a specific property name that contains special characters, e.g.
SELECT JSON_EXTRACT(Info, '$.result.summary."realty-society"."price-min"')
FROM TestInfo
Yuor code makes . part of the literal property name, rather than a separator between properties. You would use it if you had:
"result.summary": ...
in the object.

This should be works if MYSQL version>=5.7
SELECT Info->>"$.result.summary"
FROM TestInfo ;

Related

Oracle json_transform replace particular value on any level

I need to replace some values in Oracle 19 column that is CLOB with JSON constraint, but cannot find a right way to do it. Json can be big and I suppose regex function on string may not work due to the length restrictions.
My json may have 'locationId' property at any level with some values. Let's say I have bad value 000 and want to replace it with 111, so everywhere where is "locationId":"000" it becomes "locationId":"111".
I'm trying to use next json_transform command:
SELECT json_transform('
{
"a": {
"locationId":"000"
},
"b": {
"locationId":"111",
"x": {
"locationId":"000"
}
}
}', REPLACE '$..locationId?(# == "000")' = '111' IGNORE ON MISSING)
FROM dual
But it returns unchanged json, when next query for the same json fetches values to replace properly :
SELECT json_query('
{
"a": {
"locationId":"000"
},
"b": {
"locationId":"111",
"x": {
"locationId":"000"
}
}
}', '$..locationId?(# == "000")' WITH WRAPPER)
FROM dual
Result:
["000","000"]
There is no any documentation or examples how to use filters within json_transform, so I'm not sure it's even possible.
Maybe anybody know how to do it? Doesn't matter with json functions or not.
Links I use:
Oracle Json Path Expressions
Oracle json_query
Oracle json_transform
Have you seen that even
REPLACE '$..locationId' = '111' IGNORE ON MISSING
doesn't change anything ?
(at least in Cloud 21c)
It's more complicated:
SELECT json_transform('
{
"locationId" : "000",
"a": {
"locationId":"000"
},
"b": {
"locationId":"000",
"x": {
"locationId":"000",
"y": {
"locationId":"000"
}
}
}
}'
, REPLACE '$.locationId?(# == "000")' = '111' IGNORE ON MISSING
, REPLACE '$.*.locationId?(# == "000")' = '111' IGNORE ON MISSING
, REPLACE '$.*.*.locationId?(# == "000")' = '111' IGNORE ON MISSING
, REPLACE '$.*.*.*.locationId?(# == "000")' = '111' IGNORE ON MISSING
)
FROM dual;
Gives:
{"locationId":"111","a":{"locationId":"111"},"b":{"locationId":"111","x":{"locationId":"111","y":{"locationId":"111"}}}}

Is there a function in MYSQL like JSON_ARRAY_APPEND but for multiple vaues to be appended?

I'm wanting to add multiple values in JSON_ARRAY_APPEND.
For example in the following query:
SET #data = '{
"Person": {
"Name": "Homer",
"Hobbies": ["Eating", "Sleeping"]
}
}';
SELECT JSON_ARRAY_APPEND(#data, '$.Person.Hobbies', "Base Jumping") AS 'Result';
Our result would be:
{"Person": {"Name": "Homer", "Hobbies": ["Eating", "Sleeping", "Base Jumping"]}}
I'd like to be able to add multiple hobbies in one line rather than a dozen, using something like
SET #data = '{
"Person": {
"Name": "Homer",
"Hobbies": ["Eating", "Sleeping"]
}
}';
SELECT JSON_ARRAY_APPEND(#data, '$.Person.Hobbies', '"Base Jumping","Skiing"') AS 'Result';
Which results in
{"Person": {"Name": "Homer", "Hobbies": ["Eating", "Sleeping", "\"Base Jumping\",\"Skiing\""]}}
That's almost what I want but has extra characters that aren't wanted. Is there a better way to go about this?
JSON_ARRAY_APPEND() allows you to specify multiple path and value arguments. You can repeat the same path, and it will append to the result of the preceding append.
SELECT JSON_ARRAY_APPEND(#data,
'$.Person.Hobbies', "Base Jumping",
'$.Person.Hobbies', "Skiing") AS Result;
This is mentioned in the documentation:
The path-value pairs are evaluated left to right. The document produced by evaluating one pair becomes the new value against which the next pair is evaluated.
You can also use JSON_MERGE_PRESERVE() to concatenate arrays:
SELECT JSON_MERGE_PRESERVE(#data, '$.Person.Hobbies', '["Base Jumping", "Skiing"]') AS Result;

How can I use the oracle REGEXP_SUBSTR to extract specific json values?

I have some columns in my Oracle database that contains json and to extract it's data in a query, I use REGEXP_SUBSTR.
In the following example, value is a column in the table DOSSIER that contains json. The regex extract the value of the property client.reference in that json
SELECT REGEXP_SUBSTR(value, '"client"(.*?)"reference":"([^"]+)"', 1, 1, NULL, 2) FROM DOSSIER;
So if the json looks like this :
[...],
"client": {
"someproperty":"123",
"someobject": {
[...]
},
"reference":"ABCD",
"someotherproperty":"456"
},
[...]
The SQL query will return ABDC.
My problem is that some json have multiple instance of "client", for example :
[...],
"contract": {
"client":"Name of the client",
"supplier": {
"reference":"EFGH"
}
},
[...],
"client": {
"someproperty":"123",
"someobject": {
[...]
},
"reference":"ABCD",
"someotherproperty":"456"
},
[...]
You get the issue, now the SQL query will return EFGH, which is the supplier's reference.
How can I make sure that "reference" is contained in a json object "client" ?
EDIT : I'm on Oracle 11g so I can't use the JSON API and I would like to avoid using third-party package
Assuming you are using Oracle 12c or later then you should NOT use regular expressions and should use Oracle's JSON functions.
If you have the table and data:
CREATE TABLE table_name ( value CLOB CHECK ( value IS JSON ) );
INSERT INTO table_name (
value
) VALUES (
'{
"contract": {
"client":"Name of the client",
"supplier": {
"reference":"EFGH"
}
},
"client": {
"someproperty":"123",
"someobject": {},
"reference":"ABCD",
"someotherproperty":"456"
}
}'
);
Then you can use the query:
SELECT JSON_VALUE( value, '$.client.reference' ) AS reference
FROM table_name;
Which outputs:
REFERENCE
ABCD
db<>fiddle here
If you are using Oracle 11 or earlier then you could use the third-party PLJSON package to parse JSON in PL/SQL. For example, this question.
Or enable Java within the database and then use CREATE JAVA (or the loadjava utility) to add a Java class that can parse JSON to the database and then wrap it in an Oracle function and use that.
I faced similar issue recently. If "reference" is a property that is only present inside "client" object, this will solve:
SELECT reference FROM (
SELECT DISTINCT
REGEXP_SUBSTR(
DBMS_LOB.SUBSTR(
value,
4000
),
'"reference":"(.+?)"',
1, 1, 'c', 1) reference
FROM DOSSIER
) WHERE reference IS NOT null;
You can also try to adapt the regex to your need.
Edit:
In my case, column type is CLOB and that's why I use DBMS_LOB.SUBSTR function there. You can remove this function and pass column directly in REGEXP_SUBSTR.

How to query JSON values from a column into one JSON array in MS-SQL 2016?

I'm starting to fiddle out how to handle JSON in MSSQL 2016+
I simply created a table having a ID (int) and a JSON (nvarchar) column.
Here are my queries to show the issue:
First query just returns the relational table result, nice and as expected.
SELECT * FROM WS_Test
-- Results:
1 { "name": "thomas" }
2 { "name": "peter" }
Second query returns just the json column as "JSON" created my MSSQL.
Not nice, because it outputs the json column content as string and not as parsed JSON.
SELECT json FROM WS_Test FOR JSON PATH
-- Results:
[{"json":"{ \"name\": \"thomas\" }"},{"json":"{ \"name\": \"peter\" }"}]
Third query gives me two result rows with json column content as parsed JSON, good.
SELECT JSON_QUERY(json, '$') as json FROM WS_Test
-- Results:
{ "name": "thomas" }
{ "name": "peter" }
Fourth query gives me the json column contents as ONE (!) JSON object, perfectly parsed.
SELECT JSON_QUERY(json, '$') as json FROM WS_Test FOR JSON PATH
-- Results:
[{"json":{ "name": "thomas" }},{"json":{ "name": "peter" }}]
BUT:
I don't want to have the "json" property containing the json column content in each array object of example four. I just want ONE array containing the column contents, not less, not more. Like this:
[
{
"name": "peter"
},
{
"name": "thomas"
}
]
How can I archive this with just T-SQL? Is this even possible?
The FOR JSON clause will always include the column names - however, you can simply concatenate all the values in your json column into a single result, and then add the square brackets around that.
First, create and populate sample table (Please save us this step in your future questions):
CREATE TABLE WS_Test
(
Id int,
Json nvarchar(1000)
);
INSERT INTO WS_Test(Id, Json) VALUES
(1, '{ "name": "thomas" }'),
(2, '{ "name": "peter" }');
For SQL Server 2017 or higher, use the built in string_agg function:
SELECT '[' + STRING_AGG(Json, ',') + ']' As Result
FROM WS_Test
For lower versions, you can use for xml path with stuff to get the same result as the string_agg:
SELECT STUFF(
(
SELECT ',' + Json
FROM WS_Test
FOR XML PATH('')
), 1, 1, '[')+ ']' As Result
The result for both of these queries will be this:
Result
[{ "name": "thomas" },{ "name": "peter" }]
You can see a live demo on DB<>Fiddle

Single quote in JSON field POSTGRESQL

I am trying to manipulate a JSON with a single quote inside, and I am having some troubles:
1.- When I have a function, I cant pass as parameter a JSON string with a single quote inside:
This is the function:
CREATE OR REPLACE FUNCTION public.give_me_text
(
IN text json
)
RETURNS JSON AS
$$
DECLARE
v_text varchar;
begin
RAISE NOTICE 'text: %', text;
v_text:=text || '- hello';
return v_text;
end
$$
LANGUAGE 'plpgsql';
By calling like this is working:
SELECT * FROM give_me_text
(
'{"es":"name 1","en":"name 2","de":"name 3","fr":"name 4","pt":"name 5"}'
);
But when I have got a single quote is not working:
SELECT * FROM give_me_text
(
'{"es":"nam'e 1","en":"name 2","de":"name 3","fr":"name 4","pt":"name 5"}'
);
2.- When I am tryhing to insert JSON value with Single quote inside, it is giving me the same error:
This is working:
INSERT INTO public.my_columns VALUES ('{ "name": "Book the First", "author": { "first_name": "Bob", "last_name": "White" } }');
But this is not working:
INSERT INTO public.my_columns VALUES ('{ "name": "Book's the First", "author": { "first_name": "Bob", "last_name": "White" } }');
Any ideas how to escape this single quote? Thanks
In SQL, single quote must be escaped in a string. This is not a valid string:
'{"es":"nam'e 1"}'
because the string ends after "nam. You can escape the single quote by repeating it:
'{"es":"nam''e 1"}'
If you're doing dynamic SQL, you can pass parameters to execute:
execute 'insert into YourTable (col1) values ($1);' using json_var;