Building a social site which allows users to follow each other, and enforcing a business rule that only allows DMs when two users mutually follow each other.
Follows are stored in a lookup:
TABLE FOLLOWS
- userA_ID FK
- userB_ID FK
Given this dataset in the FOLLOWS
table:
|userA_ID |userB_ID |
-----------------------
|123 |456 | <- Gerald follows Jane
|789 |456 | <- Grace follows Jane
|456 |789 | <- Jane follows Grace
If I’m logged in as Jane, I can DM Grace but not Gerald, and vice-versa.
My current Query….
-- mutual followers
SELECT DISTINCT (u.id) AS userId, u."name" AS "userName"
FROM "Follows"
INNER JOIN "User" u ON u.id = "userA_ID"
WHERE "userB_ID" = $1
INTERSECT
SELECT DISTINCT (u.id) AS "userId", u."name" AS "userName"
FROM "Follows"
INNER JOIN "User" u ON u.id = "userB_ID"
WHERE "userA_ID" = $1
…feels clunky. Is there a way to write this in a single SELECT instead of with a UNION?
3
Answers
Yes, you don’t need to use
UNION
INTERSECT
. The intersection is basically computed as aWHERE EXISTS(…)
statement checking for the same values to be in the result of the second query. But the query to arrive at these results can be simplified a bit by usingEXISTS
directly – you don’t need to joinUser
again:Btw you can also drop the
DISTINCT (u.id)
– if your primary keys / unique constraints onUser(id)
andFollows(userA_ID, userB_ID)
are set up correctly then this query can’t generate multiple rows for the same user.And you can actually express that
WHERE EXISTS(*)
as anotherJOIN
:Another approach to simplify the query is to move the intersection to a straightforward subquery specifically for mutual followers:
What you need is an
inner join
and what people mostly don’t know is that you’re not limited to a simple
a.id = b.a_id
Answer
and get
As for how to make only one row, I don’t yet know
If you need this for production, you can leave it at that, though. Making it distinct won’t be faster.
Explanation
So quick stuff
I did
and your main query
result:
well, you could fix it up a bit, but that’s ok
Your requirement could be translated as per each mutual follower, there will be more than 1 related records in table "Follows".