How to use MySQL to find users who follow each other - mysql

I thought this was going to be easy until I tackled it.
I'm trying to write a query that will produce a list of users who follow each other (like tiktok). It's not too hard to get the list of users who follow each other but my query shows both ways.
For example, the data look like:
follower_id followee_id
1 2
1 3
1 4
2 1
2 3
2 4
3 1
3 2
3 4
4 2
4 3
Using the above data, the output should be:
follower_id followee_id
1 2
1 3
2 3
2 4
3 4
Note that everybody follows everybody except 4 doesn't follow 1.
The table structure is below
CREATE TABLE follows (
follower_id INT NOT NULL,
followee_id INT NOT NULL
);
The INSERT statement:
INSERT INTO follows(follower_id, followee_id)
VALUES(1,2), (1,3), (1,4), (2,1), (2,3), (2,4), (3,1), (3,2), (3,4), (4,2), (4,3);
I think a self-join can get the users who follow each other, but I get twice as many rows as I want.
mysql> SELECT
-> f1.follower_id AS f1_follower,
-> f1.followee_id AS f1_followee,
-> f2.follower_id AS f2_follower,
-> f2.followee_id AS f2_followee
-> FROM follows f1
-> JOIN follows f2
-> ON f1.follower_id = f2.followee_id
-> AND f1.followee_id = f2.follower_id
-> ORDER BY f1.follower_id, f1.followee_id;
+-------------+-------------+-------------+-------------+
| f1_follower | f1_followee | f2_follower | f2_followee |
+-------------+-------------+-------------+-------------+
| 1 | 2 | 2 | 1 |
| 1 | 3 | 3 | 1 |
| 2 | 1 | 1 | 2 |
| 2 | 3 | 3 | 2 |
| 2 | 4 | 4 | 2 |
| 3 | 1 | 1 | 3 |
| 3 | 2 | 2 | 3 |
| 3 | 4 | 4 | 3 |
| 4 | 2 | 2 | 4 |
| 4 | 3 | 3 | 4 |
+-------------+-------------+-------------+-------------+
10 rows in set (0.00 sec)
In the first row, we see that 1 and 2 follow each other, but the third row also shows that 1 and 2 follow each other, just the reciprocal of the first row. Same goes for rows 2 and 6, rows 4 and 7, rows 5 and 9, and rows 8 and 10. So I really just want to show rows 1, 2, 4, 5, and 8 (ie., only the non-reciprocal rows). Reciprocal probably isn't the right word - the assumption in the output will be that 1, 2 means "users 1 and 2 follow each other."
I'm probably way over-thinking this one but any and all help will be greatly appreciated!

Your original query is fine you just need the additional predicate to only return one version of the relationship -
SELECT f1.*
FROM follows f1
JOIN follows f2 ON f1.follower_id = f2.followee_id AND f1.followee_id = f2.follower_id
WHERE f1.follower_id < f1.followee_id;

Related

SQL: Get top users that follow same users

I have the table followers that looks like this:
id |follower_id|followee_id|
1 | 1 | 2 |
2 | 1 | 3 |
2 | 1 | 4 |
3 | 2 | 3 |
4 | 2 | 4 |
5 | 3 | 2 |
6 | 4 | 6 |
Where follower is a user_id and followee is the user they follow.
How can I find the users that have the most common followees with let's say user 1?
The results need to be ordered by number of common followees.
For example for the current table the results for user 1 would be:
follower_id|common_followees|
2 | 2 |
3 | 1 |
As you can see 4 does not appear in results since it has no common followees with user 1
I hope I explained the problem right.
Thank You.
This is a self-join and aggregation:
select f.follower_id, count(*) as num_common_followees
from followers f join
followers f1
on f.followees = f1.followees and f1.follower_id = 1
group by f.follower_id;
You can add where f.follower_id <> 1. I like to leave that row in as a validation check.

Mysql, combine two sql query in one statement

I have two tables.
1) jb_theme_metadata
column : idx | t_name
1 | sports
2 | movies
2) jb_theme
column : idx | theme_idx(F key of jb_theme_metadata) | u_idx (F key of jb_user)
1 | 1 | 3
2 | 1 | 4
3 | 1 | 5
4 | 2 | 7
expected output
column : idx | t_name | user_count
1 | sports | 3
2 | moives | 1
Can I make this output by a sql query not two statements?
May be this would work for you:
SELECT m.idx, m.t_name, COUNT(t.u_idx) as user_count
FROM jb_theme_metadata AS m
JOIN jb_theme AS t ON t.theme_idx=m.idx
GROUP BY t.theme_idx

MqSql - fetch rows which employee has maximum complaint severity level

I am dealing with a table Employee Complaint which has columns EmployeeId ComplaintSeverity and ComplaintByUser. ComplaintSeverity has four level 0,1,2, and 3.
So the table will look like this ,Example
ComplaintId|EmployeeId|ComplaintSeverity|usr_id
-----------------------------------
1 | 1 | 0 | 3
2 | 2 | 1 | 4
3 | 3 | 0 | 5
4 | 1 | 2 | 4
5 | 4 | 1 | 5
6 | 2 | 2 | 2
7 | 2 | 2 | 4
Any user can complaint employee with any of these level
When client search with severitylevel as 0,
The row should fetch as
ComplaintId|EmployeeId|ComplaintSeverity
----------------------------
3 | 3 | 0
for severitylevel as 1,
ComplaintId|EmployeeId|ComplaintSeverity
----------------------------
5 | 4 | 1
for severitylevel as 2,
ComplaintId|EmployeeId|ComplaintSeverity
----------------------------
4 | 1 | 2
6 | 2 | 2
EmployeeId 1 has been complained by 2 user with severitylevel 0,2 but his highest severity level is 2. so while searching for 0 level, 1 should not be displayed.
Can anyone help me?
The question was edited after the previous answer was submitted. The following would therefore be more accurate.
SELECT x.*
FROM my_table x
JOIN
( SELECT employeeid
, MAX(complaintseverity) severity
FROM my_table
GROUP
BY employeeid
) y
ON y.employeeid = x.employeeid
AND y.severity = x.complaintseverity
WHERE complaintseverity = 0 -- optional line
ORDER
BY employeeid;
You can try following query.
SELECT *
FROM
(
SELECT cs.`EmployeeId`, MAX(cs.`ComplaintSeverity`) severity
FROM ComplaintSeverity cs
GROUP BY cs.`EmployeeId`
) csdata
WHERE csdata.severity=1
Replace 1 with the severity level you want.

Counting patterns from table mysql

I have the following data in a Mysql table
ID | code | code order
1 | 1 | 1
1 | 2 | 2
1 | 3 | 3
2 | 1 | 1
2 | 2 | 2
2 | 3 | 3
3 | 1 | 1
3 | 4 | 2
3 | 5 | 3
4 | 1 | 1
4 | 4 | 2
4 | 5 | 3
4 | 6 | 4
How would I write a query to return the following results
code pattern 1,2,3 = 2 (count)
code pattern 1,4,5 = 1 (count)
code pattern 1,4,5,6 = 1 (count)
basically I need to find out the most popular code sequence, each sequence is grouped by an unique ID. The order the codes of the is also important. i.e
1,4,5,6 is different to 1,5,4,6
cheers
In MySQL, this is probably most easily done using two aggregation:
select pattern, count(*)
from (select id, group_concat(code order by code) as pattern
from t
group by id
) p
group by pattern;

How to select only that what matches all parameters in many-to-many

Need to get only the records that match all the specified conditions in many-to-many relationship.
Greatly simplified tables look like
Catalog Catalog_Types Types
1 1 1 1
2 1 2 2
3 2 1 3
2 3 4
2 4
3 1
3 4
It easy to select from Catalog by 1 type, but i need select by 1 ore more, for example how to get from Catalog only those rows that have Types 1 and 2, so if it have 1 but haven't 2 it is not suitable.
I saw a similar question and the decision here, but for the SQL. There used except, i tried to replace it by equals on mySQL, but I do not know mySQL so well.
thank you in advance,
and sorry for my english
This type of query is called "set within set"
If you want to get catalog ids with two types (1 and 2) but may have other types
SELECT catalog_id
FROM catalog_type
WHERE type_id IN (1, 2)
GROUP BY catalog_id
HAVING COUNT(DISTINCT type_id) = 2
if want to make sure you get catalog ids with exactly two types (e.g. 1 and 2)
SELECT catalog_id
FROM catalog_type
GROUP BY catalog_id
HAVING SUM(type_id = 1) > 0
AND SUM(type_id = 2) > 0
AND COUNT(DISTINCT type_id) = 2;
if you want to get catalog ids which have at least two of three types (e.g. 1, 2, 4)
SELECT catalog_id
FROM catalog_type
WHERE type_id IN (1, 2)
GROUP BY catalog_id
HAVING (MAX(type_id = 1)
+ MAX(type_id = 2)
+ MAX(type_id = 4)) >= 2
Assuming that you have following in catalog_type
| CATALOG_ID | TYPE_ID |
------------------------
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 3 |
| 2 | 4 |
| 3 | 1 |
| 3 | 2 |
| 3 | 4 |
Sample output for above-mentioned queries:
query 1 query 2 query 3
| CATALOG_ID | | CATALOG_ID | | CATALOG_ID |
-------------- -------------- --------------
| 1 | | 1 | | 1 |
| 3 | | 3 |
Here is SQLFiddle demo for all these queries. Take a look and see how results differ.