简体   繁体   中英

How to INNER JOIN the correct VALUE from 2 values in the table where 1 is correct

I need to select and inner join the correct u1 or u2 the opposite of the current user to display the correct friend's list with the correct picture/id

Sess id

$sess_id = $_SESSION['user']['id'];

Relationship table :

id      u1_fk    u2_fk     u_action     status
-------------------------------------------------
 1       1        2            2          5
-------------------------------------------------
 1       3        1            3          5

Details:

  • Id is auto increment id
  • u1_fk is the first users id the one who engaged (submitted a friend request)
  • u2_fk is the other user's id (The one who got the friend request)
  • u_action is the last user who made an action (etc sent a friend request, denied/accepted a friend request, blocked the other user etc etc)

User table :

user_id    user_username          user_picture
-------------------------------------------------
 1           someusername           me.jpg       
-------------------------------------------------
 2           anotherusername      another.jpg
-------------------------------------------------
 3           thirdusername         third.jpg

SQL + PHP (Here I INNER JOIN u_action on user_id):

$sql = "SELECT t1.id as id, "
        . " t1.u1_fk as u1, "
        . " t1.u2_fk as u2, "
        . " t2.user_id as userid, "
        . " t2.user_username as username, "
        . " t2.user_picture as picture "
        . " FROM relationships t1 "
        . " INNER JOIN users t2 "
        . " ON t1.u_action = t2.user_id "
        . " WHERE (t1.u1_fk = :user_one "
        . " OR t1.u2_fk = :user_two) "
        . " AND t1.relationship_status = 5 ";

$stmt = $dbCon->prepare($sql);
$stmt->bindParam(":user_one", $sess_id);
$stmt->bindParam(":user_two", $sess_id);
$stmt->execute();
$count = $stmt->rowCount();
if ($count > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
}

I thought I could use the u_action , but that does only work for one of them obviously since it is either one of the 2 users ids stored in that field.

So how do I know whenever my query should inner join u1 or u2 , I'm a bit confused here I hope someone can help me out, im thinking about doing 2 queries and sort all the results and remove the users own id and do a where in clause in the second querie, i am wondering however if this can be done in just 1 query.

What the result from the database should look like .

What I want as a result from the database in this particular example where sess_id is 1 :

id      u1_fk    u2_fk      userid     username         picture
------------------------------------------------------------------
 1       1        2            2     anotherusername   another.jpg
------------------------------------------------------------------
 1       3        1            3      thirdusername     third.jpg

What I want as a result from the database in this particular example where sess_id is = 2

id      u1_fk    u2_fk      userid     username         picture
------------------------------------------------------------------
 1       1        2            2     someusername   me.jpg
------------------------------------------------------------------

Assuming that the relationship is one way, from U1 to U2, then it is simple:

select u.*
from relationships r
inner join users u on r.u2_fk = u.id
where r.u1_fk = ?

I have no earthly idea what action or status mean.

Something that would make this clearer is if you make your dB field more descriptive in the relationship table: ie, user_id and friend_id. Then it becomes obvious that you want to join relationship.friend_id to user.id, and filter by relationship.user_id

Then you can additionally filter by status etc.


Since you've added the desired results, I see that you want to include both u1_fk and u2_fk in the results. This can certainly be done, but you're making it far more confusing that way, IMO.

I would suggest that when a friendship is accepted, create a new line for the new friend. This way, when you want to find all friends for a user, you only have to match up u1_fk (ie, user_id) and the friend will always be u2_fk (friend_id).

Then, each friend can independently control how they want to associate, ie, you can block me or I can block you. -- my two cents worth. Make your association do One Thing.


It might be helpful to look at the schema:

User    Relationship    User
           id
id ---->  u1_fk
          u2_fk <------- id

That would be easy to figure out. But what you're wanting out of it is more like

User    Relationship    User
           id
 id -----> u1_fk <------ id
     \---> u2_fk <---/

So to start, I'm looking at it from the point of view of filtering by relationship and then adding the users info as they match:

select r.id, r.u1_fk, r.u2_fk, 
       coalesce(u1.user_id, u2.user_id) userid,
       coalesce(u1.username, u2.username) username,
       coalesce(u1.user_picture, u2.user_picture) picture
from relationship r
left join user u1 on r.u1_fk = u1.id
left join user u2 on r.u1_fk = u2.id
where u1_fk = ? or u2_fk = ?

but that means you would have to coalesce fields from u1 and u2.

The other solution would be to start with user, join all possible relationships, and join that with users that aren't the user you started with (GMB's elegant solution)

However, what happens if you have:

id    u1_fk    u2_fk
        1        2
        2        1

I think both of the solutions will give you a duplicate listing.

That's why I would strongly encourage you to rename (at least in your head) u1_fk and u2_fk to user_id and friend_id .

The following query should do the trick:

SELECT
    r.id as id,
    r.u1_fk as u1,
    r.u2_fk as u2,
    u2.user_id as userid,
    u2.user_username as username,
    u2.user_picture as picture
FROM 
    users u1
    INNER JOIN relationship r 
        ON  r.status = 5
        AND (r.u1_fk = u1.user_id OR r.u2_fk = u1.user_id)
    INNER JOIN users u2
        ON  u2.user_id <> u1.user_id
        AND (r.u1_fk = u2.user_id OR r.u2_fk = u2.user_id) 
WHERE 
    u1.user_id = :sessid

u1 represents the users record for the current session id, and u2 is JOIN ed in as the user on other end of the relation.

This demo on DB Fiddle with you sample data returns, for session id 1 :

| id  | u1  | u2  | userid | username        | picture     |
| --- | --- | --- | ------ | --------------- | ----------- |
| 1   | 1   | 2   | 2      | anotherusername | another.jpg |
| 1   | 3   | 1   | 3      | thirdusername   | third.jpg   |

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