{
  "assessmentTests": {
    "sql_test": {
      "name": "SQL Test",
      "desc": "30 scenario questions on filtering, joins, aggregation, subqueries and window functions — find out whether your SQL matches what a job posting means by SQL proficiency.",
      "recommendation": "Your SQL skills profile",
      "results": {
        "beginner": {
          "name": "Beginner",
          "desc": "You can write a working SELECT statement and filter on a few conditions, but the questions you missed cluster around NULL handling and join mechanics rather than syntax — comparing a column to NULL with =, what LEFT JOIN actually preserves, how BETWEEN's boundaries work. None of this is about being bad at databases; these are the specific rules that trip up people who learned SQL by trial and error rather than from the standard. They matter at work because each one is where a query returns a plausible-looking but wrong row count.",
          "recommendation": "Start with three things, in this order: why WHERE col = NULL never matches anything (and IS NULL is required instead), how INNER JOIN drops unmatched rows while LEFT JOIN keeps them, and the exact boundaries BETWEEN includes. Mode Analytics' SQL tutorial and the PostgreSQL documentation both cover all three with runnable examples."
        },
        "intermediate": {
          "name": "Intermediate",
          "desc": "You handle everyday reporting queries comfortably — joins, GROUP BY, straightforward filtering — and would not be slowed down by routine dashboard or ad-hoc analysis work. The gap between here and Advanced is mostly in what happens when clauses interact: a WHERE clause on the joined table quietly turning a LEFT JOIN back into an INNER JOIN, a join that fans out row counts before an aggregate gets applied to them, a NOT IN that silently returns nothing because one NULL slipped into the subquery. Those are the kind of bugs that pass a quick eyeball check and only show up when someone compares the total to a different report.",
          "recommendation": "Focus on how clauses interact rather than what each one does alone: WHERE filtering on a LEFT JOIN's right-hand columns, row multiplication from one-to-many joins before you aggregate, and why NOT IN breaks in the presence of NULLs (EXISTS usually does not). Then HAVING vs WHERE, since that split trips up people who already know both clauses individually."
        },
        "advanced": {
          "name": "Advanced",
          "desc": "This is the level most job postings mean by \"strong SQL.\" You read a multi-join query and can predict its row count before running it, you know why a result set changed rather than only that it did, and you reach for a CTE or a window function instead of a nested subquery when that is the clearer tool. What separates this band from the top is the defensive side of the work: knowing which ranking function to use when ties matter, what a transaction isolates from a concurrent session, and what a missing ON DELETE rule actually does at the database level.",
          "recommendation": "Push into the parts that protect data other people also touch: the difference between RANK, DENSE_RANK and ROW_NUMBER under ties, what COMMIT actually makes visible and to whom, and foreign key behavior on DELETE. Use The Index newsletter's or SQL for Devs' deep dives on window functions and transaction isolation as the next stop for both."
        },
        "expert": {
          "name": "Expert",
          "desc": "You scored at the top of every section — filtering and NULL semantics, joins and set operations, aggregation and subqueries, and window functions, CTEs and constraints. Practically, that means you can be handed a stranger's multi-join report query and explain why it returns the row count it does, not just what the syntax says it should do, which is the harder and more valuable skill. At this level the query language is rarely the limiting factor; the limit is usually schema design or the size of the data underneath it.",
          "recommendation": "The returns are now in execution plans and design: reading EXPLAIN output before assuming a query is slow, indexing strategy as a tradeoff against write cost rather than a free win, and normalization decisions that hold up as a schema grows. If you are being screened for a role, describe a query bug like the join fan-out or NOT IN/NULL trap that you found in production rather than naming SQL features — it demonstrates the reasoning, not just the vocabulary."
        }
      },
      "questions": [
        {
          "question": "A table has a nullable column age. You run SELECT * FROM users WHERE age = NULL. How many rows does this return, even if several rows have age set to NULL?",
          "options": [
            {
              "icon": "",
              "label": "Every row where age is NULL, because = matches NULL like any other value"
            },
            {
              "icon": "",
              "label": "Zero — comparing anything to NULL with = produces UNKNOWN, never TRUE, so no rows match; IS NULL is required instead"
            },
            {
              "icon": "",
              "label": "A syntax error — NULL cannot appear on the right side of ="
            },
            {
              "icon": "",
              "label": "Every row in the table, because NULL comparisons default to TRUE"
            }
          ]
        },
        {
          "question": "You run SELECT DISTINCT department, role FROM employees. What does DISTINCT remove duplicates of?",
          "options": [
            {
              "icon": "",
              "label": "The combination of department and role together — a row is only removed if both columns match another row exactly"
            },
            {
              "icon": "",
              "label": "Duplicate department values only, keeping every role"
            },
            {
              "icon": "",
              "label": "Duplicate role values only, keeping every department"
            },
            {
              "icon": "",
              "label": "Nothing — DISTINCT only works with a single column"
            }
          ]
        },
        {
          "question": "A column name is filtered with WHERE name LIKE 'A_'. Which of these values matches: 'A', 'Al', 'Ana', 'Ally'?",
          "options": [
            {
              "icon": "",
              "label": "'A' — the underscore is optional and matches zero or more characters"
            },
            {
              "icon": "",
              "label": "'Al' — the underscore matches exactly one character, so LIKE 'A_' matches any two-character string starting with A"
            },
            {
              "icon": "",
              "label": "'Ana' and 'Ally' — the underscore matches any number of trailing characters"
            },
            {
              "icon": "",
              "label": "All four values match, because LIKE ignores length"
            }
          ]
        },
        {
          "question": "A price column is filtered with WHERE price BETWEEN 10 AND 20. Do rows with price exactly 10 or exactly 20 get included?",
          "options": [
            {
              "icon": "",
              "label": "No — BETWEEN excludes both endpoints"
            },
            {
              "icon": "",
              "label": "Yes — BETWEEN is inclusive on both ends, equivalent to price >= 10 AND price <= 20"
            },
            {
              "icon": "",
              "label": "Only price = 10 is included; the upper bound is exclusive"
            },
            {
              "icon": "",
              "label": "Only price = 20 is included; the lower bound is exclusive"
            }
          ]
        },
        {
          "question": "A table orders has 10 rows, and 3 of them have a NULL shipped_date. What does SELECT COUNT(*) FROM orders return, and what does SELECT COUNT(shipped_date) FROM orders return?",
          "options": [
            {
              "icon": "",
              "label": "10, then 10 — COUNT always counts rows regardless of NULLs"
            },
            {
              "icon": "",
              "label": "7, then 7 — both forms skip NULL rows"
            },
            {
              "icon": "",
              "label": "10, then 7 — COUNT(*) counts every row, COUNT(column) counts only rows where that column is not NULL"
            },
            {
              "icon": "",
              "label": "10, then 3 — COUNT(column) counts only the NULL values"
            }
          ]
        },
        {
          "question": "You run SELECT name, salary FROM employees ORDER BY 2 DESC. What does the 2 refer to?",
          "options": [
            {
              "icon": "",
              "label": "A syntax error — ORDER BY only accepts column names, not numbers"
            },
            {
              "icon": "",
              "label": "The second row of the result"
            },
            {
              "icon": "",
              "label": "A literal value of 2, used as a tiebreaker"
            },
            {
              "icon": "",
              "label": "The second column in the SELECT list, salary — ORDER BY accepts a column's position number as shorthand"
            }
          ]
        },
        {
          "question": "In standard SQL, what does 'Ana' || ' ' || 'Lee' evaluate to?",
          "options": [
            {
              "icon": "",
              "label": "A syntax error — SQL has no concatenation operator"
            },
            {
              "icon": "",
              "label": "3 — || is treated as a boolean OR and returns a count"
            },
            {
              "icon": "",
              "label": "'AnaLee' — || concatenates without preserving spaces"
            },
            {
              "icon": "",
              "label": "'Ana Lee' — || is the standard SQL string concatenation operator"
            }
          ]
        },
        {
          "question": "Which of these is exactly equivalent to WHERE status IN ('open', 'pending', 'review')?",
          "options": [
            {
              "icon": "",
              "label": "WHERE status = 'open' AND status = 'pending' AND status = 'review'"
            },
            {
              "icon": "",
              "label": "WHERE status != 'open' OR status != 'pending' OR status != 'review'"
            },
            {
              "icon": "",
              "label": "WHERE status = 'open' OR status = 'pending' OR status = 'review'"
            },
            {
              "icon": "",
              "label": "WHERE status LIKE 'open,pending,review'"
            }
          ]
        },
        {
          "question": "customers has 100 rows; 20 of them have never placed an order. You run SELECT c.id FROM customers c INNER JOIN orders o ON c.id = o.customer_id. Do the 20 customers with no orders appear in the result?",
          "options": [
            {
              "icon": "",
              "label": "Yes, once each, with o.id shown as NULL"
            },
            {
              "icon": "",
              "label": "Yes, but only if they also appear in a WHERE clause"
            },
            {
              "icon": "",
              "label": "No — INNER JOIN only returns rows that have a match in both tables, so customers with zero orders are dropped entirely"
            },
            {
              "icon": "",
              "label": "Yes, duplicated once per column in orders"
            }
          ]
        },
        {
          "question": "You want every customer whether or not they have orders, so you write SELECT c.id, o.total FROM customers c LEFT JOIN orders o ON c.id = o.customer_id WHERE o.total > 100. Does this still return customers with zero orders?",
          "options": [
            {
              "icon": "",
              "label": "No — filtering on o.total in the WHERE clause discards the NULL rows LEFT JOIN produced for unmatched customers, so it behaves like an INNER JOIN"
            },
            {
              "icon": "",
              "label": "Yes — LEFT JOIN always preserves every row from customers no matter what follows"
            },
            {
              "icon": "",
              "label": "Yes, with o.total shown as 0 for customers with no orders"
            },
            {
              "icon": "",
              "label": "No — LEFT JOIN silently converts itself into a RIGHT JOIN when a WHERE clause is added"
            }
          ]
        },
        {
          "question": "An employees table has an id column and a manager_id column that points to another row's id. To list each employee next to their manager's name, you join the table to itself: SELECT e.name, m.name FROM employees e JOIN employees m ON e.manager_id = m.id. What is this pattern called?",
          "options": [
            {
              "icon": "",
              "label": "A cross join — every employee is matched with every manager"
            },
            {
              "icon": "",
              "label": "A recursive join — it fetches the full management chain"
            },
            {
              "icon": "",
              "label": "A self-join — the same table is joined to itself using two different aliases"
            },
            {
              "icon": "",
              "label": "This is invalid SQL — a table cannot be joined to itself"
            }
          ]
        },
        {
          "question": "Two SELECT queries with the same columns are combined with UNION. If both queries return an identical row, how many copies of that row appear in the final result?",
          "options": [
            {
              "icon": "",
              "label": "One — UNION removes duplicate rows across the combined result; UNION ALL would keep both copies"
            },
            {
              "icon": "",
              "label": "Two — UNION keeps every row from both queries"
            },
            {
              "icon": "",
              "label": "Zero — UNION removes any row that appears in both queries"
            },
            {
              "icon": "",
              "label": "It depends on which query listed the row first"
            }
          ]
        },
        {
          "question": "Table sizes has 3 rows and colors has 4 rows. How many rows does SELECT * FROM sizes CROSS JOIN colors return?",
          "options": [
            {
              "icon": "",
              "label": "7 — CROSS JOIN adds the row counts together"
            },
            {
              "icon": "",
              "label": "12 — a CROSS JOIN returns every possible combination of rows from both tables (3 x 4)"
            },
            {
              "icon": "",
              "label": "3 — CROSS JOIN returns one row per row in the first table"
            },
            {
              "icon": "",
              "label": "0 — CROSS JOIN requires an ON condition or it returns nothing"
            }
          ]
        },
        {
          "question": "orders has 1 row for order #100, and order_items has 3 rows for order #100 (one per line item). You run SELECT o.id, o.total FROM orders o JOIN order_items i ON o.id = i.order_id WHERE o.id = 100. How many rows come back for order #100?",
          "options": [
            {
              "icon": "",
              "label": "3 — the join produces one output row per matching order_items row, so order #100's single row is repeated once per line item"
            },
            {
              "icon": "",
              "label": "1 — orders only has one row for order #100, so the join can't produce more"
            },
            {
              "icon": "",
              "label": "4 — one row for the order plus one per line item"
            },
            {
              "icon": "",
              "label": "0 — joining a one-row table to a three-row table on a non-unique key fails"
            }
          ]
        },
        {
          "question": "SELECT c.name, o.id FROM customers c RIGHT JOIN orders o ON c.id = o.customer_id returns the same rows as which of these?",
          "options": [
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM customers c INNER JOIN orders o ON c.id = o.customer_id"
            },
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM orders o LEFT JOIN customers c ON c.id = o.customer_id — swapping the table order and using LEFT JOIN instead of RIGHT JOIN is equivalent"
            },
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM customers c LEFT JOIN orders o ON c.id = o.customer_id"
            },
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM orders o CROSS JOIN customers c"
            }
          ]
        },
        {
          "question": "In standard SQL, you run SELECT department, name, AVG(salary) FROM employees GROUP BY department. Is this a valid query?",
          "options": [
            {
              "icon": "",
              "label": "Yes — GROUP BY only needs to include department because it's listed first"
            },
            {
              "icon": "",
              "label": "No — name is selected but neither aggregated nor listed in GROUP BY, and standard SQL requires every non-aggregated selected column to appear in the GROUP BY clause"
            },
            {
              "icon": "",
              "label": "Yes — SQL automatically picks one arbitrary name per department"
            },
            {
              "icon": "",
              "label": "No — AVG() cannot be combined with GROUP BY in the same query"
            }
          ]
        },
        {
          "question": "You want departments whose average salary exceeds 80000. Which clause filters on an aggregated value like AVG(salary) after grouping — WHERE or HAVING?",
          "options": [
            {
              "icon": "",
              "label": "WHERE — HAVING is only used with UNION queries"
            },
            {
              "icon": "",
              "label": "Either one works identically with aggregate functions"
            },
            {
              "icon": "",
              "label": "Neither — aggregate filtering requires a subquery"
            },
            {
              "icon": "",
              "label": "HAVING — WHERE filters individual rows before grouping happens, HAVING filters groups after aggregation"
            }
          ]
        },
        {
          "question": "You write SELECT salary * 1.1 AS new_salary FROM employees WHERE new_salary > 50000. Does this run?",
          "options": [
            {
              "icon": "",
              "label": "Yes — aliases defined in SELECT are always available to WHERE in the same query"
            },
            {
              "icon": "",
              "label": "Yes, but only for numeric aliases"
            },
            {
              "icon": "",
              "label": "No — AS is not permitted inside a WHERE-filtered query"
            },
            {
              "icon": "",
              "label": "No — WHERE is evaluated before SELECT assigns the alias new_salary, so the alias doesn't exist yet at that point in execution"
            }
          ]
        },
        {
          "question": "SELECT name FROM employees e WHERE salary > (SELECT AVG(salary) FROM employees WHERE department = e.department). Why is this called a correlated subquery?",
          "options": [
            {
              "icon": "",
              "label": "Because it uses a JOIN instead of a WHERE clause"
            },
            {
              "icon": "",
              "label": "The inner subquery references e.department from the outer query, so it must be re-evaluated for every row the outer query considers"
            },
            {
              "icon": "",
              "label": "Because it returns more than one column"
            },
            {
              "icon": "",
              "label": "Because it runs exactly once before the outer query starts"
            }
          ]
        },
        {
          "question": "A subquery SELECT manager_id FROM employees returns some NULL values along with real ids. You run SELECT name FROM employees WHERE id NOT IN (SELECT manager_id FROM employees). What happens?",
          "options": [
            {
              "icon": "",
              "label": "It returns every employee who isn't a manager, ignoring the NULLs"
            },
            {
              "icon": "",
              "label": "It returns zero rows — a single NULL in the NOT IN list makes every comparison UNKNOWN, so no row can satisfy the condition"
            },
            {
              "icon": "",
              "label": "It raises an error because NOT IN cannot be used with subqueries"
            },
            {
              "icon": "",
              "label": "It returns every employee, since NULL is treated as a wildcard"
            }
          ]
        },
        {
          "question": "SELECT name FROM customers c WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id). What does this return?",
          "options": [
            {
              "icon": "",
              "label": "Every customer who has at least one row in orders — EXISTS only checks whether the subquery returns any rows, not what values they contain"
            },
            {
              "icon": "",
              "label": "Every customer, because SELECT 1 always returns true"
            },
            {
              "icon": "",
              "label": "An error, because the subquery selects a number instead of a column name"
            },
            {
              "icon": "",
              "label": "Only customers with exactly one order"
            }
          ]
        },
        {
          "question": "You write SELECT name, (SELECT order_id FROM orders WHERE customer_id = c.id) AS last_order FROM customers c, and a given customer has 3 rows in orders. What happens when this query runs?",
          "options": [
            {
              "icon": "",
              "label": "It returns the first matching order_id and silently ignores the other two"
            },
            {
              "icon": "",
              "label": "It returns a comma-separated list of all three order_ids"
            },
            {
              "icon": "",
              "label": "It returns 3 rows for that customer, one per order"
            },
            {
              "icon": "",
              "label": "It raises an error at runtime — a scalar subquery in the SELECT list must return at most one row, and this one returns three"
            }
          ]
        },
        {
          "question": "Four rows tie for the highest score. Using RANK() ORDER BY score DESC, all four get rank 1. What rank does the next row down get?",
          "options": [
            {
              "icon": "",
              "label": "5 — RANK() leaves a gap equal to the number of tied rows before continuing"
            },
            {
              "icon": "",
              "label": "2 — RANK() always increments by exactly one after any tie"
            },
            {
              "icon": "",
              "label": "1 — every subsequent row also gets rank 1"
            },
            {
              "icon": "",
              "label": "4 — RANK() restarts counting from the number of ties"
            }
          ]
        },
        {
          "question": "Four rows tie for the highest score. Using DENSE_RANK() ORDER BY score DESC, all four get rank 1. What rank does the next row down get?",
          "options": [
            {
              "icon": "",
              "label": "5 — DENSE_RANK() behaves exactly like RANK()"
            },
            {
              "icon": "",
              "label": "1 — DENSE_RANK() assigns the same rank to every remaining row"
            },
            {
              "icon": "",
              "label": "2 — DENSE_RANK() never leaves gaps, so the next distinct value always gets the next consecutive rank"
            },
            {
              "icon": "",
              "label": "3 — DENSE_RANK() skips one rank per tie group"
            }
          ]
        },
        {
          "question": "SUM(amount) OVER (PARTITION BY region ORDER BY amount) is added to a query. What does PARTITION BY region do here?",
          "options": [
            {
              "icon": "",
              "label": "It restarts the running sum separately for each region, instead of accumulating across the whole result set"
            },
            {
              "icon": "",
              "label": "It filters the results to a single region"
            },
            {
              "icon": "",
              "label": "It groups and collapses the rows into one per region, like GROUP BY"
            },
            {
              "icon": "",
              "label": "It sorts the regions alphabetically before summing"
            }
          ]
        },
        {
          "question": "ROW_NUMBER() OVER (ORDER BY score DESC) is applied to five rows, two of which are exactly tied in score. Can two rows ever receive the same row number?",
          "options": [
            {
              "icon": "",
              "label": "Yes — tied rows always share the same row number"
            },
            {
              "icon": "",
              "label": "Only if PARTITION BY is also used"
            },
            {
              "icon": "",
              "label": "It depends on whether the tie is in the first or last position"
            },
            {
              "icon": "",
              "label": "No — ROW_NUMBER() always assigns a unique, strictly increasing integer to every row, even when values are tied"
            }
          ]
        },
        {
          "question": "WITH high_earners AS (SELECT * FROM employees WHERE salary > 100000) SELECT department, COUNT(*) FROM high_earners GROUP BY department. What is high_earners?",
          "options": [
            {
              "icon": "",
              "label": "A common table expression (CTE) — a named, temporary result set that the rest of the query can reference like a table"
            },
            {
              "icon": "",
              "label": "A permanent table created in the database"
            },
            {
              "icon": "",
              "label": "A view that persists after the query finishes"
            },
            {
              "icon": "",
              "label": "A stored procedure that must be called separately"
            }
          ]
        },
        {
          "question": "A column is declared PRIMARY KEY. Can you insert a row where that column is NULL?",
          "options": [
            {
              "icon": "",
              "label": "Yes — PRIMARY KEY only enforces uniqueness, not NULL-ness"
            },
            {
              "icon": "",
              "label": "Yes, but only one NULL row is allowed, same as a UNIQUE constraint"
            },
            {
              "icon": "",
              "label": "No — a PRIMARY KEY column is implicitly NOT NULL, so inserting NULL into it is rejected"
            },
            {
              "icon": "",
              "label": "It depends on whether the column also has a default value"
            }
          ]
        },
        {
          "question": "Inside an open transaction, you run an UPDATE but have not yet run COMMIT. From a second, separate connection to the database, is that update visible?",
          "options": [
            {
              "icon": "",
              "label": "Yes — all connections see every write the instant it runs"
            },
            {
              "icon": "",
              "label": "Yes, but only if the second connection also opens a transaction"
            },
            {
              "icon": "",
              "label": "It depends only on which table was updated"
            },
            {
              "icon": "",
              "label": "No — an uncommitted change is only visible inside the transaction that made it, until COMMIT makes it durable and visible to others"
            }
          ]
        },
        {
          "question": "products.category_id has a FOREIGN KEY constraint referencing categories.id. You try to DELETE a row from categories that still has products pointing to it, with no ON DELETE rule specified. What happens?",
          "options": [
            {
              "icon": "",
              "label": "The category row is deleted and the matching products.category_id values are automatically set to NULL"
            },
            {
              "icon": "",
              "label": "The category row is deleted and every product that referenced it is deleted too"
            },
            {
              "icon": "",
              "label": "The DELETE is rejected — the default foreign key behavior blocks deleting a referenced row while dependent rows still point to it"
            },
            {
              "icon": "",
              "label": "The DELETE succeeds silently, leaving the products' category_id pointing at a category that no longer exists"
            }
          ]
        }
      ],
      "optionOrderVersion": "e0466e547cfd8a45"
    }
  }
}
