Knowledge Guide
HomeDatabasesSQL Practice Problems

easy Sales Person

You build the set of sales_ids that did trade with RED, then keep every salesperson whose id is provably absent from that set — an anti-join (set difference) over the join Orders ⋈ Company.

Problem

Three tables. Find the names of salespersons who had no orders with the company named "RED".

SalesPerson(sales_id PK, name, salary, commission_rate, hire_date)
Company(com_id PK, name, city)
Orders(order_id PK, order_date, com_id FK→Company, sales_id FK→SalesPerson, amount)

The task is a set difference: all salespersons minus salespersons linked to RED. The only subtlety is how SQL evaluates "not in this set" when the set can contain unknowns.

The data we will trace

Concrete rows (the canonical LeetCode 607 fixture):

SalesPersonCompanyOrders (com_id → sales_id)
1 John1 RED (Boston)o1: com 3 → sales 4
2 Amy2 ORANGE (NewYork)o2: com 4 → sales 5
3 Mark3 YELLOW (Boston)o3: com 1 → sales 1
4 Pam4 GREEN (Austin)o4: com 1 → sales 4
5 Alex

Only orders o3 and o4 point at company 1 (RED). Their salespersons are 1 (John) and 4 (Pam). So the answer is everyone else: Amy, Mark, Alex.

Step 1 — who sold to RED

Join Orders to Company on com_id, keep only the RED company, project the salesperson id.

SELECT o.sales_id
FROM   Orders o
       JOIN Company c ON c.com_id = o.com_id
WHERE  c.name = 'RED';

Trace: o1→com3 (YELLOW, drop), o2→com4 (GREEN, drop), o3→com1 (RED, keep → 1), o4→com1 (RED, keep → 4). Result set: {1, 4}.

Step 2 — keep everyone not in that set

SELECT s.name
FROM   SalesPerson s
WHERE  s.sales_id NOT IN (
           SELECT o.sales_id
           FROM   Orders o
                  JOIN Company c ON c.com_id = o.com_id
           WHERE  c.name = 'RED');

Row by row against {1, 4}: John(1)→in set, drop. Amy(2)→keep. Mark(3)→keep. Pam(4)→in set, drop. Alex(5)→keep. Output: Amy, Mark, Alex. Correct for this data.

diagram
diagram

Why the naive version is fragile

The query above is correct only because Orders.sales_id happens to hold no NULLs here. The pattern itself hides SQL's single most-missed gotcha.

x NOT IN (a, b, c) desugars to x ≠ a AND x ≠ b AND x ≠ c. If any element is NULL, that comparison is not FALSE — it is UNKNOWN (three-valued logic). And TRUE AND UNKNOWN = UNKNOWN, which is not TRUE, so the row is excluded. The result: a single NULL anywhere in the subquery makes NOT IN return zero rows, regardless of the real data. No error, no warning — just an empty result that looks plausible until production traffic produces a NULL sales_id.

The robust formulations sidestep three-valued logic entirely. NOT EXISTS is the canonical fix:

-- NOT EXISTS: NULL-safe, and usually the planner's friend
SELECT s.name
FROM   SalesPerson s
WHERE  NOT EXISTS (
           SELECT 1
           FROM   Orders o
                  JOIN Company c ON c.com_id = o.com_id
           WHERE  c.name = 'RED'
             AND  o.sales_id = s.sales_id);

NOT EXISTS asks "is there a matching RED order for this salesperson?" A NULL o.sales_id never equals s.sales_id, so it simply fails to match — it cannot poison other rows. The anti-join via LEFT JOIN ... IS NULL is equivalent:

-- Anti-join: keep salespersons with NO surviving RED match
SELECT s.name
FROM   SalesPerson s
       LEFT JOIN (Orders o JOIN Company c
                    ON c.com_id = o.com_id AND c.name = 'RED')
              ON o.sales_id = s.sales_id
WHERE  o.order_id IS NULL;

The RED filter must constrain which orders count before the anti-join, so collapse Orders ⋈ Company(RED) into one joined set and LEFT JOIN the salesperson to that, keeping those with no surviving match. A naive version — two separate LEFT JOINs with c.name='RED' in the second ON — is wrong: a salesperson who has both a RED and a non-RED order (here Pam: RED order o4 and YELLOW order o1) keeps her non-RED row with a NULL company, which slips through ... IS NULL and re-admits her. Restrict the probe side first, then test for the absence of a match.

Pitfalls

Takeaways


Problem from LeetCode 607 "Sales Person." NULL semantics of NOT IN per the SQL standard's three-valued logic (ISO/IEC 9075); equivalence of NOT EXISTS and anti-join, and planner behavior, follow the PostgreSQL and SQL Server documentation on subqueries and join elimination. Three-valued-logic framing draws on Joe Celko, "SQL for Smarties." Re-authored and deepened for this guide: added the NULL-propagation failure mode the original omitted, the NULL-safe NOT EXISTS and LEFT JOIN ... IS NULL rewrites, a traced example, and the three-valued-logic diagram.

🤖 Don't fully get this? Learn it with Claude

Stuck on Sales Person? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🪜 Hint ladder (no spoilers)

Progressively stronger hints — you still solve it.

I'm working on the problem **Sales Person** (Databases). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🎨 Explain the approach visually

See the technique, not just code.

Explain the optimal approach to **Sales Person** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔍 Review my solution

Catch bugs, edge cases, sub-optimality.

I'll paste my solution to **Sales Person**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔁 Drill the pattern

Lock in recognition with look-alikes.

Give me 2 problems that use the SAME underlying pattern as **Sales Person**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes