How to Use This Practice Test

This practice test checks your understanding of standard SQL across the most commonly tested topics: the SELECT statement and logical clause order, filtering with WHERE, the different JOIN types, NULL handling, aggregate functions, GROUP BY and HAVING, subqueries, set operations (UNION, INTERSECT, EXCEPT), and the basics of window functions. Work through Section A (multiple choice) and Section B (write-the-query) using only the reference schema below, write down your answers, and then self-check against the Answer Key. Every question is numbered so you can match each answer to its question. The example queries follow ANSI/standard SQL and run on most major databases (PostgreSQL, SQL Server, modern MySQL/MariaDB, SQLite, Oracle).

A relational database schema diagram with SQL query examples

Reference Schema

All questions below reference these three related tables

customers

One row per customer

Columns: customer_id (INTEGER, primary key), name (VARCHAR), country (VARCHAR), signup_date (DATE).

products

One row per product

Columns: product_id (INTEGER, primary key), product_name (VARCHAR), category (VARCHAR), unit_price (DECIMAL).

orders

One row per order line

Columns: order_id (INTEGER, primary key), customer_id (INTEGER, references customers), product_id (INTEGER, references products), quantity (INTEGER), order_date (DATE). The line total is quantity * unit_price after joining to products.

Section A: Multiple Choice

Choose the single best answer for each of the 10 questions

A1. Logical clause order

In which order are the clauses of a single SELECT query logically evaluated?

  • A. SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY
  • B. FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
  • C. FROM → SELECT → WHERE → GROUP BY → ORDER BY → HAVING
  • D. WHERE → FROM → GROUP BY → SELECT → HAVING → ORDER BY

A2. JOIN types

A query joins customers to orders and you need every customer in the result, including those who have never placed an order. Which join do you use (with customers on the left)?

  • A. INNER JOIN
  • B. LEFT OUTER JOIN
  • C. RIGHT OUTER JOIN
  • D. CROSS JOIN

A3. NULL comparison

Which predicate correctly returns rows where country has no value?

  • A. WHERE country = NULL
  • B. WHERE country != NULL
  • C. WHERE country IS NULL
  • D. WHERE country = ''

A4. COUNT and NULLs

For a column category that contains some NULL values, how do COUNT(*) and COUNT(category) differ?

  • A. They are always equal
  • B. COUNT(*) counts all rows; COUNT(category) counts only non-NULL category values
  • C. COUNT(category) counts all rows; COUNT(*) skips NULLs
  • D. Both ignore NULLs and duplicates

A5. WHERE vs HAVING

Which statement about WHERE and HAVING is correct?

  • A. WHERE filters individual rows before grouping; HAVING filters groups after aggregation
  • B. HAVING runs before WHERE
  • C. You can use aggregate functions in WHERE
  • D. HAVING can only be used without GROUP BY

A6. GROUP BY rule

In standard SQL, a non-aggregated column in the SELECT list of a grouped query must also appear in:

  • A. The ORDER BY clause
  • B. The GROUP BY clause
  • C. The HAVING clause
  • D. A subquery

A7. SUM over no rows

If SUM(quantity) is applied to a result set that contains zero matching rows (no GROUP BY), what does it return?

  • A. 0
  • B. An error
  • C. NULL
  • D. An empty string

A8. DISTINCT vs GROUP BY

Which pair of queries returns the same set of distinct country values?

  • A. SELECT DISTINCT country FROM customers and SELECT country FROM customers GROUP BY country
  • B. SELECT country FROM customers and SELECT DISTINCT country FROM customers
  • C. SELECT COUNT(country) FROM customers and SELECT DISTINCT country FROM customers
  • D. None of these are equivalent

A9. UNION vs UNION ALL

What is the difference between UNION and UNION ALL?

  • A. UNION keeps duplicate rows; UNION ALL removes them
  • B. UNION removes duplicate rows; UNION ALL keeps all rows including duplicates
  • C. They are identical
  • D. UNION ALL sorts the result; UNION does not

A10. Indexes

Which statement about a B-tree index on orders(customer_id) is most accurate?

  • A. It guarantees queries run instantly regardless of the predicate
  • B. It can speed up equality and range lookups on customer_id but adds overhead to writes
  • C. It removes the need for a WHERE clause
  • D. It only helps with ORDER BY, never with filtering

Section B: Write the Query

Write a single standard-SQL query for each of the 8 tasks, using the reference schema. Difficulty increases as you go.

B1. Basic projection and ordering

Beginner

List the name and country of every customer, sorted alphabetically by name.

B2. Filtering

Beginner

Return all products in the 'Electronics' category with a unit_price greater than 100, showing product name and price, most expensive first.

B3. Inner join

Intermediate

For every order, show the customer name, the product name, and the quantity. Only include orders that have a matching customer and product.

B4. Left join to find missing rows

Intermediate

List the names of customers who have never placed an order.

B5. Aggregation with GROUP BY

Intermediate

For each product category, compute the total quantity ordered. Show the category and the total, ordered by total descending.

B6. GROUP BY + HAVING

Intermediate

Find customers who have placed more than 5 orders. Show the customer name and their order count.

B7. Subquery

Advanced

List the products whose unit_price is above the average unit price across all products.

B8. Window function

Advanced

For each order, show the order_id, customer_id, order_date, and a per-customer sequence number that ranks the customer's orders from earliest to latest order_date.

Answer Key & Explanations

Correct answers for Section A and example queries for Section B

A

Section A — Multiple Choice Answers

  • A1 → B. SQL is logically evaluated FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY, which is why SELECT aliases generally cannot be used in WHERE.
  • A2 → B. A LEFT OUTER JOIN keeps every row from the left table (customers) and fills NULLs where no matching order exists.
  • A3 → C. NULL is not equal to anything, including NULL, so you must use IS NULL; = NULL never returns true.
  • A4 → B. COUNT(*) counts rows, while COUNT(category) ignores rows where category is NULL.
  • A5 → A. WHERE filters rows before grouping/aggregation; HAVING filters the resulting groups and may reference aggregates.
  • A6 → B. Any non-aggregated SELECT column in a grouped query must appear in the GROUP BY clause in standard SQL.
  • A7 → C. Aggregates other than COUNT return NULL over an empty set; SUM of no rows is NULL (use COALESCE to get 0).
  • A8 → A. SELECT DISTINCT country and grouping by country both collapse to one row per distinct value.
  • A9 → B. UNION removes duplicate rows; UNION ALL keeps all rows and is faster because it skips the de-duplication step.
  • A10 → B. An index speeds up equality/range lookups and joins on the indexed column but slows down inserts/updates/deletes that must maintain it.
B1

Basic projection and ordering

SELECT name, country
FROM customers
ORDER BY name;

SELECT chooses the two columns and ORDER BY sorts ascending by name (ASC is the default).

B2

Filtering

SELECT product_name, unit_price
FROM products
WHERE category = 'Electronics'
  AND unit_price > 100
ORDER BY unit_price DESC;

Two conditions are combined with AND in the WHERE clause; DESC sorts the most expensive products first.

B3

Inner join

SELECT c.name, p.product_name, o.quantity
FROM orders AS o
JOIN customers AS c ON c.customer_id = o.customer_id
JOIN products  AS p ON p.product_id  = o.product_id
ORDER BY o.order_id;

Two INNER JOINs link orders to customers and products; only orders with matches on both keys appear.

B4

Left join to find missing rows

SELECT c.name
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.customer_id
WHERE o.order_id IS NULL;

The LEFT JOIN keeps all customers; the IS NULL test on the order key isolates customers with no matching order. (NOT IN / NOT EXISTS are valid alternatives.)

B5

Aggregation with GROUP BY

SELECT p.category, SUM(o.quantity) AS total_quantity
FROM orders AS o
JOIN products AS p ON p.product_id = o.product_id
GROUP BY p.category
ORDER BY total_quantity DESC;

Rows are grouped by category and SUM aggregates the quantity within each group; the alias is used in ORDER BY, which runs after SELECT.

B6

GROUP BY + HAVING

SELECT c.name, COUNT(*) AS order_count
FROM customers AS c
JOIN orders AS o ON o.customer_id = c.customer_id
GROUP BY c.customer_id, c.name
HAVING COUNT(*) > 5
ORDER BY order_count DESC;

HAVING filters the groups by an aggregate (the count); WHERE cannot do this because aggregation has not happened yet. Grouping by customer_id keeps the count correct even if two customers share a name.

B7

Subquery

SELECT product_name, unit_price
FROM products
WHERE unit_price > (SELECT AVG(unit_price) FROM products)
ORDER BY unit_price DESC;

The scalar subquery computes the overall average once, and the outer query keeps only products priced above it.

B8

Window function

SELECT order_id,
       customer_id,
       order_date,
       ROW_NUMBER() OVER (
           PARTITION BY customer_id
           ORDER BY order_date
       ) AS order_seq
FROM orders;

ROW_NUMBER assigns 1, 2, 3, ... within each customer (PARTITION BY) ordered by order_date, without collapsing rows the way GROUP BY would. Use RANK() or DENSE_RANK() if ties on the same date should share a number.

Related Resources

Continue practicing and deepen your data skills

Python Practice Test

Test your Python fundamentals with multiple-choice questions and coding tasks, complete with a worked answer key.

Start Test

Machine Learning Practice Test

Check your understanding of core machine learning concepts and workflows with a self-graded practice test.

Start Test

Data Science with Python Cheat Sheet

A quick reference for pandas, NumPy, and common data-wrangling patterns that pair well with SQL.

View Cheat Sheet

Data Science Course

Build end-to-end data skills, from SQL and Python to analysis and modeling, in our structured course.

Explore Course