Mysql explode json array to rows - mysql

From a table with a column with json array of dictionaries i need to extract all values of key "user_id" one per row. If null or empty array return NULL. Similar to python pandas explode method.
Length of array is unknown.
Original table:
| id | users |
|----|-----------------------------------------------------------------|
| 1 |[{"id": 2, "mail": "u1#ab.com"}, {"id": 3, "mail": "u2#ab.com"}] |
| 2 |[{"id": 5, "email": "user3#hi.com"}]" |
| 3 | []
|
Processed table:
| id | users |
|----|----------|
| 1 | 2 |
| 1 | 3 |
| 2 | 5 |
| 3 | NULL |

select id, j.user_id from mytable left outer join
json_table(users, '$[*]' columns (user_id int path '$.user_id')) as j on true;
+------+---------+
| id | user_id |
+------+---------+
| 1 | 2 |
| 1 | 3 |
| 2 | 5 |
| 3 | NULL |
+------+---------+
Read https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html for more information on the JSON_TABLE() function.

Related

Count character from a varchar column in json format

MYSQL - It will be my last post. I have a customer table that has a varchar (string) column. It is a json in string format.
I need to count the amount of characters for each field in the string. example:
---------------------------------------------------------
| table client |
---------------------------------------------------------
| id | name (type string) |
---------------------------------------------------------
| 1 | {"name":"Dylan Smith","valor":"$ 210,02"} |
| 2 | {"name":"Bruce Johnson","valor":"$ 1.210,02"} |
| 3 | {"name":"James Williams","valor":"$ 50.210,02"} |
| 4 | {"name":"Jimmy Jones","valor":"$ 87.210,02"} |
---------------------------------------------------------
I need a query that returns me:
---------------------------------------------------------
| resulta |
---------------------------------------------------------
| id | qtd_name_caracter | qtd_value_caracter |
---------------------------------------------------------
| 1 | 11 | 8 |
| 2 | 13 | 10 |
| 3 | 14 | 11 |
| 4 | 11 | 11 |
---------------------------------------------------------
I have no idea how to do this query. Does anyone know if this is possible?
If these strings are consistently properly formatted JSON, then you can use JSON functions on them:
select id,
char_length(name ->> '$.name' ) qtd_name_character,
char_length(name ->> '$.value') qtd_value_character
from mytable

Filter table rows linked to another table via pivot table on basis of where clauses acting on second table

+--------------+
| paintings |
+--------------+
| id | title |
+----+---------+
| 1 | muzelf1 |
| 2 | muzelf2 |
| 3 | muzelf3 |
+----+---------+
+----------------------------------------+
| tags |
+----------------------------------------+
| id | type | name |
+----+-----------------+-----------------+
| 1 | painting_medium | oil_painting |
| 2 | painting_style | impressionistic |
| 3 | painting_medium | mixed_media |
| 4 | painting_medium | watercolours |
| 5 | painting_style | mixed_media |
| 6 | painting_style | photorealistic |
+----+-----------------+-----------------+
+---------------------------+
| paintings_tags |
+---------------------------+
| id | painting_id | tag_id |
+----+-------------+--------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 4 |
| 4 | 3 | 2 |
| 5 | 3 | 1 |
+----+-------------+--------+
sql
CREATE TABLE paintings (
id integer AUTO_INCREMENT PRIMARY KEY,
title text
);
INSERT INTO paintings(id,title) VALUES
(1,'muzelf1'),(2,'muzelf2'),(3,'muzelf3');
CREATE TABLE tags (
id integer AUTO_INCREMENT PRIMARY KEY,
name text,
type text
);
INSERT INTO tags(id,name,type) VALUES
(1,'oil_painting','painting_medium')
,(2,'impressionistic','painting_style')
,(3,'mixed_media','painting_medium')
,(4,'watercolours','painting_medium')
,(5,'mixed_media','painting_style')
,(6,'photorealistic','painting_style');
CREATE TABLE paintings_tags (
id integer AUTO_INCREMENT PRIMARY KEY,
painting_id integer,
tag_id integer
);
INSERT INTO paintings_tags(id,painting_id,tag_id) VALUES
(1,1,1)
,(2,1,2)
,(3,2,4)
,(4,3,2)
,(5,3,1);
Find all the paintings with [{tags.type="painiting_medium", tags.name="oil_painitng"},{tags.type="painiting_style", tags.name="impressionistic"}].
+-----------------------------------+
| Expected Output |
+-----------------------------------+
| id | painting_title | painting_id |
+----+----------------+-------------+
| 1 | muzelf1 | 1 |
+----+----------------+-------------+
| 2 | muzelf3 | 3 |
+----+----------------+-------------+
Here is something I tried doing using bookShelf ORM and knex query builder.
Painting.query(function (qb) {
qb.innerJoin('painting_tags','paintings.id','painting_tags.painting_id')
.innerJoin('tags','painting_tags.tag_id','tags.id')
.where(qb => {
tagFilters.forEach(filter => {
qb.where('tags.type',filter.type).andWhere('tags.name',filter.name)
})
});
});
The above only works if the tag filters array has only one element. But I need it to work for all the filters in the array.
What would a raw query look like for the above? And how can I convert the same to work using ORM and query builder?
Here's one idea:
SELECT p.id painting_id
, p.title
, MAX(CASE WHEN t.type = 'painting_medium' THEN t.name END) medium
, MAX(CASE WHEN t.type = 'painting_style' THEN t.name END) style
FROM paintings p
JOIN paintings_tags pt
ON pt.painting_id = p.id
JOIN tags t
ON t.id = pt.tag_id
GROUP
BY p.id;
+-------------+---------+--------------+-----------------+
| painting_id | title | medium | style |
+-------------+---------+--------------+-----------------+
| 1 | muzelf1 | oil_painting | impressionistic |
| 2 | muzelf2 | watercolours | NULL |
| 3 | muzelf3 | oil_painting | impressionistic |
+-------------+---------+--------------+-----------------+
You could filter this as a subquery (or using HAVING) but, unless the data set was vast, I would be inclined to do the filtering in a bit of javascript.

MySql determine all elements of string list exists in other string list

I have these tables:
category_table
+--------+-----------------+---------+
| id | title | parent_id |
+--------+---------------+-----------+
| 1 | f | null |
| 2 | h | null |
| 3 | j | 1 |
| 4 | y | 3 |
| 5 | d | 3 |
+--------+-----------------+---------+
post_table
+--------+---------------+-------------+
| id | title | categoryies |
+--------+---------------+-------------+
| 1 | title1 | 1 |
| 2 | title2 | 1,2 |
| 3 | title3 | 4,5 |
| 4 | title4 | 4 |
| 5 | title5 | 3 |
+--------+---------------+-------------+
and a procedure that find all posts that has '3,5,2' categories.
how procedure will search string list in other string list similar to:
Create Procedure post_select(IN category_ids Varchar(200))
Begin
Select *
From post
Where
// all category_ids exists in post categories column
// such as FIND_IN_SET('1', '1,2,3') but first parameter
// should be list string for example:
// FIND_IN_SET('2,3,4','2,4,5,6,7,8')
End;
You should consider creating a post_category table where you store the post_id together with the category_id.

How to Search parent content from multiple table?

Table - parents
+----+----------+--------------+----------+
| id | user_id | content_type | name |
+----+----------+--------------+----------+
| 1 | 10 | 1 | name - 1 |
| 2 | 12 | 2 | name - 2 |
+----+----------+--------------+----------+
content_type can be
1 = Single part(movies)
2 = Multi prt(serials, episode)
Table - childs
+----+------------+--------------+--------------+-----------+
| id | parent_id | is_episode | episode_name | file_name |
+----+------------+--------------+--------------+-----------+
| 1 | 1 | 0 | NULL | movie.mp4 |
| 2 | 2 | 0 | NULL | zee.mp4 |
| 3 | 2 | 1 | cname-2 | lil-1.mp4 |
| 4 | 2 | 1 | child-2 | lil-2.mp4 |
+----+------------+--------------+--------------+-----------+
And is_episode can be:
0 = No
1 = Yes
NB: some other fields I have skipped
My QUERY:
SELECT F.id,F.user_id,F.content_type,F.name,M.is_episode, M.episode_name, M.file_name
FROM childs M,parents F
WHERE M.parent_id = F.id AND M.is_episode=0 AND
(F.name LIKE '%child%' OR M.episode_name LIKE '%child%' )
Abve MySQL query I am getting 0 record. There is 1 content
My search string applied based on parents.name or childs.episode_name I want to get all record which are is_episode=0 If I search child-2 then findout parent content of my current record. Here is my output should come
+----+----------+----------------+----------+------------+--------------+-----------+
| id | user_id | content_type | name | is_episode | episode_name | file_name |
+----+----------+----------------+----------+------------+--------------+-----------+
| 2 | 12 | 2 | name - 2 | 0 | NULL | zee.mp4 |
+----+----------+----------------+----------+------------+--------------+-----------+
OUTPUTS:
In above my two tables my output should come following criterias
If I search by name LIKE '%name%' output should be
+----+----------+----------------+----------+------------+--------------+
| id | user_id | content_type | name | is_episode | episode_name |
+----+----------+----------------+----------+------------+--------------+
| 1 | 10 | 1 | name - 1 | 0 | NULL |
| 2 | 12 | 2 | name - 2 | 0 | NULL |
+----+----------+----------------+----------+------------+--------------+
If I search by name LIKE '%cname%' or name LIKE '%name - 2%' or name LIKE '%child%' output should be
+----+----------+----------------+----------+------------+--------------+
| id | user_id | content_type | name | is_episode | episode_name |
+----+----------+----------------+----------+------------+--------------+
| 2 | 12 | 2 | name - 2 | 0 | NULL |
+----+----------+----------------+----------+------------+--------------+
If I search by name LIKE '%name - 1%' output should be
+----+----------+----------------+----------+------------+--------------+
| id | user_id | content_type | name | is_episode | episode_name |
+----+----------+----------------+----------+------------+--------------+
| 1 | 10 | 1 | name - 1 | 0 | NULL |
+----+----------+----------------+----------+------------+--------------+
If I search by name LIKE '%child%' output should be
+----+----------+----------------+----------+------------+--------------+
| id | user_id | content_type | name | is_episode | episode_name |
+----+----------+----------------+----------+------------+--------------+
| 2 | 12 | 2 | name - 2 | 0 | NULL |
+----+----------+----------------+----------+------------+--------------+
I am unable to get proper output of my query. Could you plese write down query which is satisfied my all the output.
Your problem is that you're filtering out only rows that has Is_episode = 0 however you need to search in the rows that has is_episode = 1 like cname-2 and child-2
your problem caused because is_episode = 0, remove it and it should work. please leave a comment if you still have a problem.
Update: based in your comments, based on my understanding I think you may require some sort of multiple queries and separation based on the table or your logic/conditions then union results together.
select .. from parent, child .. where is_episode = 0 and name like ...
union
select .. from child join parent where episode_name like ...

SQL Query with "feedback loop"

Currently, I am using MySQL
I have 2 tables:
Table objects:
| id | desc |
| 1 | 'A' |
| 2 | 'B' |
| 3 | 'C' |
| 4 | 'D' |
| 5 | 'E' |
Table implies:
| id1 | id2 |
| 1 | 2 |
| 1 | 3 |
| 2 | 4 |
| 2 | 5 |
| 3 | 5 |
Table Implies columns id1 and id2 are both foreign keys to table objects id.
Which means:
object 1 implies object 2 and object 3.
object 2 implies object 4 and object 5
object 3 implies object 5
Therefore, Object 1, implies 2, 3, and 4 and 5 (Since 2 implies 4 and 5)
Is there any way to create a query for this behaviour? My current solution consists on calling recursively from java the query until I don't get any new info:
SQL Query Im calling:
SELECT o.id, i.id2
FROM objects o
INNER JOIN implies i ON o.id = i.id1 WHERE id = 1;
I first call it with id = 1, then with id IN (2, 3)... etc
The kind of result I want to achieve:
SELECT ... WHERE id = 1
should return:
| id | id2 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |