Friend Suggestions (Friends of Friends)
For each user, which users do they share a mutual friend with but are not yet directly connected to?
- CTEs
- Joins
- Subqueries
- Filtering
- Sorting
Challenge brief
Understand the request
Social Graph Team is building the 'People You May Know' feature and needs users who share a mutual friend but are not yet directly connected.
Find second-degree connections (friends of friends who are not yet direct friends) using bidirectional friendship CTEs.
Return
- user_name (the user getting the suggestion)
- suggested_friend (username of suggested connection)
Constraints
- Use accepted friendships only
- Exclude the current user and every existing direct friend
- Return each user/suggestion pair once and order alphabetically
Data you will use
Review the relevant tables before deciding how to join, filter, or aggregate them.
friendships
friendship_idINTEGERuser_id_1INTEGERuser_id_2INTEGERstatusVARCHAR(20)
users
user_idINTEGERusernameVARCHAR(50)
Hints, when you need them
Open one clue at a time so you still do the reasoning.
Hint 1
Model friendships as bidirectional using UNION ALL. Then walk two hops: user to their friend (df1), then that friend to their other friends (df2). Filter out self-suggestions and anyone already directly connected.
Hint 2
CTE direct_friends: UNION ALL of both directions WHERE accepted. Chain: df1 (me to my friend) JOIN df2 (that friend to their friends). WHERE df2.fid != df1.uid AND df2.fid NOT IN (direct friends of me).
Hint 3
Start with the tables that establish the result grain for question 23, select the required output aliases, and add the remaining joins, filters, aggregation, and ordering one clause at a time.
Verified SQL answer
Attempt the problem first, then compare structure and reasoning—not just syntax.
Reveal solution and explanation
WITH direct_friends AS (SELECT user_id_1 AS uid, user_id_2 AS fid FROM friendships WHERE status = 'accepted' UNION ALL SELECT user_id_2, user_id_1 FROM friendships WHERE status = 'accepted') SELECT DISTINCT u.username AS user_name, u2.username AS suggested_friend FROM direct_friends df1 INNER JOIN direct_friends df2 ON df1.fid = df2.uid INNER JOIN users u ON df1.uid = u.user_id INNER JOIN users u2 ON df2.fid = u2.user_id WHERE df2.fid != df1.uid AND NOT EXISTS (SELECT 1 FROM direct_friends existing WHERE existing.uid = df1.uid AND existing.fid = df2.fid) ORDER BY user_name, suggested_friendWhy this works
Expand accepted friendships in both directions, traverse two hops, exclude self, and use a correlated anti-join so null semantics cannot admit an existing friend.
Success check
4 suggestions — john suggests sarah, sarah suggests john, jane suggests mike, mike suggests jane
Expected result
Use this output to verify values, aliases, ordering, and row count.
| user_name | suggested_friend |
|---|---|
| jane_smith | mike_wilson |
| john_doe | sarah_jones |
| mike_wilson | jane_smith |
| sarah_jones | john_doe |
Learn the concepts behind this answer
Strengthen your understanding with these targeted learning topics:
Continue practicing
Explore related company challenges
Google
Independent Google-style search, advertising, user-engagement, and video-product SQL practice.
Netflix
Independent Netflix-style streaming, subscription, catalog, ratings, and engagement SQL practice.
Airbnb
Independent Airbnb-style marketplace, booking, listing, payment, review, and guest analytics SQL practice.
Return to the complete interview preparation experience.