N019-H2 Tier 2 · Core SQL · hard analytics · Streamhub

Return the session ID and event ID for every row in the audit view

Part of FULL OUTER JOIN in SQL

The problem

Streamhub's data engineering team is auditing the completeness of the event pipeline:

  • Every session must appear, including sessions with no events recorded (event ID will be NULL).
  • Every event must appear, including events whose session_id does not resolve to any session (session ID will be NULL).

Write a query to return the session ID and event ID for every row in the audit view.

Assumptions:

  • A session with multiple events appears once per event in the result; a session with no events appears once with event_id as NULL; an orphan event appears once with session_id as NULL.

Output:

  • One row per matched session-event pair, plus one row per silent session (with event_id as NULL), plus one row per orphan event (with session_id as NULL), with columns session_id and event_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
  s.id AS session_id,
  e.id AS event_id
FROM
  sessions s
  FULL OUTER JOIN events e ON s.id = e.session_id

The shape

A FULL OUTER JOIN between sessions and events keeps every row from both sides. The matched rows multiply: a session that fired four events appears four times, one per event. The unmatched rows do not multiply: a silent session appears exactly once with event_id as NULL, and an orphan event appears exactly once with session_id as NULL. Cardinality is what controls the row count on the matched side; the outer join is what guarantees the orphan rows survive.

Clause by clause

  • SELECT s.id AS session_id, e.id AS event_id returns the primary key from each side of the join. On a matched row both values are real. On a silent session, event_id is NULL because the events side was padded in by the outer join. On an orphan event, session_id is NULL for the same reason on the opposite side. The two NULL patterns are how the data-engineering team labels each row as matched, silent, or orphan.
  • FROM sessions s FULL OUTER JOIN events e ON s.id = e.session_id is the audit join. The ON condition pairs a session with each of its events. Where it matches, the row is assembled from both sides — and the one-to-many relationship means a session with multiple events produces multiple rows. Where it doesn't, the outer join keeps the unmatched row anyway and NULL-pads the missing side. FULL makes that guarantee in both directions.
  • No WHERE. The team asked for the full audit view, so every row the join produces belongs in the output.

Why this and not a LEFT JOIN

LEFT JOIN anchored on sessions delivers the matched rows and the silent sessions, but loses every orphan event. Orphan events — events whose session_id doesn't resolve to any session — are usually the more interesting finding in a pipeline audit. Surfacing them alongside the silent sessions in a single pass is the whole reason the audit runs on both tables, which is exactly what FULL OUTER JOIN produces and what LEFT JOIN cannot.

The trap

The trap is reading the matched-row count as wrong because it's higher than the session count or the event count. A session with five events contributes five rows, not one. The matched side is producing one row per session-event pair, which is the correct shape for an event-level audit. Read the result by row category using the NULL patterns, not by counting against the source tables' row totals.

You practiced a FULL OUTER JOIN against a junction-style relationship. The recurring lesson: row count multiplies on the matched side (one row per session-event pair) while orphan rows on either side appear once each — three categories of rows, one query.

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.