JSON_EXTRACT() Query returns NULL - mysql

Hello i have a question about mysql json_extract function.
DROP TABLE IF EXISTS `db`.`PacJSON`;
CREATE TABLE PacJSON SELECT * FROM PAC;
ALTER TABLE PacJSON ADD COLUMN hc JSON DEFAULT NULL;
UPDATE `db`.`PacJSON`
SET `hc`='[{"estado":"1"},{"descripcion":"name1"},{"estudio": "name2"}, {"url":"name3"},{"idpaciente":"11"},{"idmedico":"6"},{"fecha_hc":"2019-05-2"}]'
WHERE idUsuario=11;
The query below is returning a null value when it should return 6.
Can somebody tell me what am i doing wrong?
SELECT idUsuario,PacJSON.hc ,JSON_UNQUOTE(JSON_EXTRACT(hc ,'$."idmedico"')) AS "idmedico"
FROM PacJson;
Thanks!

Your hc value contains an array of objects, so you need to use a path which reflects that i.e. $[*].idmedico. Note that double quotes should not be used in the path.
SELECT idUsuario,
hc,
JSON_UNQUOTE(JSON_EXTRACT(hc ,'$[*].idmedico')) AS idmedico
FROM PacJSON
Output:
["6"]
Note that because hc is an array, JSON_EXTRACT returns one too. If you know there's only one idmedico value in the JSON, you can use JSON_EXTRACT again on that result to get the actual numeric value:
SELECT idUsuario,
hc,
JSON_UNQUOTE(JSON_EXTRACT(JSON_EXTRACT(hc ,'$[*].idmedico'), '$[0]')) AS idmedico
FROM PacJSON
Output:
6
Demo on dbfiddle

Related

SQL JSON_VALUE returning NULLs [duplicate]

I have a column data consisting of {"name":["John","Peter"],id:["20","30"]}
If I do
SELECT JSON_VALUE(data,'$.name[0]') from table
it returns John but doing
SELECT JSON_VALUE(data,'$') from db
SELECT JSON_VALUE(data,'$.name') from table
returns NULL in both.
How come it does not return:
{"name":["John","Peter"],id:["20","30"]}
["John","Peter"]
As mentioned in the remarks section of the JSON_VALUE documentation there is a table that says for tags array in the json says: Use JSON_QUERY instead.
SELECT json_query(j,'$.name') from a;
Fiddle

How to get first key's value from a flat jsonb field in postgresql

I have localized jsonb column with data like {"en": "Atmosphere", "ja": "雰囲"} . I can extract it using field->'en'. I want to get a fallback, the first/any value in case the given locale (say 'es') is missing. Is this possible?
I'm using Postgres 13
I would create a function for that:
create or replace function get_value_with_fallback(p_data jsonb, p_key text)
returns text
as
$$
select p_data ->> p_key
where p_data ? 'en'
union all
select value
from jsonb_each_text(p_data) as d(key, value)
where not p_data ? p_key
limit 1;
$$
language sql
immutable;
Then you can use it like this:
select get_value_with_fallback(t.data, 'en')
from the_table t
As this is a simple SQL function that can be defined as immutable, this is essentially the same as embedding that UNION query directly into your SQL query.
I'm sure there is a better solution using path syntax. I can suggest using ORDER BY for that. Getting "en" translation or falling back to any other value:
SELECT
value
FROM
jsonb_each('{"cn": "囲囲", "lt":"test"}'::jsonb)
ORDER BY
key = 'en' DESC --position matching translation first
LIMIT 1
You take first - either the one that you are searching for, or any value.

How to extract a value from JSON that repeats multiple times?

I have the following table:
I need to create a select that returns me something like this:
I have tried this code:
SELECT Code, json_extract_path(Registers::json,'sales', 'name')
FROM tbl_registers
The previous code returns me a NULL in json_extract_path, I have tried the operator ::json->'sales'->>'name', but doesn't work too.
You need to unnest the array, and the aggregate the names back. This can be done using json_array_elements with a scalar sub-query:
select code,
(select string_agg(e ->> 'name', ',')
from json_array_elements(t.products) as x(e)) as products
from tbl_registers t;
I would also strongly recommend to change your column's type to jsonb
step-by-step demo:db<>fiddle
SELECT
code,
string_agg( -- 3
elems ->> 'name', -- 2
','
) as products
FROM tbl_registers,
json_array_elements(products::json) as elems -- 1
GROUP BY code
If you have type text (strictly not recommended, please use appropriate data type json or jsonb), then you need to cast it into type json (I guess you have type text because you do the cast already in your example code). Afterwards you need to extract the array elements into one row per element
Fetch the name value
Reaggregate by grouping and use string_agg() to create the string list

JSON_VALUE path "$" returns NULL when it contains data

I have a column data consisting of {"name":["John","Peter"],id:["20","30"]}
If I do
SELECT JSON_VALUE(data,'$.name[0]') from table
it returns John but doing
SELECT JSON_VALUE(data,'$') from db
SELECT JSON_VALUE(data,'$.name') from table
returns NULL in both.
How come it does not return:
{"name":["John","Peter"],id:["20","30"]}
["John","Peter"]
As mentioned in the remarks section of the JSON_VALUE documentation there is a table that says for tags array in the json says: Use JSON_QUERY instead.
SELECT json_query(j,'$.name') from a;
Fiddle

Assigning query's results into variable inside MySQL procedure

Here is the piece of sql from my procedure:
....
SET #list := (
SELECT
`i`.`id`
FROM
`Item` AS `i`
Order by RAND()
LIMIT 10
);
RETURN CONCAT_WS( '-', #list );
Inside procedure, I need to set query's results (yes, query returns multiple rows as a result) into some variable.
Then as a second variable, I need to concatenate previous results into one string.
But when I do it, I get following error:
Sub-query returns more than 1 row
So the question is, what am I doing wrong?
By the way, I know about group_concat. In second part of procedure, there is a requirement for checking if some id exists on this #list variable: find_in_set(item_id, #list )
And the query returns random results every time when I call it.
That's why, calling sub-query 2 times: 1 time as group concat string, second time just as list of results is not a solution for me. So, I need them as a set stored in variable.
You are approaching this is exactly the wrong way. There is no reason to store the ids in a list.
In the second part of the procedure, you should just be using a subquery:
where exists (select 1
from item i
where i.id = <outer table>.item_id
)
If you really did want to put things into a list, you would use group_concat() as you allude to:
SELECT #list := GROUP_CONCAT(i.id ORDER BY RAND() SEPARATOR '-') as ids
FROM Item i;
I don't see a use for storing the value in a variable, nor for ordering the ids randomly.
So the question is, what am I doing wrong?
What you're doing wrong is trying to store a result set in a user variable.
https://dev.mysql.com/doc/refman/5.7/en/user-variables.html says:
User variables can be assigned a value from a limited set of data types: integer, decimal, floating-point, binary or nonbinary string, or NULL value.
This kind of variable cannot store an array or a result set. Only one scalar value.
This question has code that seems to be related to Checking and preventing similar strings while insertion in MySQL
You should try following solution to overcome the issue of storing large data, it might help others too looking for solution:
# sets the default 1Mb storage limit to 10Mb
SET SESSION group_concat_max_len = (1024*10);
SET #list := (SELECT GROUP_CONCAT(id) FROM `Item` AS `i` Order by RAND() LIMIT 10);