This is a sample database 'test' with a JSON column 'arr' containing an array of JSON objects
+----+----------------------------------------------------------+
| id | arr |
+----+----------------------------------------------------------+
| 1 | [{"name": "aman"}, {"name": "jay"}] |
| 2 | [{"name": "yash"}, {"name": "aman"}, {"name": "jay"}] |
+----+----------------------------------------------------------+
I want to use JSON_CONTAINS to know if a value exists in a specific key of an object in the array.
Here's my query :
SELECT JSON_CONTAINS(arr, '"jay"', '$[*].name') from test WHERE id=1;
I get the following error:
ERROR 3149 (42000): In this situation, path expressions may not contain the * and ** tokens or an array range.
I know that I can try using JSON_EXTRACT() for this, but what am I doing wrong here ?
Is there any way to use JSON_CONTAINS with an array of JSON objects in MySQL.
Yes, it is possible using the following syntax:
SELECT JSON_CONTAINS(arr, '{"name": "jay"}') from test WHERE id=1;
db<>fiddle demo
Example:
+-----+--------------------------------------------------------+---+
| id | arr | r |
+-----+--------------------------------------------------------+---+
| 1 | [{"name": "aman"}, {"name": "jay"}] | 1 |
| 2 | [{"name": "yash"}, {"name": "aman"}, {"name": "jay"}] | 1 |
| 3 | [{"name": "yash"}, {"name": "aman"}] | 0 |
+-----+--------------------------------------------------------+---+
You must use JSON_SEARCH:
SELECT JSON_SEARCH(arr, 'one', 'jay', NULL, '$[*].name') IS NOT NULL
FROM test
WHERE id=1;
Related
I have a table with a json column that looks like this :
+----+------------+
| id | myfield |
+----+------------+
| 1 | ["1", "2"] |
| 2 | ["3", "2"] |
| 3 | ["2", "4"] |
+----+------------+
How can I merge all values from myfield in one array?
I need a result that will look like this: ["1", "2", "3", "2", "2", "4"], or even better with removed duplicates.
I tried using this query:
SELECT JSON_ARRAYAGG(myfield) FROM json_test but as a result I'm getting:
[["1", "2"], ["3", "2"], ["2", "4"]]
I assume I need a query in combination with the function JSON_MERGE.
Here's a solution but it requires MySQL 8.0 for the JSON_TABLE() function:
SELECT GROUP_CONCAT(j.myvalue) AS flattened_values
FROM mytable, JSON_TABLE(
mytable.myfield, '$[*]' COLUMNS(myvalue INT PATH '$')
) AS j;
Output:
+------------------+
| flattened_values |
+------------------+
| 1,2,3,2,2,4 |
+------------------+
I would actually recommend avoiding storing JSON arrays. Instead, store multi-valued data in a normalized manner, in a second table. Then you could just use GROUP_CONCAT() on the joined table.
I have still yet to hear of a use of JSON in MySQL that isn't better accomplished by using database normalization.
How do I extract only value based on "id" = "BAR"
+------------------------------+
| data |
+------------------------------+
| {"id": "FOO", "code": "FOO"} |
| {"id": "BAR", "code": "BAR"} |
+------------------------------+
desired output
+------------------------------+
| code |
+------------------------------+
| BAR |
+------------------------------+
I tried with this but it does not work.
SELECT
JSON_EXTRACT(DATA, '$[*].code') as code
FROM TABLETEST
where JSON_UNQUOTE(JSON_EXTRACT(data, '$[*].id')) ='BAR'
If you just want to get the data from the "code" column when the id = "BAR", the SQL you're looking for may simply be:
SELECT `code` FROM `data` WHERE id = "BAR"
Hey I've been searching and looking all day. Have gotten further into understanding my problem and the options. By I am at a lack of understanding.
My general issue is that I am trying to SELECT rows based on values in the JSON and order the selection by there selected values.
I have a table (elements), with two columns: Person and Tags. Tags contains a JSON array that can have multiple JSON objects inside it. Objects always have "name" and "sort".
+-------------+------------------------------------------------------------------+
| Person | tags
+-------------+------------------------------------------------------------------+
| William | [{"name": "apple", "sort": "1"}, {"name": "orange", "sort": "2"}]
| Anna | [{"name": "apple", "sort": "3"}, {"name": "orange", "sort": "1"}]
| Michael | [{"name": "apple", "sort": "2"}]
+-------------+------------------------------------------------------------------+
Ideally what I would like to do is tell the database using to SELECT * FROM elements WHERE tags (has an object where name is "apple") ORDER by (The sort value from the object where it matched);
So if I gave it "apple" it would list: William, Michael, Anna.
If I gave it "orange" it would list: Anna, William.
I have been looking into having SELECTs within SELECTs (Subqueries) but I can find the right combination with JSON. Below is the closest I have gotten, but I can tell it needs something more advanced?
SELECT *
FROM elements
WHERE JSON_SEARCH( tags, 'one', 'apple', NULL, '$[*].name' ) IS NOT NULL
This will return all the people, with apple tag, but it will not order them based on the sort.
Any suggestions are welcome, thanks in advance.
Here a "nice" Query that works for you. You only must change res.* to res.name for your query.
SELECT res.* FROM (
SELECT
SUBSTRING_INDEX( JSON_UNQUOTE (JSON_SEARCH(e.tags, 'one', 'apple')),'.',1) as idx
,e.* FROM `elements` AS e ) AS res
WHERE res.idx IS NOT NULL
ORDER BY JSON_UNQUOTE(JSON_EXTRACT(res.tags,CONCAT(res.idx,'.sort')));
SAMPLE
mysql> select * from elements;
+----+---------+-------------------------------------------------------------------+
| id | Person | tags |
+----+---------+-------------------------------------------------------------------+
| 1 | William | [{"name": "apple", "sort": "1"}, {"name": "orange", "sort": "2"}] |
| 2 | Anna | [{"name": "apple", "sort": "3"}, {"name": "orange", "sort": "1"}] |
| 3 | Michael | [{"name": "apple", "sort": "2"}] |
+----+---------+-------------------------------------------------------------------+
3 rows in set (0.00 sec)
Find apple
mysql> SELECT res.* FROM (
-> SELECT
-> SUBSTRING_INDEX( JSON_UNQUOTE (JSON_SEARCH(e.tags, 'one', 'orange')),'.',1) as idx
-> ,e.* FROM `elements` AS e ) AS res
-> WHERE res.idx IS NOT NULL
-> ORDER BY JSON_UNQUOTE(JSON_EXTRACT(res.tags,CONCAT(res.idx,'.sort')));
+----+---------+-------------------------------------------------------------------+
| id | Person | tags |
+----+---------+-------------------------------------------------------------------+
| 1 | William | [{"name": "apple", "sort": "1"}, {"name": "orange", "sort": "2"}] |
| 2 | Anna | [{"name": "apple", "sort": "3"}, {"name": "orange", "sort": "1"}] |
| 3 | Michael | [{"name": "apple", "sort": "2"}] |
+----+---------+-------------------------------------------------------------------+
3 rows in set (0.00 sec)
Find orange
mysql> SELECT res.* FROM (
-> SELECT
-> SUBSTRING_INDEX( JSON_UNQUOTE (JSON_SEARCH(e.tags, 'one', 'orange')),'.',1) as idx
-> ,e.* FROM `elements` AS e ) AS res
-> WHERE res.idx IS NOT NULL
-> ORDER BY JSON_UNQUOTE(JSON_EXTRACT(res.tags,CONCAT(res.idx,'.sort')));
+------+----+---------+-------------------------------------------------------------------+
| idx | id | Person | tags |
+------+----+---------+-------------------------------------------------------------------+
| $[1] | 2 | Anna | [{"name": "apple", "sort": "3"}, {"name": "orange", "sort": "1"}] |
| $[1] | 1 | William | [{"name": "apple", "sort": "1"}, {"name": "orange", "sort": "2"}] |
+------+----+---------+-------------------------------------------------------------------+
2 rows in set (0.01 sec)
There's a similar question here which might assist you.
You may be able to use JSON_EXTRACT however it gets complicated because you're storing an array of JSON data so you might also require a sub query.
I'll propose an alternate solution though. Have you considered restructuring your database across multiple tables instead of using a JSON blob?
You could have a table dedicated to storing the tags, something like this:
+-------------+------------------------------------------------------------------+
| tagid | name
+-------------+------------------------------------------------------------------+
| 1 | apple
| 2 | orange
| 3 | banana
+-------------+------------------------------------------------------------------+
Another table for storing the people:
+-------------+------------------------------------------------------------------+
| id | name
+-------------+------------------------------------------------------------------+
| 1 | William
| 2 | Anna
| 3 | Michael
+-------------+------------------------------------------------------------------+
And finally a table for storing the many-many relationship between people and tags. This is also where you can store the sort order:
+-------------+--------------+-----------+--------------------------------------+
| id | personid | tagid | sort
+-------------+--------------+-----------+--------------------------------------+
| 1 | 1 | 1 | 1
| 2 | 1 | 2 | 2
| 3 | 2 | 1 | 3
| 4 | 2 | 2 | 1
| 5 | 3 | 1 | 1
+-------------+--------------+-----------+---------------------------------------+
A database model that looks more like this will make complicated queries much simpler and won't require complex subqueries, just joins. It's likely to improve your ability to report on data relating to your tags, if that's something that's important to you.
I have a Redshift table in which one of the columns is a JSON array. I would like to append some data into that array. Eg:
id | col1 | col2
1 | A | {"key": []}
2 | B | {"key": []}
3 | B | {"key": ['A']}
4 | B | {"key": ['A', 'B']}
I would like to create a statement like UPDATE <table> SET col2 = <something> where col1 = 'B' so that I get:
id | col1 | col2
1 | A | {"key": []}
2 | B | {"key": ['C']}
3 | B | {"key": ['A', 'C']}
4 | B | {"key": ['A', 'B', 'C']}
You'd have to write your own User Defined Function (UDF), passing in the current value of the column and the element you would like to add, then passing back the result.
Hwoever, you really should avoid JSON columns in Amazon Redshift if at all possible. They cannot take advantage of all the features that make Redshift great (columnar, SORTKEY, etc). Plus, you'll have problems like this that are not in the normal realm of a relational database.
I've got several Postgres 9.4 tables that contain data like this:
| id | data |
|----|-------------------------------------------|
| 1 | {"user": "joe", "updated-time": 123} |
| 2 | {"message": "hi", "updated-time": 321} |
I need to transform the JSON column into something like this
| id | data |
|----|--------------------------------------------------------------|
| 1 | {"user": "joe", "updated-time": {123, "unit":"millis"}} |
| 2 | {"message": "hi", "updated-time": {321, "unit":"millis"}} |
Ideally it would be easy to apply the transformation to multiple tables. Tables that contain the JSON key data->'updated-time' should be updated, and ones that do not should be skipped. Thanks!
You can use the || operator to merge two jsonb objects together.
select '{"foo":"bar"}'::jsonb || '{"baz":"bar"}'::jsonb;
= {"baz": "bar", "foo": "bar"}