SQL Practice Questions and Answers
Level: intermediate · ~22 min read · Intent: informational
Audience: backend developers, data analysts, data engineers, technical teams, students, junior developers, career switchers
Prerequisites
- basic familiarity with databases
- basic understanding of tables, rows, and columns
Key takeaways
- The best way to improve in SQL is to practice solving real query problems, not just memorize syntax. Strong SQL skills come from understanding how to filter, join, group, sort, and reason about data shape.
- Good SQL practice questions should test both correctness and thinking. The strongest learners explain what the query needs to return, identify the right tables and relationships, and then choose the SQL pattern that fits.
FAQ
- What is the best way to practice SQL?
- The best way to practice SQL is to solve real query problems repeatedly, explain what each query should return, and review why the answer works instead of only memorizing syntax.
- Should SQL practice include JOINs and GROUP BY?
- Yes. Good SQL practice should include filtering, sorting, joins, aggregates, GROUP BY, HAVING, subqueries, and NULL handling because these appear constantly in real SQL work.
- Are SQL practice questions useful for interviews?
- Yes. SQL practice questions are one of the best ways to prepare for interviews because they improve both query-writing speed and your ability to explain your reasoning clearly.
- How do I know if my SQL answer is correct?
- A SQL answer is more likely to be correct when you define the expected output clearly, check row counts, think about duplicates and NULL values, and make sure the query matches the real business question.
SQL gets easier when you stop thinking about it as a list of commands and start thinking about it as a way to answer questions about data.
That is why practice matters so much.
You do not really learn SQL by only reading definitions of:
SELECTWHEREJOINGROUP BYORDER BY
You learn SQL by using those tools to answer real questions like:
- which customers placed the most orders?
- which employees earn above the department average?
- which products have never been sold?
- how many users signed up last month?
- what was the previous order amount for each customer?
- which emails appear more than once?
That is what SQL practice questions are really for.
They train you to:
- understand the data model
- identify the correct output
- choose the right SQL pattern
- and avoid common mistakes with duplicates, NULL values, grouping, and joins
This guide gives you practical SQL practice questions and answers, with explanations designed to help you understand the reasoning instead of only copying the query.
Why SQL practice matters more than memorization
A lot of people try to learn SQL by memorizing syntax first.
That helps a little, but it is not enough.
The real challenge in SQL is usually not remembering that GROUP BY exists.
The real challenge is knowing:
- when you need
GROUP BY - when you need
HAVING - when a
LEFT JOINis better than anINNER JOIN - when duplicates are caused by joins
- when NULL changes the result
- and what one row in the final output should actually represent
That is why practice questions are so powerful.
They train your thinking, not only your memory.
The more real SQL questions you solve, the more naturally you start recognizing patterns.
The most important rule
Before working through practice questions, remember this:
Always define what one row in the output should represent before you write the query.
That is one of the most important SQL habits you can build.
For example:
- one row per customer
- one row per order
- one row per department
- one row per product
- one row per month
If you do not define that clearly, it becomes very easy to:
- join the wrong tables
- group at the wrong level
- count duplicates
- or return the wrong result shape
So a strong SQL workflow always starts by asking:
- what should each output row mean?
That question will help you solve almost every practice problem more accurately.
Simple example schema used in these questions
To keep the questions practical, imagine you are working with tables like these.
customers
customer_idcustomer_nameemailcountrycreated_at
orders
order_idcustomer_idorder_datetotal_amountstatus
products
product_idproduct_namecategoryprice
order_items
order_item_idorder_idproduct_idquantityunit_price
employees
employee_idemployee_namedepartmentsalarymanager_id
These are common tables in SQL practice and interviews because they make it easy to test filtering, joining, aggregation, and relationships.
SQL Practice Question 1: Return all customers
Question:
Write a query to return all rows and columns from the customers table.
Answer
SELECT *
FROM customers;
Explanation
This is the most basic SQL query pattern.
It says:
- select all columns
- from the
customerstable
This is useful for previewing data, but in real applications you often want to select only the columns you actually need.
SQL Practice Question 2: Return specific columns
Question:
Write a query to return only customer_name and email from the customers table.
Answer
SELECT customer_name, email
FROM customers;
Explanation
This is better than SELECT * when you only need a few fields.
It keeps the query:
- clearer
- more focused
- and often more efficient
This is a good habit to build early.
SQL Practice Question 3: Filter rows with WHERE
Question:
Write a query to return customers from South Africa only.
Answer
SELECT
customer_id,
customer_name,
email,
country
FROM customers
WHERE country = 'South Africa';
Explanation
WHERE filters rows before they are returned.
This query keeps only customers where country is exactly 'South Africa'.
This is one of the most common SQL patterns.
SQL Practice Question 4: Sort results
Question:
Write a query to list all products from most expensive to least expensive.
Answer
SELECT
product_id,
product_name,
category,
price
FROM products
ORDER BY price DESC;
Explanation
ORDER BY price DESC sorts rows by price from highest to lowest.
This is useful for:
- top-priced products
- rankings
- and admin views
If you wanted cheapest first, you would use ASC instead.
SQL Practice Question 5: Return the first 5 rows
Question:
Write a query to return the first 5 products.
Answer
SELECT
product_id,
product_name,
price
FROM products
LIMIT 5;
Explanation
LIMIT 5 means:
- return only 5 rows
This is often used for:
- previews
- top-N queries
- debugging
- and pagination
In real applications, LIMIT is usually best used with ORDER BY.
SQL Practice Question 6: Count all customers
Question:
Write a query to count how many customers exist.
Answer
SELECT COUNT(*) AS customer_count
FROM customers;
Explanation
COUNT(*) counts rows.
This query returns one row with one value:
- the total number of customer records
This is one of the most common beginner SQL exercises.
SQL Practice Question 7: Count customers by country
Question:
Write a query to count how many customers exist in each country.
Answer
SELECT
country,
COUNT(*) AS customer_count
FROM customers
GROUP BY country;
Explanation
This query groups rows by country and counts how many rows exist in each group.
This is a very important SQL pattern:
GROUP BYcreates groups- aggregate functions like
COUNTsummarize them
SQL Practice Question 8: Filter grouped results with HAVING
Question:
Write a query to return only countries that have more than 10 customers.
Answer
SELECT
country,
COUNT(*) AS customer_count
FROM customers
GROUP BY country
HAVING COUNT(*) > 10;
Explanation
HAVING filters grouped results after aggregation.
This is different from WHERE, which filters rows before grouping.
This is one of the most common SQL comparison concepts:
WHEREfor raw rowsHAVINGfor grouped results
SQL Practice Question 9: INNER JOIN two tables
Question:
Write a query to return order IDs and customer names for all matching orders and customers.
Answer
SELECT
o.order_id,
o.order_date,
c.customer_name
FROM orders o
INNER JOIN customers c
ON o.customer_id = c.customer_id;
Explanation
This query joins:
orders- with
customers
using the shared customer_id field.
INNER JOIN returns only rows that match in both tables.
This is one of the most important SQL skills.
SQL Practice Question 10: LEFT JOIN to keep unmatched rows
Question:
Write a query to return all customers and any matching orders they may have.
Answer
SELECT
c.customer_id,
c.customer_name,
o.order_id,
o.order_date,
o.total_amount
FROM customers c
LEFT JOIN orders o
ON c.customer_id = o.customer_id;
Explanation
LEFT JOIN keeps all rows from the left table:
customers
If a customer has no order, the order columns become NULL.
This is very useful when you want:
- all customers
- including customers with no orders yet
SQL Practice Question 11: Find customers with no orders
Question:
Write a query to return customers who have never placed an order.
Answer
SELECT
c.customer_id,
c.customer_name,
c.email
FROM customers c
LEFT JOIN orders o
ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;
Explanation
This is a classic SQL pattern.
It works because:
LEFT JOINkeeps all customers- customers with no matching orders get
NULLin order columns WHERE o.order_id IS NULLkeeps only those unmatched rows
This is a very common interview question too.
SQL Practice Question 12: Find duplicate emails
Question:
Write a query to return email addresses that appear more than once in the customers table.
Answer
SELECT
email,
COUNT(*) AS duplicate_count
FROM customers
GROUP BY email
HAVING COUNT(*) > 1;
Explanation
This query:
- groups rows by
email - counts how many times each email appears
- returns only those groups with more than one row
This is the standard SQL pattern for finding duplicates.
SQL Practice Question 13: Find the highest salary
Question:
Write a query to return the highest salary in the employees table.
Answer
SELECT MAX(salary) AS highest_salary
FROM employees;
Explanation
MAX(salary) returns the largest value in the salary column.
This is one of the most basic aggregate queries.
SQL Practice Question 14: Find the second highest salary
Question:
Write a query to return the second highest salary in the employees table.
Answer
SELECT MAX(salary) AS second_highest_salary
FROM employees
WHERE salary < (
SELECT MAX(salary)
FROM employees
);
Explanation
The inner query finds the highest salary.
The outer query then finds the maximum salary below that value.
This is a classic SQL interview and practice problem because it tests:
- subqueries
- aggregate functions
- logical problem-solving
SQL Practice Question 15: Average salary by department
Question:
Write a query to return the average salary for each department.
Answer
SELECT
department,
AVG(salary) AS avg_salary
FROM employees
GROUP BY department;
Explanation
This groups employees by department and calculates the average salary in each group.
This is a common reporting pattern.
SQL Practice Question 16: Employees above department average
Question:
Write a query to return employees whose salary is above the average salary of their own department.
Answer
SELECT
e.employee_id,
e.employee_name,
e.department,
e.salary
FROM employees e
WHERE e.salary > (
SELECT AVG(e2.salary)
FROM employees e2
WHERE e2.department = e.department
);
Explanation
This is a correlated subquery.
For each employee row, the subquery calculates:
- the average salary in that employee’s department
Then the outer query keeps only employees whose salary is above that average.
This is a very strong SQL practice question because it introduces more realistic logic.
SQL Practice Question 17: Total sales per product
Question:
Write a query to return total quantity sold per product.
Answer
SELECT
p.product_id,
p.product_name,
SUM(oi.quantity) AS total_quantity_sold
FROM products p
INNER JOIN order_items oi
ON p.product_id = oi.product_id
GROUP BY
p.product_id,
p.product_name;
Explanation
This query joins:
- products
- to order_items
Then it groups by product and sums the quantity.
This is a common example of:
- joins
- aggregation
- and one-to-many relationships
SQL Practice Question 18: Revenue per product
Question:
Write a query to return total revenue per product using quantity * unit_price.
Answer
SELECT
p.product_id,
p.product_name,
SUM(oi.quantity * oi.unit_price) AS total_revenue
FROM products p
INNER JOIN order_items oi
ON p.product_id = oi.product_id
GROUP BY
p.product_id,
p.product_name;
Explanation
This calculates revenue at the order item level, then sums it per product.
This is a very practical SQL exercise because it combines:
- arithmetic expressions
- grouping
- and joins
SQL Practice Question 19: Top 5 customers by revenue
Question:
Write a query to return the top 5 customers by total order revenue.
Answer
SELECT
c.customer_id,
c.customer_name,
SUM(o.total_amount) AS total_revenue
FROM customers c
INNER JOIN orders o
ON c.customer_id = o.customer_id
GROUP BY
c.customer_id,
c.customer_name
ORDER BY total_revenue DESC
LIMIT 5;
Explanation
This is a classic top-N query.
It:
- joins customers to orders
- sums total order value per customer
- sorts by revenue descending
- returns only the top 5
This is a very realistic SQL reporting task.
SQL Practice Question 20: Latest order per customer using a window function
Question:
Write a query to return the latest order for each customer.
Answer
WITH ranked_orders AS (
SELECT
o.*,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY order_date DESC, order_id DESC
) AS rn
FROM orders o
)
SELECT
order_id,
customer_id,
order_date,
total_amount,
status
FROM ranked_orders
WHERE rn = 1;
Explanation
This uses ROW_NUMBER() to rank each customer’s orders from newest to oldest.
Then:
WHERE rn = 1keeps only the latest order for each customer.
This is one of the most useful real-world SQL patterns.
SQL Practice Question 21: Find previous order amount with LAG
Question:
Write a query to return each customer’s orders along with the previous order amount.
Answer
SELECT
customer_id,
order_id,
order_date,
total_amount,
LAG(total_amount) OVER (
PARTITION BY customer_id
ORDER BY order_date, order_id
) AS previous_order_amount
FROM orders;
Explanation
LAG looks backward within each customer’s order history.
This is useful for:
- comparing purchases over time
- change detection
- and customer behavior analysis
This is a strong intermediate SQL practice question.
SQL Practice Question 22: Use CASE for categorization
Question:
Write a query to classify products into price bands:
- Expensive if price >= 1000
- Mid Range if price >= 200 and < 1000
- Budget otherwise
Answer
SELECT
product_id,
product_name,
price,
CASE
WHEN price >= 1000 THEN 'Expensive'
WHEN price >= 200 THEN 'Mid Range'
ELSE 'Budget'
END AS price_band
FROM products;
Explanation
CASE lets you build conditional labels in SQL.
This is useful in:
- reporting
- classification
- business rules
- and dashboard logic
SQL Practice Question 23: Handle NULL values with COALESCE
Question:
Write a query to return customer names and phone numbers, showing 'No phone number' when the phone number is NULL.
Answer
SELECT
customer_name,
COALESCE(phone_number, 'No phone number') AS phone_display
FROM customers;
Explanation
COALESCE returns the first non-NULL value.
This is one of the most useful SQL NULL-handling tools.
It is commonly used for:
- display values
- fallback logic
- and replacing NULL where a clearer result is needed
SQL Practice Question 24: Count customers with zero orders
Question:
Write a query to return all customers and how many orders each customer has, including customers with zero orders.
Answer
SELECT
c.customer_id,
c.customer_name,
COUNT(o.order_id) AS order_count
FROM customers c
LEFT JOIN orders o
ON c.customer_id = o.customer_id
GROUP BY
c.customer_id,
c.customer_name;
Explanation
This is a very important SQL pattern.
Because it uses:
LEFT JOIN- and
COUNT(o.order_id)
customers with no orders will correctly get:
0
If you used COUNT(*) here, the result would be misleading for unmatched rows.
SQL Practice Question 25: Find products never ordered
Question:
Write a query to return products that have never appeared in order_items.
Answer
SELECT
p.product_id,
p.product_name
FROM products p
LEFT JOIN order_items oi
ON p.product_id = oi.product_id
WHERE oi.order_item_id IS NULL;
Explanation
This uses the same unmatched-row pattern as “customers with no orders.”
It is one of the most useful SQL anti-join style patterns:
- keep all products
- then return only those with no match
SQL Practice Question 26: Monthly order totals
Question:
Write a query to return total revenue per month.
Answer
SELECT
DATE_TRUNC('month', order_date) AS order_month,
SUM(total_amount) AS total_revenue
FROM orders
GROUP BY DATE_TRUNC('month', order_date)
ORDER BY order_month;
Explanation
This groups orders by month and sums total revenue.
The exact month-truncation function varies by database, but the reporting pattern is very common:
- group by time period
- calculate totals
- sort chronologically
SQL Practice Question 27: Customers who ordered more than 3 times
Question:
Write a query to return customers who placed more than 3 orders.
Answer
SELECT
customer_id,
COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
HAVING COUNT(*) > 3;
Explanation
This is a classic grouped filter problem.
Use:
GROUP BYto form customer groupsCOUNT(*)to count ordersHAVINGto keep only customers above the threshold
This is one of the most common SQL practice patterns.
SQL Practice Question 28: Rank employees by salary within department
Question:
Write a query to rank employees by salary inside each department, highest salary first.
Answer
SELECT
employee_id,
employee_name,
department,
salary,
RANK() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS salary_rank
FROM employees;
Explanation
This uses a window function to create a rank inside each department.
This is useful for:
- leaderboards
- internal rankings
- top performers
- and per-group comparisons
It is also good SQL interview practice.
SQL Practice Question 29: Remove duplicates while keeping one row
Question:
Suppose a table contains duplicate emails. Write a query pattern to identify duplicates and keep only one row per email.
Answer
WITH ranked_customers AS (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY email
ORDER BY customer_id
) AS rn
FROM customers
)
SELECT *
FROM ranked_customers
WHERE rn = 1;
Explanation
This query does not delete duplicates yet.
It identifies the first row per email using ROW_NUMBER().
This is safer because you can inspect the result first.
This is a very strong SQL practice pattern for:
- deduplication
- cleanup
- and data quality work
SQL Practice Question 30: Explain why a query result is duplicated after a join
Question:
You join customers to orders and see the same customer name repeated multiple times. Why?
Answer
Because one customer can have many orders.
A join returns one result row per match. So if one customer matches three orders, that customer appears three times.
Explanation
This is one of the most important SQL concepts:
- joins follow relationship cardinality
If the relationship is one-to-many, row multiplication is expected.
This is not a bug unless the final output was supposed to be one row per customer. If that was the goal, then you usually need:
- grouping
- aggregation
- window functions
- or a different query structure
This is an excellent SQL reasoning question because it tests understanding, not just syntax.
How to get more value from SQL practice questions
SQL practice becomes much more useful when you do more than copy the final answer.
A stronger practice workflow looks like this:
1. Define the result in plain language
What should one row represent?
2. Identify the table or tables
Which tables hold the needed data?
3. Think about relationships
Do you need a join? Is the relationship one-to-many?
4. Decide whether you need filtering, grouping, sorting, or ranking
This helps choose the right SQL pattern.
5. Write the query
Try it before checking the answer.
6. Explain why it works
This is where real learning happens.
That method improves SQL much faster than passive reading.
Common SQL mistakes these practice questions help fix
Working through real SQL questions helps expose recurring mistakes like:
- using
WHEREwhenHAVINGis required - using
INNER JOINwhenLEFT JOINis needed - forgetting that one-to-many joins multiply rows
- using
COUNT(*)whenCOUNT(column_name)is more appropriate - mishandling NULL values
- grouping at the wrong level
- forgetting stable ordering when using
LIMIT - and solving row-by-row problems without considering window functions
These are exactly the kinds of mistakes practice is supposed to fix.
How to keep improving after these questions
Once you are comfortable with the questions in this guide, the next best areas to practice are:
- more join problems
- duplicate cleanup
- grouped reporting
- window functions
- date filtering
- subqueries
- CTEs
- performance reasoning
- and execution plan basics
That is the natural progression from beginner-to-intermediate SQL.
FAQ
What is the best way to practice SQL?
The best way to practice SQL is to solve real query problems repeatedly, explain what each query should return, and review why the answer works instead of only memorizing syntax.
Should SQL practice include JOINs and GROUP BY?
Yes. Good SQL practice should include filtering, sorting, joins, aggregates, GROUP BY, HAVING, subqueries, and NULL handling because these appear constantly in real SQL work.
Are SQL practice questions useful for interviews?
Yes. SQL practice questions are one of the best ways to prepare for interviews because they improve both query-writing speed and your ability to explain your reasoning clearly.
How do I know if my SQL answer is correct?
A SQL answer is more likely to be correct when you define the expected output clearly, check row counts, think about duplicates and NULL values, and make sure the query matches the real business question.
Final thoughts
SQL practice questions are valuable because they teach you to think in data, not just commands.
The real goal is not to memorize 100 query templates. The real goal is to become comfortable answering questions like:
- what should the result look like?
- which tables hold the data?
- what does one row represent?
- how do joins affect row count?
- when do I group?
- when do I rank?
- how do NULL values affect the answer?
Once you start thinking that way, SQL becomes much easier to learn and much easier to use well.
That is why practice matters so much.
Not because it helps you remember syntax alone, but because it helps you recognize the patterns that appear in real SQL work again and again.