FredyC
FredyC

Reputation: 4067

SELECTing for the other user of the pair

I have the following structure (simplified for brevity). I am mostly frontend developer that suddenly needs to learn the basics of SQL, so bear with me, please :)

CREATE TABLE user (
    id text NOT NULL,
    lastOnlineAt timestamptz NOT NULL
);
CREATE TABLE pair (
    id text NOT NULL
);
CREATE TABLE userPair (
    userId text NOT NULL,
    pairId text NOT NULL
);

The important aspect here is that every pair is linked to exactly 2 user entities (through userPair). I am not sure if was the wisest approach, but I did not like the idea of having columns user1/2 inside the pair.

Now I need to do a SELECT that for every user finds associated pairs, picks the other user of that pair and gets his lastOnlineAt for a comparison. Effectively I need to find paired users that were online in the last 5 minutes.

I would probably start like this.

SELECT up.'pairId' 
  FROM 'userPair' AS up 
       LEFT JOIN pair as p 
 WHERE up.'userId' = $userId 
   AND p.id = up.'pairId'

But then I am getting lost in complexity here.

It's for the Postgres 12.

Upvotes: 0

Views: 44

Answers (2)

Gordon Linoff
Gordon Linoff

Reputation: 1270653

One method uses a lateral join:

select u.*
from userpair p cross join lateral
     (values (userid, pairid), (pairid, userid)
     ) v(theuserid, theotherid) join
     users u 
     on u.id = v.theotherid
where v.theuserid = ?;

This uses the lateral join to split the data into two pairs -- with the users in either order. The first is matched to the input. The second is the other one that is returned.

Upvotes: 0

Mike Organek
Mike Organek

Reputation: 12494

You have a syntax errors in that a left join needs an on and identifiers cannot be enclosed in single quotes since that makes them literals.

You need to join userpair twice to get what you want:

SELECT u2.* 
  FROM "userPair" AS p1 
       JOIN "userPair" p2 
         ON p2."pairId" =  p1."pairId"
        AND p2."userId" != p1."userId"
       JOIN "user" u2 
         ON u2.id = p2."userId" 
 WHERE p1."userId" = $userId 
   AND u2."lastOnlineAt" >= now() - interval '5 minutes'

Also, using camel case for identifier is very bad idea.

Upvotes: 1

Related Questions