Rooms in Common
A hard SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.
- Domain
- SQL
- Difficulty
- hard
- Seniority
- L5
- Asked in
Problem
We map user networks through our chat channels: two people count as connected the moment they've both posted in the same channel, no matter how many channels they end up sharing. For each sender, find how many other people they're connected to.
Two people, one channel, a connection you never counted.
Tables
chat_msgs
Columns: msg_id INTEGER, channel TEXT, sender_id INTEGER, content TEXT, msg_type TEXT, sent_at TEXT, edited INTEGER, reply_to INTEGER
| msg_id | channel | sender_id | content | msg_type | sent_at | edited | reply_to |
|---|---|---|---|---|---|---|---|
| 147 | #engineering | 197 | Anyone seeing increased latency? | file | 2026-02-02 01:07:00 | 0 | NULL |
| 194 | #incidents | 294 | PR #412 ready for review | reaction | 2026-03-03 02:14:00 | 0 | NULL |
| 241 | #random | 391 | Dashboard is down | thread_reply | 2026-04-04 03:21:00 | 0 | NULL |
| 288 | #deployments | 488 | Fixed the flaky test | system | 2026-05-05 04:28:00 | 0 | NULL |
| 335 | #data-team | 585 | Merged the migration | Text | 2026-06-06 05:35:00 | 0 | NULL |
| 382 | #general | 682 | NULL | FILE | 2026-07-07 06:42:00 | 0 | NULL |
| 429 | #engineering | 779 | LGTM | text | 2026-08-08 07:49:00 | 0 | NULL |
| 476 | #incidents | 876 | 👍 | file | 2026-09-09 08:56:00 | 0 | 5 |
| 523 | #random | 973 | reaction | 2026-01-10 09:03:00 | 0 | NULL | |
| 570 | #deployments | 1070 | Can someone check the pipeline? | thread_reply | 2026-02-11 10:10:00 | 0 | NULL |
Expected output
| sender_id | mutual_connections |
|---|---|
| 100 | 24 |
| 197 | 24 |
| 294 | 24 |
| 391 | 24 |
| 488 | 24 |
Worked solution and explanation
What this problem really is
This is a mutual-connections network problem wearing a channel-analytics costume. Two senders are connected the moment they've both posted in the same channel, and the ask is simply: how big is each sender's network? The skill being probed is joining chat_msgs to itself on channel and counting each sender's distinct partners. The trap is double-counting from two directions at once: a sender pairs with themselves on every channel they touch, and a sender who shares three channels with the same person is still ONE connection. Miss either guard and your busiest senders balloon with phantom contacts.
Building it step by step
Step 1: Self-join on channel, exclude the self-pair
Alias chat_msgs as a and b and join on a.channel = b.channel. Every matching (a, b) row means those two senders posted in the same channel. The inequality a.sender_id != b.sender_id drops the self-pair, so a sender is never counted as their own connection.
Step 2: Count each distinct partner once
Use COUNT(DISTINCT b.sender_id) grouped by a.sender_id. The DISTINCT lives INSIDE the count, deduplicating partners during aggregation: if a and b share three channels they produce three matched rows, but the same b.sender_id counts once. This is the correct and efficient place for the dedup, not a SELECT DISTINCT after the fact.
Step 3: Sort most-connected first, tie-break on sender_id
ORDER BY mutual_connections DESC, a.sender_id DESC puts the most-connected senders first. Because many senders tie on the same connection count, the count alone is not a total order, so the second key a.sender_id DESC breaks ties deterministically and makes the row order a function of the input. Without it two correct answers could disagree on row order.
The solution
SELECT a.sender_id, COUNT(DISTINCT b.sender_id) AS mutual_connections
FROM chat_msgs a
INNER JOIN chat_msgs b ON a.channel = b.channel AND a.sender_id != b.sender_id
GROUP BY a.sender_id- Redundant three-way join
- Adding a third copy
cjoined onb.channel = c.channel AND a.sender_id = c.sender_idlooks like it verifies the link is bidirectional, but it re-asserts a constraint the first join already guarantees:ais always present inb's channel, socis justa's own row. It returns identical numbers at triple the join cost. - Clean two-alias self-join
- The first join already establishes that
aandbshare a channel; that relationship is inherently symmetric. One self-join plus the inequality and the distinct count is all the logic the metric needs.
Common follow-up questions
- Now only count two senders as connected if they share at least two different channels. How does the query change? (Tests whether the candidate can extend the connection definition with a strength threshold using HAVING or a channel-count aggregate.)
- `channel` is zipf-skewed with a few very hot channels. How does that skew affect the self-join, and how would you keep the hottest channels from dominating runtime? (Tests understanding of how the self-join fans out on a skewed, high-cardinality join key at scale.)
- Instead of the count per sender, return the distinct list of connected sender pairs without mirrored duplicates. How would you write that? (Tests ability to move from a per-sender count to the underlying edge list.)