0

I have table friends and table users

All the ids in friends table (user_one, user_two) are valid users from table users

Lets says a current LoggIn user visit another user's profile and the profile id which he visited is 27

Please Note: I am using the $_GET global variable to get this profile id. e.g

$user_id = $_GET['id'];

then he click on a link to view the friends of this user(27)

so now his friends are:18 and 33

Please how can I query database if current(18) user is also friends with user 33 ?

Note: user 18 is the current LoggIn user

below is clear friends table structure:

u1 | u2

18 | 33

33 | 27

27 | 18

below is my code i tried :

SELECT IF(user_one = '$IsLoggIn' OR user_two = '".$_GET['id']."', user_two, user_one)
FROM friends
WHERE ((user_one = '$IsLoggIn' OR user_two = '".$_GET['id']."') OR (user_two ='$IsLoggIn' OR user_two = '".$_GET['id']."')

Please am new to sql. Thank you

2 Answers2

0

I'm sure this is not the fastest solution (at all...) but it works at least.

I've implemented it with statements to avoid SQL injections as Niet mentioned in the comments.

PHP code:

<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// prepare and bind
$stmt = $conn->prepare("
select
    user_two as friend_id,
    if(exists(
        select *
        from friends
        where (user_one = friend_id and user_two = ?)
            or (user_two = friend_id and user_one = ?)),
        'yes', 'no') as mutual
from friends
where user_one = ? and user_two <> ?
union
select
    user_one as friend_id,
    if(exists(
        select *
        from friends
        where
            (user_one = friend_id and user_two = ?)
            or
            (user_two = friend_id and user_one = ?)),
        'yes', 'no') as mutual
from friends
where user_two = ? and user_one <> ?
");
$stmt->bind_param("iiiiiiii", $myUserId, $myUserId, $visitedUserId, $myUserId, $myUserId, $myUserId, $visitedUserId, $myUserId);

// set parameters and execute
$myUserId = $IsLoggIn;
$visitedUserId = $_GET['id'];
$stmt->execute();

// bind variables to prepared statement
$stmt->bind_result($visitedUserFriendsId, $isMutual);

// fetch values (here you can do whatever you want with results)
while ($stmt->fetch()) {
    printf("%s %s\n", $visitedUserFriendsId, $isMutual);
}

$stmt->close();
$conn->close();
?>

If you have this relationships in the table friends (27 is friend of 25, but 18 is not):

user_one | user_two
      18 |       33
      33 |       27
      27 |       18
      27 |       25

when user 18 visits user 27 profile, that SQL query will return:

friend_id | mutual
       25 |     no
       33 |    yes

And then you can work very easily with those results in PHP.

nanocv
  • 2,227
  • 2
  • 14
  • 27
  • @nancv Thanks for the help but can u please explain things to me on your code above? why did you prepared the statement? – Triumph Oduro Apr 30 '16 at 13:51
  • Sure I can! All you see there about statements is just the way most people work with PHP and MySQL nowadays. You have to prepare it to tell SQL which query you are going to make. And after that, you send the params to MySQL separatedly with the execute method. It's very well explained here: http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php – nanocv Apr 30 '16 at 13:56
  • @nancv. Can you use sub-queries or self join to get the same result? – Triumph Oduro Apr 30 '16 at 14:08
  • Well, actually we are using subqueries allready, into the exists() functions. And that's why its so slow. I'll try to get the same results with joins, and I'll let you know if I get it. – nanocv Apr 30 '16 at 14:13
  • @nancv...am waiting .. Thank you very much – Triumph Oduro Apr 30 '16 at 14:28
0

I know you already have the answer. I will use the same PHP code as @nanocv for you to make it short and easier to understand.

You can try this query instead (this query will return all friends of user profile visited, giving a second column as mutual: yes or no):

$stmt = $conn->prepare("
SELECT IF(f.user_one = ?,f.user_two,f.user_one) AS friend_id,     
IF((
    SELECT count(*) 
    FROM friends mf WHERE 
    (mf.user_one = friend_id AND mf.user_two = ?) OR 
    (mf.user_two = friend_id AND mf.user_one = ?) OR 
    (friend_id = ?) /* this return who is visiting as mutual! */

) > 0,'yes','no') AS mutual
FROM friends f 
WHERE (f.user_one = ? OR f.user_two = ?)
/* the next line will not return who is visiting as friend, 
   remove it if you want it to be return as friend */
AND (f.user_one != ? AND f.user_two != ?)
");

$stmt->bind_param('iiiiiiii', $visitedUserId, $myUserId, $myUserId,$myUserId, $visitedUserId, $visitedUserId, $myUserId, $myUserId);

IF the data in friends table does repeat like:

| u1 | u2 |
|----|----|
|  2 | 1  |
|  1 | 2  |

You will need to add a GROUP BY friend_id at the end of the query.

This query will return ONLY the friends of the user profile visited and the user logged in that are mutual:

$stmt = $conn->prepare("SELECT IF(f.user_one = ?,f.user_two,f.user_one) AS friend_id
    FROM friends f 
    WHERE (f.user_one = ? OR f.user_two = ?) AND 
    IF((
        SELECT count(*) 
        FROM friends mf WHERE 
        (mf.user_one = IF(f.user_one = ?,f.user_two,f.user_one) AND mf.user_two = ?) OR 
        (mf.user_two = IF(f.user_one = ?,f.user_two,f.user_one) AND mf.user_one = ?)

    ) > 0,TRUE,FALSE);");

    $stmt->bind_param('iiiiiii', $visitedUserId,$visitedUserId,$visitedUserId,$visitedUserId, $myUserId,$visitedUserId, $myUserId);
David Lavieri
  • 1,060
  • 1
  • 8
  • 19
  • Thanks for your help. I tried yours and it worked too but I added one id in the friends table who are friends with the current user and his id shows too.. how do i completely remove the that user if hes not friends friends at all?? – Triumph Oduro Apr 30 '16 at 15:06
  • So you dont want to show those whose arent mutual friends? – David Lavieri Apr 30 '16 at 15:08
  • yes please @ David Lavieri. BUT can u use self JOIN to achieve the same result? that way I will not need use the prepare statement because am thinking in the feature when the visitee friends increase like 600 the query will be slow. – Triumph Oduro Apr 30 '16 at 15:14
  • if you cant use self JOIN just show me how to get mutual users id. Thank you @David Lavieri – Triumph Oduro Apr 30 '16 at 15:18
  • self join require more comparison statements and will be even more slow. the query above is optimized – David Lavieri Apr 30 '16 at 15:41
  • Prepared statements don't make your query slow, but save. – David Lavieri Apr 30 '16 at 15:42
  • I updated the answer. the last query is what you asked. And if it works and it is what you want. set my answer as "this answer is useful" arrow up. – David Lavieri Apr 30 '16 at 16:06
  • 1
    When i get 15 reputable I will do that. Thanks it worked! – Triumph Oduro May 02 '16 at 10:01