Lists from Subqueries: IN

In lesson 3, you used IN with a list of values: WHERE id IN (1, 3, 5). The list doesn't have to be typed by hand: a subquery can make it. Which games have at least one five-star review? The IDs of those games are in the table reviews:

SELECT game_id FROM reviews WHERE stars = 5;
game_id
1
1
3
6
…

Put this query in parentheses after IN, and the outer query finds the titles of the games:

SELECT title
FROM games
WHERE id IN (SELECT game_id FROM reviews WHERE stars = 5)
ORDER BY title;
title
Cube Logic
Dragon Forge
Knight's Oath
Moon Farm
Star Pilots
Turbo Karts
Zombie Town

The subquery runs first and returns a list: 1, 1, 3, 6, 7, 10, 14, 15. Then IN checks each game: is its id in the list? Dragon Forge (1) is in the list twice, but that doesn't matter: IN only asks whether the value is there, so each game is in the result at most once.

Unlike the subqueries of the previous exercise, a subquery after IN may return any number of rows, even none (then IN finds nothing). But it must return exactly one column, because IN compares one value with a list of values:

SELECT title
FROM games
WHERE id IN (SELECT game_id, stars FROM reviews);
Error on line 1: sub-select returns 2 columns - expected 1

You could find the games with a join too:

SELECT g.title
FROM games AS g
JOIN reviews AS r ON r.game_id = g.id
WHERE r.stars = 5
ORDER BY g.title;
title
Cube Logic
Dragon Forge
Dragon Forge
Knight's Oath
Moon Farm
Star Pilots
Turbo Karts
Zombie Town

A join makes one row for every matching review, so Dragon Forge, with two five-star reviews, is there twice, and you'd need DISTINCT. Which one to use? When you need columns of the other table in the result, such as the stars or the comment, you need a join. When the other table only decides which rows to keep, IN with a subquery says exactly what you mean: “the games whose ID is among these”.

Typical mistake: = instead of IN. WHERE id = (SELECT game_id FROM reviews WHERE stars = 5) isn't an error in SQLite, but as you saw in the previous exercise, it takes only the first value of the list, so it finds just Dragon Forge.

Instructions

The query in the editor finds the games that someone has bought, with a join and DISTINCT. Rewrite it without the join: show the titles of the games whose id is in the list of game_id values of order_items. Use IN with a subquery. The result stays the same:

title
Bakery Story
Castle Siege
Cube Logic
…

Below it, show the name and the city of the customers who placed an order in December, in any year. The subquery finds the IDs of these customers in orders; the month of a date is strftime('%m', ordered_at). Sort by name:

namecity
Emma ClarkLondon
Noah WilsonLeeds
Olivia BrownLondon
Oscar KingBristol

A subquery can contain another subquery. Show the name and the email of the customers who reviewed Dragon Forge: a subquery finds the IDs of the reviewers in reviews, and inside it, another subquery finds the ID of the game by its title. Sort by name:

nameemail
Ava Greenava.green@mail.com
Emma Clarkemma.clark@mail.com
Leo Walkerleo.walker@mail.com
Liam Turnerliam.t@mail.com

Start programming for free

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

2/8