N023-M1 Tier 2 · Core SQL · medium analytics · Streamhub

Return the user IDs that appear in both the `sessions` table and the `conversions` table

Part of UNION, UNION ALL, INTERSECT, EXCEPT in SQL

The problem

Streamhub's conversion team wants to know which users have both started at least one session and made at least one conversion.

Write a query to return the user IDs that appear in both the sessions table and the conversions table.

Assumptions:

  • The sessions table records each session; user_id identifies the user.
  • The conversions table records each paid conversion; user_id identifies the user.
  • A user appears in the result exactly once, regardless of how many sessions or conversions they have.

Output:

  • One row per user who appears in both tables, with a single column user_id.
Schema · analytics 5 tables
users
id integer
name text
email text
country text
plan text
signed_up_at timestamptz
is_active boolean
conversions
id integer
user_id integer
converted_at timestamptz
plan text
amount numeric
sessions
id integer
user_id integer
started_at timestamptz
ended_at? timestamptz
event_count integer
events
id integer
user_id integer
session_id? integer
event_type text
occurred_at timestamptz
properties? jsonb
periods
id integer
name text
start_month integer
end_month integer

Run previews · Check grades

Write a query, then run it to see results here.

Worked solution Try it yourself first
Solution query
SELECT
  user_id
FROM
  sessions
INTERSECT
SELECT
  user_id
FROM
  conversions

The shape

INTERSECT returns only rows that appear in both result sets, after deduplication. The output is the list of users who show up in sessions and also show up in conversions — the conversion team's session-plus-conversion overlap, computed directly as a set intersection.

Clause by clause

  • SELECT user_id FROM sessions is the left input. Every row in sessions projects its user. A user with many sessions contributes many rows here, but INTERSECT will deduplicate before comparing, so the multiplicity on each side does not change the output.
  • INTERSECT is the set operator. PostgreSQL evaluates each query independently, deduplicates each side, then returns rows that are present in both. The comparison is on the full row across both inputs — for a single-column query like this one, that means the user_id values themselves.
  • SELECT user_id FROM conversions is the right input. Same column, same type. A user with multiple conversions contributes multiple rows here too, but they collapse to one before the intersection runs.
  • The prompt asks for each qualifying user exactly once, which is the default shape INTERSECT produces. No extra step is needed to remove duplicates.

Why this and not UNION

UNION would combine the two queries and return every user who appears in either — anyone with a session, anyone with a conversion, deduplicated. That's the wrong question. The conversion team wants the and, not the or: users who are in sessions and in conversions simultaneously. UNION answers "appears in at least one"; INTERSECT answers "appears in both." The difference between the operators is the difference between the two questions, and picking the wrong one produces a much larger result set that looks plausible until someone checks the row count against either input.

You practiced INTERSECT for set-intersection logic. The recurring rule: INTERSECT returns rows present in both inputs after deduplication — equivalent to a JOIN on the matching columns followed by a DISTINCT, but more readable when set-membership is the question.

How you actually get good at SQL

Reading explains SQL. Writing it, over and over with instant feedback, is what makes you fluent.

That's the whole SQLMaxx loop: 600+ real problems, instant AI feedback, mastery you can actually see, and spaced review that won't let you forget.

A stack of SQL practice problem cards, the top card showing an employees table.
615 problems · 66 concepts

Real problems. Not toy examples.

615 hand-built problems spanning all 66 concepts, from basic SELECTs to window functions, built on real schemas and real business questions, the kind you'll actually get asked on the job. Enough reps to make SQL automatic.

A retro computer showing a SQL query marked correct with a green checkmark.
Instant AI feedback

Write a query. Know if it's right in one second.

No copying an answer and hoping it clicked. The AI grader checks your real query against real data, catches exactly what's wrong, and explains the fix in plain English, like a senior analyst reading over your shoulder on every problem.

A circular mastery progress dial filling from blue to green, the SQLMaxx diamond at its center.
Mastery tracking

Stop guessing whether you actually know it.

SQLMaxx tracks every concept and shows you what you've mastered and what's still shaky. Your skills fill in one concept at a time, so 'I think I get joins' becomes something you can prove.

A SQL query editor circled by a blue return arrow with a clock, scheduled to come back for review.
Spaced review

Learn it once. Keep it for good.

Most of what you learn this week fades by next week. So when a concept comes due for review, SQLMaxx hands you a fresh problem to solve from a blank editor, not a flashcard to re-read. A research-backed spaced-repetition algorithm (FSRS) times each return for right before you'd forget, so your SQL is still there months later, when the interview or the job actually needs it.

Practice, feedback, mastery, review. That's the loop that turns reading into real skill.

Start free

No account, no credit card. Start solving in under a minute.