table looks like this:
my_table
id (int) create_time (timestamp) meta_data (json)
1 2019-01-20 18:35:42 {"my property": "123"}
2 2019-01-20 19:35:42 {"more data": "456"}
I've tried querying with:
SELECT * FROM my_table
WHERE meta_data = '{"my property": "123"}';
SELECT * FROM my_table
WHERE meta_data = '\{\"my property\"\: \"123\"\}';
And it doesn't work, how can I query an exact match on a json field string?
I noticed this DOES work...
SELECT * FROM my_table
WHERE meta_data LIKE '\{\"my property\"\: \"123\"\}';
Do I need to use LIKE? Why = not work?
I know the JSON field is a special field type that is designed to let you easily query specific properties, but I wanted to be able to just check against the full JSON easily. And clearly the JSON field has some parameters that cause the = not to work as I expected.
This is the solution I figured out, cast JSON as CHAR:
SELECT * FROM my_table
WHERE CAST(meta_data as CHAR) = '{"my property": "123"}';
Another option:
SELECT * FROM my_table
WHERE meta_data = CAST('{"my property": "123"}' AS JSON);
You can also obtain JSON values by casting values of other types to the JSON type using CAST(value AS JSON);"
https://dev.mysql.com/doc/refman/5.7/en/json-creation-functions.html#function_json-quote
Use JSON_CONTAINS:
SELECT *
FROM my_table
WHERE JSON_CONTAINS(meta_data, '"123"', '.$"my property"');
Demo
Notes:
Since the target value to match for the key my property is a literal string, we need to also search for the double quotes.
To escape the key my property in the JSON path, we can escape that using double quotes.
If you want to compare a JSON column to a JSON value, then use JSON_OBJECT() to create the value.
Demo:
create table t (id int primary key, data json);
insert into t values (1, json_object('my property', '123'));
insert into t values (2, json_object('more_data', 456));
select * from t where data = json_object('more_data', 456);
+----+--------------------+
| id | data |
+----+--------------------+
| 2 | {"more_data": 456} |
+----+--------------------+
You should refer this
https://dev.mysql.com/doc/refman/5.7/en/json-search-functions.html
to use JSON data for query
Try (modify according to the right name of the property and datatype. If String use "123".
SELECT * FROM my_table WHERE JSON_EXTRACT(meta_data, "$.`my property`")= 123
Or may be
SELECT * FROM my_table WHERE JSON_EXTRACT(meta_data, "$.my property")= 123
Related
I have 2 MySQL tables that look like this:
first_table: the "json_field" values are just lists of integers, but the field type is "json":
id json_field
1 [1,2,3]
2 [2,3]
3 [1,3]
second_table: just a simple table with 2 fields (integer, varchar):
id name
1 bob
2 sam
3 mary
I need a single query that gives me all rows from first_table for which json_field values intersect with any "id" value from second_table that satisfies a simple query condition of "where name = 'sam'" (e.g. using a subquery)
Here's what I have so far:
select * from first_table where
JSON_OVERLAPS(json_field, (select group_concat(id) from second_table where name = 'sam'))
This query gives this error, however:
"Invalid JSON text in argument 1 to function json_overlaps: "The document root must not be followed by other values." at position 1."
I also tried this thinking that I had to convert the result of group_concat to json first, but got an SQL syntax error:
select * from first_table where
JSON_OVERLAPS(json_field, JSON_OBJECT(select group_concat(id) from second_table where name = 'sam'))
The correct result should give me the following 2 rows, since those rows contain id = 2, which is the id that corresponds to "sam" in second_table
1 1,2,3
2 2,3
Please assume that I must use a json field type for "first_table". The schema that I outlined above cannot be changed.
Don't use GROUP_CONCAT(), because it returns a string, not a set of rows. It can't be used to compare to a JSON document, and it can't be used to convert into a JSON array.
Instead, use JSON_ARRAYAGG() on a set of rows. This function transforms the set of rows into a JSON array.
select id, json_pretty(json_field) from first_table
where json_overlaps(json_field,
(select json_arrayagg(id) from second_table where name='Sam')
);
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=7a8d4f8a47042c1f9fa763c0689287ea
SELECT t1.id, CAST(t1.json_field AS CHAR), t2.id, t2.name
FROM t1
JOIN t2 ON JSON_OVERLAPS(t1.json_field, CAST(t2.id AS JSON))
WHERE t2.name = 'sam'
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=6d065e49643b04d4630f0031096aa4ee
Below is the json stored in a table called "Sample" and the column name is "argument". I want to fetch all those records having a particular value in a specified argument. I could query the argument name but not able to query a particular value as it is an array of strings. (Please find my keys have . in it)
{
"arguments":{
"app.argument1.appId":["123", "456"],
"app.argument2.testId":["546", "567"]
}
}
This gives me all the records having particular argument.
select * from sample where json_exists(argument, '$.arguments."app.argument1.appId"');
But I need to match argument value. I tried below but getting JSON expression error.
select * from sample where json_exists(argument, '$.arguments."app.argument1.appId[*]"?(# == "123"));
Please help. Thanks in advance.
You have the quotation marks in the wrong place; you want the double quotes before the square-brackets for the array instead of afterwards:
select *
from sample
where json_exists(
argument,
'$.arguments."app.argument1.appId"[*]?(# == "123")'
);
Which, for the sample data:
CREATE TABLE sample ( argument CLOB CHECK ( argument IS JSON ) );
INSERT INTO sample ( argument ) VALUES ( '{
"arguments":{
"app.argument1.appId":["123", "456"],
"app.argument2.testId":["546", "567"]
}
}');
Outputs:
| ARGUMENT |
| :----------------------------------------------------------------------------------------------------------------------- |
| {<br> "arguments":{<br> "app.argument1.appId":["123", "456"],<br> "app.argument2.testId":["546", "567"]<br> }<br>} |
db<>fiddle here
Do you know a way to do this in 12.1?
You could also use EXISTS with a correlated JSON_TABLE (which is available from Oracle 12c Release 1 (12.1.0.2)).:
select *
from sample
where EXISTS (
SELECT 1
FROM JSON_TABLE(
argument,
'$.arguments."app.argument1.appId"[*]'
COLUMNS (
value VARCHAR2(100) PATH '$'
)
)
WHERE value = '123'
);
db<>fiddle here
There's a hard to understand issue with querying on a json field in MySQL. The data column is of type json.
The following query works perfectly fine
SELECT * FROM `someTable` WHERE data->'$.someData' in ('A')
However the following one returns nothing.
SELECT * FROM `someTable` WHERE data->'$.someData' in ('A','B')
Funnily enough this also works:
SELECT * FROM `someTable` WHERE data->'$.someData'='A' OR data->'$.someData'='B'
I'm clueless as to why this happens. I originally thought that WHERE x IN executed in a json query format might be doing something like && but even if the values are ('A','A') it still returns nothing which essentially shows that more than one value in WHERE x IN wont work.
SAMPLE DATA (any would do really)
id | data (json)
1 | {"someData":"A"}
2 | {"someData":"B"}
Too long for a comment...
This seems to be related to an optimisation MySQL is performing when there is only one value in the IN expression (probably converting it to an a = b expression) and then it ignoring quotes. Strictly speaking,
SELECT *
FROM `someTable`
WHERE data->'$.someData' in ('A')
or
SELECT *
FROM `someTable`
WHERE data->'$.someData' = 'A'
should return no data because
SELECT data->'$.someData'
FROM someTable;
returns
"A"
"B"
which is not the same as A. You need to use JSON_UNQUOTE (or if you have MySQL 5.7.13 or later the ->> operator) to get the actual value of the someData key:
SELECT JSON_UNQUOTE(data->'$.someData') FROm someTable;
SELECT data->>'$.someData' FROm someTable;
which gives
A
B
which then works fine with an IN expression:
SELECT *
FROM `someTable`
WHERE JSON_UNQUOTE(data->'$.someData') in ('A','B')
-- or use WHERE data->>'$.someData' in ('A','B')
Output:
id data
1 {"someData":"A"}
2 {"someData":"B"}
Demo on dbfiddle
You could try using a join on a subquery instead of a IN clause
SELECT *
FROM `someTable` s
INNER JOIN (
select 'A' col
union
select 'B'
) t ON t.col = s.data->'$.someData
I need to get json from a restful service in a pl/pgsql function. (I have no control on restful webservice. It's published by someone else). I could get the json but I couldn't convert it to rows (for inserting to a table). The simplified format of it is below. Every GUID is random and I don't know their content before. When I convert it from text (with ::json) I get no errors, so it's valid json.
l_json := '{"GUID-0001":{"Id":"1","Field1":"aaa1","Field2":"bbb1"}, "GUID-0002":{"Id":"2","Field1":"aaa2","Field2":"bbb2"}}'::json;
I tried several Postgresql json functions but each time I got a different error. i.e. when I use json_array_elements() function, I got "ERROR: cannot call json_array_elements on a non-array". When I tried json_each_text() function I got "ERROR: query has no destination for result data"
I need a resultset as the following:
GUID | Id | Field1 | Field2
---------+----+--------+-------
GUID-0001| 1 | aaa1 | bbb1
GUID-0002| 1 | aaa2 | bbb2
You can get all the keys using jsonb_object_keys() and the use that to access the fields inside the JSON:
with data(doc) as (
values ('{"GUID-0001":{"Id":"1","Field1":"aaa1","Field2":"bbb1"}, "GUID-0002":{"Id":"2","Field1":"aaa2","Field2":"bbb2"}}'::jsonb)
)
select t.uid,
d.doc -> t.uid ->> 'Id' as id,
d.doc -> t.uid ->> 'Field1' as column1,
d.doc -> t.uid ->> 'Field2' as column2
from data d, jsonb_object_keys(doc) as t(uid);
returns:
uid | id | column1 | column2
----------+----+---------+--------
GUID-0001 | 1 | aaa1 | bbb1
GUID-0002 | 2 | aaa2 | bbb2
You can put that into a function that accepts a jsonb as a parameter:
create or replace function store_json(p_doc jsonb)
returns void
as
$$
insert into the_table (guid, id, column1, column2)
select t.uid,
(d.doc -> t.uid ->> 'Id')::int,
d.doc -> t.uid ->> 'Field1',
d.doc -> t.uid ->> 'Field2'
from (select p_doc) as d(doc),
jsonb_object_keys(doc) as t(uid);
$$
language sql;
I think the easiest way to tackle this problem is to adjust your json a bit prior to inserting and then use json_populate_recordset to convert the json to rows.
Convert the outer object to an array in your app code, and move the GUID-000x value inside the relevant object under a GUID key like so:
[
{
"GUID": "GUID-0001",
"Id": "1",
...
},
{
"GUID": "GUID-0002",
"Id": "1",
...
}
...
]
I don't know what language you are using for your app code, but I assume you have some form of reduce at your disposal to do the job.
Once you have your data in the proper format, you can use json_populate_recordset like so:
insert into your_table
select GUID, Id, Field1, Field2
from json_populate_recordset(null::your_table, _your_modified_json_from_above)
;
json_populate_recordset basically takes your json and matches keys to columns defined on your_table and adds the values accordingly. The catch is your object keys must match the column names exactly, and your values need to match (or be able to be cast to match) the data types defined on those columns.
I want to put random values into my user-table with data from a set.
I got a list of firstnames and surnames and i want to replace all name columns in my table. I was thinking of using a set
SET #firstNames = 'Thomas,Chris,Sophia,Ava';
SET #surNames = 'Peterson,Bolander,Travolta,Anniston';
Is it possible to write a query which randomly updates values in the name column on each user?
Table
User table
---------------------
id
name
password
created_at
I just found a way doing it
UPDATE persons
SET first_name = (
SELECT val FROM (
SELECT '' as val
UNION ALL SELECT 'Thomas' as val
UNION ALL SELECT 'Chris' as val
UNION ALL SELECT 'Sophia' as val
......
) AS vals ORDER BY RAND() LIMIT 1
)
would not be good idea to do that with Mysql, try doing that with your front-end Language. in Mysql we have RAND() function but that returns random number between 0 and 1, it would be very long way to get your desired output with this, so tryout passing random names from your front-end language, which is very easy task