SELECT Practice
Hands-on practice session: SELECT queries with filtering, sorting, and NULL handling.
Goals
- Apply
SELECT,WHERE,ORDER BY,LIMIT, andDISTINCTto answer real questions about DVD Rental data - Use
LIKE/ILIKEfor flexible text search on film titles and actor names - Combine
BETWEEN,IN, and compoundAND/ORconditions in a single query - Identify and filter rows with
NULLvalues usingIS NULLandIS NOT NULL - Write multi-column
ORDER BYwith mixedASC/DESCdirections
Warm-up
You have 5 minutes. Without checking notes, write a query from memory that:
- Selects
title,rating, andlengthfrom thefilmtable - Filters for films rated
'PG' - Orders by
lengthdescending - Returns only the first 5 rows
Run it. If you get results, you are ready for the session. If not, review lesson 26 before continuing.
Hint
SQL
SELECT title, rating, length
FROM film
WHERE rating = 'PG'
ORDER BY length DESC
LIMIT 5;Steps
Step 1 — Cheap Films, Longest First (Easy)
Context: The store wants to promote its cheapest films. List all films with a rental rate of exactly $0.99, showing the title, length, and rating. Present them from longest to shortest so customers can find full-length movies in the budget tier.
Task: Write a query on the film table that:
- Filters for
rental_rate = 0.99 - Shows
title,length, andrating - Orders by
lengthdescending, then bytitleascending when lengths are equal
Expected shape: Many rows (roughly 340 films at the $0.99 price point). The first row should be the longest cheap film.
Hint
This is a straightforward WHERE + ORDER BY. Two sort columns: primary length DESC, secondary title ASC.
SQL
SELECT title, length, rating
FROM film
WHERE rental_rate = 0.99
ORDER BY length DESC, title ASC;Step 2 — Customers with Last Name Starting with 'S' (Easy)
Context: A customer calls in and says their last name starts with "S" but they cannot remember if their account is registered under their first name or a nickname. List all customers with last names beginning with 'S' so the agent can find the account quickly.
Task: Write a query on the customer table that:
- Filters for last names starting with the letter
'S' - Shows
first_name,last_name, andemail - Orders by
last_nameascending, thenfirst_nameascending
Expected shape: Around 50 customers. Rows ordered A→Z by last name.
Hint
Use LIKE 'S%' — the % wildcard matches everything after the initial S. Last name is stored in the last_name column.
SQL
SELECT first_name, last_name, email
FROM customer
WHERE last_name LIKE 'S%'
ORDER BY last_name ASC, first_name ASC;Step 3 — Count Family Films in a Specific Length Range (Medium)
Context: A parent asks how many films the store has that are appropriate for children (rated 'PG' or 'G') and fit into a roughly 90-minute sitting (between 80 and 100 minutes).
Task: Write two queries:
- A
SELECT COUNT(*)query that returns the exact count of films meeting both criteria. - A full listing query showing
title,rating, andlengthfor all matching films, sorted bylengthascending.
Expected shape for query 1: A single number. For query 2: Each qualifying film on its own row.
Hint
Combine rating IN ('PG', 'G') with length BETWEEN 80 AND 100. Both conditions must be true for a film to be included.
SQL
-- Query 1: count only
SELECT COUNT(*)
FROM film
WHERE rating IN ('PG', 'G')
AND length BETWEEN 80 AND 100;
-- Query 2: full listing
SELECT title, rating, length
FROM film
WHERE rating IN ('PG', 'G')
AND length BETWEEN 80 AND 100
ORDER BY length ASC;Step 4 — Actors Whose First Name Contains 'an' (Medium)
Context: Someone is looking for an actor they saw credited as "Ann" or "Juan" but cannot remember the exact spelling. Search for all actors whose first name contains the letters 'an' anywhere (case-insensitive), since the name could be capitalised differently in the database.
Task: Write a query on the actor table that:
- Uses a case-insensitive pattern match on
first_namefor'an'anywhere in the name - Shows
first_nameandlast_name - Orders by
last_nameascending
Expected shape: A list of actors — names like Ann, Anna, Juanita, Dan, Sandra, etc.
Hint
Use ILIKE '%an%' so that ANN, ann, and hANna all match. ILIKE is PostgreSQL's case-insensitive LIKE.
SQL
SELECT first_name, last_name
FROM actor
WHERE first_name ILIKE '%an%'
ORDER BY last_name ASC;Step 5 — Customers Without an Email Address (Hard)
Context: The marketing team wants to send a promotional email campaign but first needs to identify which customers are missing an email address so they can be excluded from the mailing list (or contacted by phone instead).
Task: Write a query on the customer table that:
- Returns only customers where
emailisNULL - Shows
customer_id,first_name, andlast_name - Orders by
last_nameascending
Also write a second query that returns the total count of customers without an email.
Expected shape: If DVD Rental has all emails populated, query 1 returns 0 rows — that is a valid result. The count query will confirm it with 0.
Tip: Remember that WHERE email = NULL is always wrong — it returns 0 rows whether or not NULLs exist. You must use IS NULL.
Hint
IS NULL is the only correct way to check for absent values in SQL.
SQL
-- Query 1: listing
SELECT customer_id, first_name, last_name
FROM customer
WHERE email IS NULL
ORDER BY last_name ASC;
-- Query 2: count
SELECT COUNT(*)
FROM customer
WHERE email IS NULL;Step 6 — Films Without an 'Epic' Description (Hard)
Context: A film critic who reviews epic blockbusters wants a list of all films that are either completely undescribed OR whose description does not mention the word 'epic' — so they can find films outside their usual genre.
Task: Write a query on the film table that returns films where:
descriptionisNULL, ORdescriptiondoes not contain the word'epic'(case-insensitive)
Show title and rating. Order by title ascending. Also add a third column called has_description that shows 'Yes' when description is not NULL and 'No' when it is NULL — use a CASE expression for this.
Expected shape: Most films in the database, since only a subset will have 'epic' in their description. Two-column output plus the derived has_description flag.
Tip: The CASE expression syntax is: CASE WHEN condition THEN value ELSE other_value END.
Hint
The OR condition needs parentheses to combine correctly with any other future filters. Use NOT ILIKE for the case-insensitive negative match.
SQL
SELECT title,
rating,
CASE WHEN description IS NULL THEN 'No' ELSE 'Yes' END AS has_description
FROM film
WHERE description IS NULL
OR description NOT ILIKE '%epic%'
ORDER BY title ASC;Bonus Tasks
Bonus 1 — Three Cheapest Films per Rating
Find the three cheapest films (by rental_rate) for each rating category. For each rating, show title, rental_rate, and length, sorted by rental_rate ascending and then title ascending. (Hint: you can do this with a separate query per rating, or challenge yourself to look up the LIMIT trick inside a subquery — we cover subqueries fully in lesson 34.)
Hint
For now, write one query per rating and use ORDER BY rental_rate ASC, title ASC LIMIT 3. After lesson 34 you can replace these with a single query using ROW_NUMBER().
SQL
-- Example for 'G' rating — repeat for PG, PG-13, R, NC-17
SELECT title, rental_rate, length
FROM film
WHERE rating = 'G'
ORDER BY rental_rate ASC, title ASC
LIMIT 3;Bonus 2 — Active Customers Without a Recent Address
The customer table has an address_id column linking to the address table. Write a query that lists active customers (active = 1) whose email contains neither '.com' nor '.org' (case-insensitive). Show customer_id, first_name, last_name, and email. Order by customer_id.
Hint
Use NOT ILIKE for each domain pattern. Connect the two negative conditions with AND (the customer's email must lack both .com AND .org for the row to qualify).
SQL
SELECT customer_id, first_name, last_name, email
FROM customer
WHERE active = 1
AND email NOT ILIKE '%.com%'
AND email NOT ILIKE '%.org%'
ORDER BY customer_id;Bonus 3 — Film Length Extremes by Rating
For each rating (G, PG, PG-13, R, NC-17), write a single query that shows the shortest and longest film. Show rating, title, length, and a label column called extreme with value 'Shortest' or 'Longest'. (This is a union challenge — combine two queries with UNION ALL.)
Hint
Use two subqueries joined with UNION ALL. Each subquery finds all films whose length equals the minimum (or maximum) for their rating. Aggregate functions for the min/max length are covered fully in lesson 29.
SQL
-- Shortest per rating
SELECT rating, title, length, 'Shortest' AS extreme
FROM film
WHERE (rating, length) IN (
SELECT rating, MIN(length) FROM film GROUP BY rating
)
UNION ALL
-- Longest per rating
SELECT rating, title, length, 'Longest' AS extreme
FROM film
WHERE (rating, length) IN (
SELECT rating, MAX(length) FROM film GROUP BY rating
)
ORDER BY rating, extreme;