简体   繁体   中英

My SQL Query to get Mutual/Friends Followers

I have a table like the one below:

id | Follower_id | leader_id | status
---------------------------------------- 
1  |   2         |  1        | approved
2  |   1         |  2        | approved
3  |   3         |  2        | approved
4  |   1         |  3        | approved

From this table, I want to retrive the Follower_id/leader_id that are mutual.

For examples 2 , 1 are mutual in this table. To achieve this I am using the following sql

SELECT r.follower_id RF
     , r.leader_id   RL
     , l.follower_id LF
     , l.leader_id   LL
  FROM followers r
  JOIN followers l
    ON l.follower_id = r.leader_id 
   AND l.leader_id = r.follower_id 
 WHERE r.status = 'approved'
   AND l.status = 'approved'; 

It returns the expected output, but it is very slow.

How can I optimize this SQL?

Perhaps something simpler might work faster, eg

SELECT follower_id, leader_id 
FROM followers a  
WHERE follower_id IN (
   SELECT follower_id 
   FROM followers b 
   WHERE a.leader_id = b.leader_id 
   AND status = 'approved' 
)
AND status = 'approved';

You are joining the whole table with the same table. That make no sense. Try the Inner Join so it will gave you the cut where the Leaders have the same followers or the followers the same leaders. Also you need to use an as Alias to join your tables.

SELECT *
FROM followers as f
INNER JOIN followers as k on f.follower_id = k.leader_id
WHERE f.follower_id like k.leader_id OR f.follower_id = k.leader_id

Before someone shit storm me, this is an example script which is shown you all entrys of bouth tables. In this case two times the same table.

Better for this is to make 2 Tables. Create an Accounting Table and an Follow Table and join them. should be works fine aswell and faster.

If you want more methods to join Tables take a look here: https://www.w3schools.com/sql/sql_join.asp

Your query produce a duplicate records. This also create some delay for your mysql connection.

To avoid duplication is to solve your problem.

I add my works below,

SELECT r.follower_id RF
     , r.leader_id   RL
     , l.follower_id LF
     , l.leader_id   LL

  FROM sample r

  JOIN sample l
    ON l.follower_id = r.leader_id 
   AND l.leader_id = r.follower_id AND r.id < l.id


 WHERE r.status = 'approved'
   AND l.status = 'approved';

Output:

RF  RL  LF  LL
2   1   1   2

Note: Use your table name insteed of sample .

Sometimes EXISTS is very efficient:

select 
  t.follower_id id1,
  t.leader_id id2
from followers t
where 
  status = 'approved'
  and
  t.follower_id < t.leader_id
  and 
  exists (
    select 1 from followers
    where status = 'approved' and follower_id = t.leader_id and leader_id = t.follower_id 
  )

This query will return each pair only once.
See the demo .
Results:

| id1 | id2 |
| --- | --- |
| 1   | 2   |

First, you can optimize this query with indexes:

SELECT r.follower_id as RF, r.leader_id as RL,
       l.follower_id as LF, l.leader_id as LL
FROM followers r JOIN
     followers l
     ON l.follower_id = r.leader_id AND
       l.leader_id = r.follower_id 
WHERE r.status = 'approved' AND l.status = 'approved'; 

The following index should help: followers(follower_id, leader_id, status) .

I would prefer to write this as exists . You might also try aggregation:

SELECT f.follower_id, f.leader_id
FROM followers f
WHERE f.status = 'approved'
GROUP BY LEAST(f.follower_id, f.leader_id),
         GREATEST(f.follower_id, f.leader_id)
HAVING MIN(f.follower_id) = MIN(f.leader_id);

The last condition guarantees that you have both directions in the data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM