Practice set Β· sample.db

SQL Drills, Levels 1–3

42 word problems, no joins, checked against your progress log. Figure out which columns and clauses you need β€” the hint under each one shows the technique if you get stuck, not the finished query. After you attempt a question, mark which review box it belongs in.

0 / 42 attempted
Due for review 0

    Nothing due yet. Mark a box on a question once you've attempted it.

    Box 1 β†’ tomorrow Β· Box 2 β†’ 3 days Β· Box 3 β†’ 1 week Β· Box 4 β†’ 2 weeks Β· Box 5 β†’ 1 month β€” counted from that level's "Completed" date, not from today. Set each level's date next to its heading first; click a box after attempting a question, click the same box again to clear it. Editing a level's date reschedules every question in it at once.

    Schema reference

    customers
    customer_id Β· name Β· city Β· signup_date Β· email
    products
    product_id Β· name Β· category Β· price
    orders
    order_id Β· customer_id Β· order_date Β· status
    order_items
    order_id Β· product_id Β· quantity

    Level 1 β€” Querying a Single Table

    SELECT / WHERE, logical operators, IN / BETWEEN / LIKE, ORDER BY, DISTINCT, LIMIT / OFFSET, NULL checks.

    L1.1 β€” SELECT / WHERE / ANDΒ·ORΒ·NOT / IN / BETWEEN / LIKE
    • In products, which items are in the 'Electronics' category AND cost more than 500? Show name and price, aliasing price as unit_price.
      Not attempted yet
      Hint
      WHERE category = 'Electronics' AND price > 500
    • In customers, list customer_id, name, city for anyone based in Chennai or Delhi β€” OR whose name starts with 'A'.
      Not attempted yet
      Hint
      WHERE city IN ('Chennai','Delhi') OR name LIKE 'A%'
    • In orders, show order_id and status for every order that is not cancelled and was placed sometime in the first half of 2026.
      Not attempted yet
      Hint
      WHERE status NOT IN ('cancelled') AND order_date BETWEEN '2026-01-01' AND '2026-06-30'
    L1.2 β€” ORDER BY (multi-column, alias visibility, positional, NULLS FIRST/LAST)
    • In products, list name and price with the priciest item first, breaking ties alphabetically by name.
      Not attempted yet
      Hint
      ORDER BY price DESC, name ASC
    • In customers, select name as cust_name and signup_date, sorted alphabetically β€” but sort using the alias, not the raw column.
      Not attempted yet
      Hint
      SELECT name AS cust_name ... ORDER BY cust_name
    • In orders, select order_id, order_date, status sorted by column position β€” 3rd column first, then 2nd β€” with any missing status pushed to the bottom.
      Not attempted yet
      Hint
      ORDER BY 3 NULLS LAST, 2
    L1.3 β€” DISTINCT, LIMIT / OFFSET, IS NULL / IS NOT NULL
    • In orders, what distinct values can status take?
      Not attempted yet
      Hint
      SELECT DISTINCT status
    • In products, find the 2nd, 3rd, and 4th most expensive products β€” skip the single priciest one.
      Not attempted yet
      Hint
      ORDER BY price DESC LIMIT 3 OFFSET 1
    • In customers, find everyone with no email on file β€” then flip the query to find everyone who does have one.
      Not attempted yet
      Hint
      WHERE email IS NULL, then WHERE email IS NOT NULL

    Level 2 β€” Functions, Expressions & Data Types

    CAST, arithmetic, string / numeric / date functions, CASE, COALESCE / NULLIF.

    L2.1 β€” Data types, CAST
    • In orders, show order_id, order_date, and order_id converted to text β€” call it order_id_text.
      Not attempted yet
      Hint
      CAST(order_id AS TEXT)
    • In products, show name, price, and price forced into an integer (price_int). What happens to the decimal part?
      Not attempted yet
      Hint
      CAST(price AS INTEGER) β€” truncates, doesn't round
    • In customers, show signup_date next to the same value cast to TEXT. Does anything visibly change in SQLite?
      Not attempted yet
      Hint
      CAST(signup_date AS TEXT)
    L2.2 β€” Arithmetic + integer-division gotcha
    • In order_items, show product_id, quantity, and what quantity would be if every line item doubled.
      Not attempted yet
      Hint
      quantity * 2
    • In products, show name, price, and price split three ways. Does it truncate?
      Not attempted yet
      Hint
      price / 3 β€” result type follows price's stored type
    • In order_items, show order_id, product_id, quantity, and quantity minus one.
      Not attempted yet
      Hint
      quantity - 1
    L2.3 β€” String functions (||, UPPER/LOWER, LENGTH, SUBSTR, INSTR)
    • In customers, build one combined column showing name and city together, separated by ' - '.
      Not attempted yet
      Hint
      name || ' - ' || city
    • In products, show name in all caps alongside its character length.
      Not attempted yet
      Hint
      UPPER(name), LENGTH(name)
    • In customers, pull just the username portion out of each email β€” everything before the @.
      Not attempted yet
      Hint
      SUBSTR(email, 1, INSTR(email, '@') - 1)
    L2.4 β€” Numeric functions (ROUND/CEIL/FLOOR/ABS/MOD/POWER)
    • In products, round every price to one decimal place.
      Not attempted yet
      Hint
      ROUND(price, 1)
    • In order_items, tag each row with quantity mod 3 β€” useful for spotting a pattern across rows.
      Not attempted yet
      Hint
      quantity % 3
    • In products, show each price floored and ceiled side by side.
      Not attempted yet
      Hint
      FLOOR(price), CEIL(price)
    L2.5 β€” Date/time (STRFTIME, JULIANDAY, DATE modifier)
    • In customers, extract just the signup year from signup_date.
      Not attempted yet
      Hint
      STRFTIME('%Y', signup_date)
    • In orders, work out how many days ago each order was placed, relative to right now.
      Not attempted yet
      Hint
      JULIANDAY('now') - JULIANDAY(order_date)
    • In customers, compute the date exactly 30 days after each signup_date.
      Not attempted yet
      Hint
      DATE(signup_date, '+30 days')
    L2.6 β€” CASE (searched + simple)
    • In products, label every product 'Premium' (price β‰₯ 1000), 'Mid' (price β‰₯ 500), or 'Budget' (below that).
      Not attempted yet
      Hint
      searched CASE WHEN price >= 1000 THEN ... WHEN price >= 500 THEN ... ELSE ...
    • In orders, translate each status into a friendlier label: delivered β†’ Done, cancelled β†’ Lost, anything else β†’ Pending.
      Not attempted yet
      Hint
      simple CASE status WHEN 'delivered' THEN ... WHEN 'cancelled' THEN ... ELSE ...
    • In customers, tag each row 'South' if city is Chennai or Bangalore, else 'Other'.
      Not attempted yet
      Hint
      CASE WHEN city IN ('Chennai','Bangalore') THEN 'South' ELSE 'Other' END
    L2.7 β€” NULL functions (COALESCE, NULLIF)
    • In customers, show name and email, replacing any missing email with the text 'no-email'.
      Not attempted yet
      Hint
      COALESCE(email, 'no-email')
    • In orders, do the same for status β€” replace missing values with 'unknown'.
      Not attempted yet
      Hint
      COALESCE(status, 'unknown')
    • In products, compute 100 divided by price, guarding against a divide-by-zero even though it can't happen in this data. What exactly are you guarding against?
      Not attempted yet
      Hint
      100 / NULLIF(price, 0)

    Level 3 β€” Aggregation & Grouping

    Aggregates, GROUP BY, HAVING vs WHERE, conditional aggregation. Stops exactly where your teaching has, ahead of Gate 3.

    L3.1 β€” Aggregate functions (COUNT/SUM/AVG/MIN/MAX, COUNT's three forms)
    • In orders, compare the total row count against the count of non-null status values. Are they the same? Why or why not?
      Not attempted yet
      Hint
      COUNT(*) vs COUNT(status)
    • In order_items, find the total and average quantity across every line item.
      Not attempted yet
      Hint
      SUM(quantity), AVG(quantity)
    • In products, find the cheapest price, the priciest, and how many distinct category values exist.
      Not attempted yet
      Hint
      MIN(price), MAX(price), COUNT(DISTINCT category)
    L3.2 β€” GROUP BY (single/multi-column, NULL grouping)
    • In order_items, find total quantity sold per product_id.
      Not attempted yet
      Hint
      GROUP BY product_id, SUM(quantity)
    • In orders, count how many orders fall into each status.
      Not attempted yet
      Hint
      GROUP BY status, COUNT(*)
    • In customers, count customers per city, busiest city first.
      Not attempted yet
      Hint
      GROUP BY city, COUNT(*) ... ORDER BY COUNT(*) DESC
    L3.3 β€” HAVING vs WHERE
    • In order_items, which product_ids have sold more than 5 units in total?
      Not attempted yet
      Hint
      GROUP BY product_id HAVING SUM(quantity) > 5
    • In orders, ignoring cancelled orders, which status values have at least 2 orders?
      Not attempted yet
      Hint
      WHERE status != 'cancelled' GROUP BY status HAVING COUNT(*) >= 2
    • In customers, ignoring anyone with no email on file, which cities have more than 1 customer?
      Not attempted yet
      Hint
      WHERE email IS NOT NULL GROUP BY city HAVING COUNT(*) > 1
    L3.4 β€” Conditional aggregation
    • In orders, in a single row, show how many orders are 'delivered' and how many are 'cancelled', side by side.
      Not attempted yet
      Hint
      SUM(CASE WHEN status='delivered' THEN 1 ELSE 0 END), SUM(CASE WHEN status='cancelled' THEN 1 ELSE 0 END)
    • In order_items, per product_id, count how many order lines had a quantity greater than 2.
      Not attempted yet
      Hint
      GROUP BY product_id, COUNT(CASE WHEN quantity > 2 THEN 1 END)
    • In products, in a single row, count how many products are 'Electronics' versus everything else.
      Not attempted yet
      Hint
      COUNT(CASE WHEN category='Electronics' THEN 1 END), COUNT(CASE WHEN category!='Electronics' THEN 1 END)
    L2.7's last question is intentionally contrived β€” price never actually hits 0 in this data, so it's testing whether you understand what NULLIF is guarding against, not a real divide-by-zero case.