N059-H1 Tier 5 · Expert · hard hr · Helix Systems

Return the total number of pairings produced when each active employee is matched up with each of their salary records and each of their job-history records simultaneously

Part of Join Fanout and Aggregate Correctness in SQL

The problem

Scenario: Helix Systems' HR analytics team is sizing a planned compensation report that pulls each active employee's salary records and job-history records together, before committing to its compute cost.

Task: Write a query to return the total number of pairings produced when each active employee is matched up with each of their salary records and each of their job-history records simultaneously.

Assumptions:

  • An active employee has is_active equal to TRUE.
  • An employee can have multiple salary records.
  • An employee can have multiple job-history entries.
  • An active employee with 3 salary records and 4 job-history entries contributes 12 pairings to the total — every salary paired with every job-history entry.

Output:

  • One row, holding the total pairing count.
  • Columns in this order: row_count.
Schema · hr 4 tables
departments
id integer
name text
location text
budget numeric
salaries
id integer
employee_id integer
amount numeric
effective_date date
end_date? date
employees
id integer
name text
email text
department_id integer
manager_id? integer
hire_date date
title text
is_active boolean
job_history
id integer
employee_id integer
title text
department_id integer
start_date date
end_date? date

Run previews · Check grades

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

Worked solution Try it yourself first
Solution query
SELECT
  COUNT(*) AS row_count
FROM
  employees e
  JOIN salaries s ON s.employee_id = e.id
  JOIN job_history jh ON jh.employee_id = e.id
WHERE
  e.is_active = TRUE

The shape

Joining a parent to two independent child collections multiplies the per-parent row count by the cardinality of each child set. An employee with 3 salary records and 4 job-history entries doesn't produce 3 + 4 = 7 rows after both joins — it produces 3 × 4 = 12, because every salary record gets paired with every job-history entry for that employee.

Clause by clause

  • SELECT COUNT(*) AS row_count counts the rows produced by the full joined, filtered result. Each row is one (employee, salary record, job-history entry) triple.
  • FROM employees e reads the employees as the driving parent.
  • JOIN salaries s ON s.employee_id = e.id attaches every salary record to its employee. An employee with three salary records contributes three rows after this join.
  • JOIN job_history jh ON jh.employee_id = e.id attaches every job-history entry to its employee. Crucially, this join runs against the already-fanned-out result from the previous join — each of the three salary rows now gets paired with every one of the employee's four job-history entries, producing 12 rows total for that employee.
  • WHERE e.is_active = TRUE keeps only active employees. The filter applies on the employee side, so all salary records and job-history entries of inactive employees drop out together.

Why this and not summing the two child counts

The compute-cost sizing is asking the right question — what is the post-join row volume? — and the only way to get that number is to actually run the joined count. Adding COUNT(*) FROM salaries and COUNT(*) FROM job_history separately would tell the HR team how many salary records and job-history entries exist on their own, but it would miss the multiplicative interaction between them entirely. The 12-row example in the prompt is the whole point: two collections joined to the same parent multiply, they don't add.

The trap

This is the canonical multi-way fanout shape, and the danger isn't visible until someone tries to aggregate a salary column or a job-history column over this result. Summing s.salary_amount here would count each salary record once per matching job-history entry — four times for the employee in the example. Summing jh.tenure_months would count each job-history entry once per matching salary record — three times. The pairing count is the right metric for compute sizing, but it is the wrong shape for any per-employee, per-salary, or per-history aggregation. The fix in those cases is to pre-aggregate each child collection to one row per employee before bringing it into the same query, so the parent table joins to two one-to-one summaries instead of two one-to-many tables.

You practiced sizing a multi-way join's row explosion — pairing two child collections per parent multiplies the per-parent count by the cardinality of each child set.

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.