WHERE city = 'Pune' OR city = 'Mumbai' OR city = 'Delhi' works, but it is long and easy to break. IN says the same thing in one place:
5. IN, BETWEEN, LIKE, DISTINCT, LIMIT
Step 1 of 4 · Lesson
Lesson 5 of 21
MySQL IN, BETWEEN, LIKE, DISTINCT and LIMIT with examples
Filter with lists (IN), ranges (BETWEEN) and text patterns (LIKE), remove duplicates with DISTINCT, and page through results with LIMIT and OFFSET.
In short
What do IN, BETWEEN and LIKE do in MySQL?
IN matches any value in a list (city IN ('Pune','Mumbai')). BETWEEN matches an inclusive range (price BETWEEN 100 AND 300 includes both ends). LIKE matches text patterns: % stands for any number of characters and _ for exactly one, so name LIKE 'E%' finds names starting with E.
By the end of this lesson you can
- Replace long OR chains with IN and NOT IN
- Filter number and date ranges with BETWEEN — and know when a half-open range is safer
- Search text with LIKE, % and _
- Remove duplicate rows with DISTINCT
- Return the top N rows and page through results with LIMIT / OFFSET
IN: match any value in a list
SELECT customer_name, city
FROM customers
WHERE city IN ('Pune', 'Mumbai')
ORDER BY customer_id;| customer_name | city |
|---|---|
| Asha | Pune |
| Bilal | Mumbai |
| Charu | Pune |
| Esha | Mumbai |
NOT IN keeps rows whose value is not in the list: WHERE city NOT IN ('Pune', 'Mumbai') returns Dev and Farah. Lesson 9 shows how the list can come from another query: WHERE customer_id IN (SELECT customer_id FROM orders).
BETWEEN: inclusive ranges
BETWEEN low AND high keeps values from low to high, including both ends. It works for numbers, text and dates:
SELECT product_name, price
FROM products
WHERE price BETWEEN 100 AND 300
ORDER BY price;| product_name | price |
|---|---|
| Notebook | 100.00 |
| Mug | 250.00 |
| Planner | 300.00 |
Notebook (100.00) and Planner (300.00) are included because both ends count. NOT BETWEEN 100 AND 300 returns the others.
Date ranges: BETWEEN or half-open?
For a DATE column, BETWEEN '2026-02-01' AND '2026-02-28' returns all of February. But if the column also stores a time (DATETIME), an order at 2026-02-28 14:30 is after '2026-02-28' (which means midnight) and is lost.
Professionals use a half-open range — greater-or-equal the first day, strictly less than the first day of the next period. It is correct for both DATE and DATETIME, and for any month length:
SELECT order_id, order_date, status
FROM orders
WHERE order_date >= '2026-02-01'
AND order_date < '2026-03-01'
ORDER BY order_id;| order_id | order_date | status |
|---|---|---|
| 103 | 2026-02-03 | completed |
| 104 | 2026-02-10 | cancelled |
| 105 | 2026-02-15 | completed |
LIKE: search text with wildcards
LIKE compares text against a pattern:
| Pattern | Matches | Example |
|---|---|---|
'E%' |
starts with E | Esha |
'%a' |
ends with a | Asha, Esha |
'%lamp%' |
contains lamp anywhere | Desk lamp |
'___' |
exactly three characters | Pen, Mug |
% means any number of characters (even zero), and _ means exactly one character. With MySQL's default collation LIKE ignores case, so 'e%' finds Esha too.
SELECT customer_name
FROM customers
WHERE customer_name LIKE '%a'
ORDER BY customer_id;| customer_name |
|---|
| Asha |
| Esha |
To search for a real % or _ character, escape it with a backslash: LIKE '%50\%%' finds text containing 50%.
DISTINCT: remove duplicate rows
SELECT DISTINCT removes repeated rows from the result. It applies to the whole row, not just the first column:
SELECT DISTINCT city
FROM customers
ORDER BY city;| city |
|---|
| Delhi |
| Jaipur |
| Mumbai |
| Pune |
Six customers, four distinct cities. SELECT DISTINCT city, customer_name would return all six rows again, because every (city, name) pair is unique. DISTINCT treats all NULLs as one value.
LIMIT and OFFSET: top-N and pages
LIMIT n returns at most n rows. Combined with ORDER BY it answers top-N questions such as the three cheapest products:
SELECT product_name, price
FROM products
ORDER BY price
LIMIT 3;| product_name | price |
|---|---|
| Pen | 20.00 |
| Notebook | 100.00 |
| Mug | 250.00 |
LIMIT 2 OFFSET 2 skips two rows and returns the next two — page 2 when each page shows two rows. MySQL also accepts the short form LIMIT 2, 2 (offset first, then count).
Putting it together
Clauses always appear in this order: SELECT … FROM … WHERE … ORDER BY … LIMIT. A typical catalogue query combines several of today's tools:
SELECT product_name, category, price
FROM products
WHERE category IN ('Stationery', 'Home')
AND price BETWEEN 50 AND 500
AND product_name NOT LIKE 'P%'
ORDER BY price DESC
LIMIT 2;| product_name | category | price |
|---|---|---|
| Mug | Home | 250.00 |
| Notebook | Stationery | 100.00 |
Common mistakes
Wrong
WHERE order_date BETWEEN '2026-02-01' AND '2026-02-28' -- on a DATETIME columnFix
WHERE order_date >= '2026-02-01' AND order_date < '2026-03-01'Why: '2026-02-28' means midnight, so orders later that day are excluded.
Wrong
WHERE customer_name LIKE 'E'Fix
WHERE customer_name LIKE 'E%'Why: Without a wildcard LIKE behaves like =, so only a name exactly equal to 'E' matches.
Wrong
SELECT product_name FROM products LIMIT 3; -- “the 3 cheapest”Fix
ORDER BY price LIMIT 3Why: No ORDER BY, so the rows are arbitrary.
Wrong
WHERE email NOT LIKE '%.test' -- expecting CharuFix
WHERE email NOT LIKE '%.test' OR email IS NULLWhy: Charu's email is NULL, and NULL NOT LIKE anything is unknown, so she is filtered out.
Check yourself
- Does price BETWEEN 100 AND 300 include 300? Why might you prefer >= and < for dates?
- What is the difference between % and _ in a LIKE pattern?
- Why must LIMIT almost always come with ORDER BY?
Answer out loud or in your notebook. If one is hard, reread that section before practising.
Frequently asked questions
Is BETWEEN inclusive in MySQL?
Yes. a BETWEEN 1 AND 10 is the same as a >= 1 AND a <= 10, so both ends are included.
Is MySQL LIKE case-sensitive?
Not with the default utf8mb4_0900_ai_ci collation: LIKE 'e%' matches Esha. Use a binary or _cs collation, or LIKE BINARY, for case-sensitive matching.
How do I get the top 5 rows in MySQL?
Sort and then limit: SELECT … ORDER BY column DESC LIMIT 5;. MySQL uses LIMIT where SQL Server uses TOP and Oracle uses FETCH FIRST.
Quick quiz — 4 questions
Quick Check: IN, BETWEEN, LIKE, DISTINCT, LIMIT
Meet Learning Shop
One small fictional shop powers the whole course: 6 customers, 6 products, 8 orders and 14 order lines, small enough to check every answer by eye. The practice editor on this page already contains it. To practise in MySQL Workbench, import it once.
customers.customer_id → orders.customer_id · orders.order_id → order_items.order_id · products.product_id → order_items.product_id
Import in MySQL Workbench
- Connect to your local MySQL server (8.0.16 or newer; 8.4 recommended).
- Choose File → Open SQL Script and open the downloaded file.
- Click the lightning bolt to execute the whole script. The last result shows 6, 6, 8 and 14 rows.
- Refresh the Schemas panel, then select the database:
USE portfolio_retail_lab;
SHOW TABLES;Command line instead: mysql -u root -p < mysql-retail-lab.sql
In the practice editor, the Reset database button does the same as the reset script — instantly and only in your browser.
Let’s do one together
Start from a list filter and add one tool at a time.
- 1Run the query: Stationery and Home products.
- 2Add AND price BETWEEN 100 AND 300 to the WHERE and run — Pen drops out.
- 3Add AND product_name LIKE '%e%' — which product disappears?
- 4Finish with ORDER BY price DESC LIMIT 1 to get the most expensive match.
SELECT product_name, category, price
FROM products
WHERE category IN ('Stationery', 'Home')
ORDER BY product_id;What you should see
Four rows: Notebook, Pen, Mug and Planner.
| product_name | category | price |
|---|---|---|
| Notebook | Stationery | 100.00 |
| Pen | Stationery | 20.00 |
| Mug | Home | 250.00 |
| Planner | Stationery | 300.00 |
Practice problems
17 problems from Easy to Professional · 0 solved · J / K to move
List the products in the Stationery or Home category using IN.
Target: 4 rows: Notebook, Pen, Mug, Planner
Database already selected: Learning Shop (small)(portfolio_retail_lab)— write the query directly, no USE needed.
I’m stuck — show a hint
category IN ('Stationery', 'Home').
Reference answer
SELECT product_name, category FROM products WHERE category IN ('Stationery', 'Home') ORDER BY product_id;| product_name | category |
|---|---|
| Notebook | Stationery |
| Pen | Stationery |
| Mug | Home |
| Planner | Stationery |
More than one query can be correct. If your result matches the target, your query is right.
List each city that has a customer, once, A to Z.
Target: 4 rows: Delhi, Jaipur, Mumbai, Pune
I’m stuck — show a hint
SELECT DISTINCT city.
Reference answer
SELECT DISTINCT city FROM customers ORDER BY city;| city |
|---|
| Delhi |
| Jaipur |
| Mumbai |
| Pune |
More than one query can be correct. If your result matches the target, your query is right.
Find products priced from 100 to 300 inclusive, cheapest first.
Target: 3 rows: Notebook 100.00, Mug 250.00, Planner 300.00
I’m stuck — show a hint
BETWEEN includes both ends.
Reference answer
SELECT product_name, price FROM products WHERE price BETWEEN 100 AND 300 ORDER BY price;| product_name | price |
|---|---|
| Notebook | 100.00 |
| Mug | 250.00 |
| Planner | 300.00 |
More than one query can be correct. If your result matches the target, your query is right.
Find customers whose name starts with E.
Target: 1 row: Esha
I’m stuck — show a hint
LIKE 'E%'.
Reference answer
SELECT customer_name FROM customers WHERE customer_name LIKE 'E%';| customer_name |
|---|
| Esha |
More than one query can be correct. If your result matches the target, your query is right.
Show the three cheapest products.
Target: 3 rows: Pen 20.00, Notebook 100.00, Mug 250.00
I’m stuck — show a hint
ORDER BY price, then LIMIT 3.
Reference answer
SELECT product_name, price FROM products ORDER BY price LIMIT 3;| product_name | price |
|---|---|
| Pen | 20.00 |
| Notebook | 100.00 |
| Mug | 250.00 |
More than one query can be correct. If your result matches the target, your query is right.
List February 2026 orders using BETWEEN on order_date.
Target: 3 rows: 103, 104, 105
I’m stuck — show a hint
order_date is a DATE, so BETWEEN '2026-02-01' AND '2026-02-28' is safe here.
Reference answer
SELECT order_id, order_date FROM orders WHERE order_date BETWEEN '2026-02-01' AND '2026-02-28' ORDER BY order_id;| order_id | order_date |
|---|---|
| 103 | 2026-02-03 |
| 104 | 2026-02-10 |
| 105 | 2026-02-15 |
More than one query can be correct. If your result matches the target, your query is right.
Find products whose name contains the letter o anywhere.
Target: 2 rows: Notebook, Keyboard
I’m stuck — show a hint
Wildcards on both sides: '%o%'.
Reference answer
SELECT product_name FROM products WHERE product_name LIKE '%o%' ORDER BY product_id;| product_name |
|---|
| Notebook |
| Keyboard |
More than one query can be correct. If your result matches the target, your query is right.
List customers who are not in Pune or Mumbai.
Target: 2 rows: Dev (Delhi), Farah (Jaipur)
I’m stuck — show a hint
NOT IN ('Pune', 'Mumbai').
Reference answer
SELECT customer_name, city FROM customers WHERE city NOT IN ('Pune', 'Mumbai') ORDER BY customer_id;| customer_name | city |
|---|---|
| Dev | Delhi |
| Farah | Jaipur |
More than one query can be correct. If your result matches the target, your query is right.
List each order status once, A to Z.
Target: 3 rows: cancelled, completed, pending
I’m stuck — show a hint
DISTINCT on status.
Reference answer
SELECT DISTINCT status FROM orders ORDER BY status;| status |
|---|
| cancelled |
| completed |
| pending |
More than one query can be correct. If your result matches the target, your query is right.
Show page 2 of the product list, 2 products per page, in product_id order.
Target: 2 rows: Desk lamp, Mug
I’m stuck — show a hint
LIMIT 2 OFFSET 2.
Reference answer
SELECT product_id, product_name FROM products ORDER BY product_id LIMIT 2 OFFSET 2;| product_id | product_name |
|---|---|
| 3 | Desk lamp |
| 4 | Mug |
More than one query can be correct. If your result matches the target, your query is right.
Find product names that are exactly three characters long using LIKE.
Target: 2 rows: Pen, Mug
I’m stuck — show a hint
Each _ matches one character.
Reference answer
SELECT product_name FROM products WHERE product_name LIKE '___' ORDER BY product_id;| product_name |
|---|
| Pen |
| Mug |
More than one query can be correct. If your result matches the target, your query is right.
Find customers whose email does NOT end in .test — including customers with no email.
Target: 1 row: Charu (email NULL)
I’m stuck — show a hint
NOT LIKE alone drops NULLs; add OR email IS NULL.
Reference answer
SELECT customer_name, email FROM customers WHERE email NOT LIKE '%.test' OR email IS NULL;| customer_name | |
|---|---|
| Charu | NULL |
More than one query can be correct. If your result matches the target, your query is right.
List each customer_id that appears in orders, once.
Target: 5 rows: 1, 2, 3, 4, 5 (customer 6 never ordered)
I’m stuck — show a hint
DISTINCT customer_id from orders.
Reference answer
SELECT DISTINCT customer_id FROM orders ORDER BY customer_id;| customer_id |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
More than one query can be correct. If your result matches the target, your query is right.
Find the single most expensive Stationery product.
Target: 1 row: Planner 300.00
I’m stuck — show a hint
Filter, sort descending, LIMIT 1.
Reference answer
SELECT product_name, price FROM products WHERE category = 'Stationery' ORDER BY price DESC LIMIT 1;| product_name | price |
|---|---|
| Planner | 300.00 |
More than one query can be correct. If your result matches the target, your query is right.
List orders from 2026-01-08 to 2026-03-02 inclusive that were not cancelled.
Target: 4 rows: 102, 103, 105, 106
I’m stuck — show a hint
BETWEEN for the dates, <> for the status.
Reference answer
SELECT order_id, order_date, status FROM orders WHERE order_date BETWEEN '2026-01-08' AND '2026-03-02' AND status <> 'cancelled' ORDER BY order_id;| order_id | order_date | status |
|---|---|---|
| 102 | 2026-01-08 | completed |
| 103 | 2026-02-03 | completed |
| 105 | 2026-02-15 | completed |
| 106 | 2026-03-02 | completed |
More than one query can be correct. If your result matches the target, your query is right.
A support agent types “sh” into a search box. Return customers whose name or email contains it.
Target: 2 rows: Asha, Esha
I’m stuck — show a hint
Two LIKE conditions joined with OR; LIKE ignores case.
Reference answer
SELECT customer_id, customer_name, email FROM customers WHERE customer_name LIKE '%sh%' OR email LIKE '%sh%' ORDER BY customer_id;| customer_id | customer_name | |
|---|---|---|
| 1 | Asha | asha@example.test |
| 5 | Esha | esha@example.test |
More than one query can be correct. If your result matches the target, your query is right.
Price-list page 1: non-Electronics products priced 100–800, names A to Z, 2 per page.
Target: 2 rows: Mug 250.00, Notebook 100.00
I’m stuck — show a hint
category <> 'Electronics', BETWEEN, ORDER BY product_name, LIMIT 2.
Reference answer
SELECT product_name, price FROM products WHERE category <> 'Electronics' AND price BETWEEN 100 AND 800 ORDER BY product_name LIMIT 2;| product_name | price |
|---|---|
| Mug | 250.00 |
| Notebook | 100.00 |
More than one query can be correct. If your result matches the target, your query is right.
Practice mode runs in your browser on a SQLite engine with a MySQL compatibility layer, so you can practise without installing anything. Your result is compared with the reference answer on a fresh copy of the same rows, so any correct query is accepted. A few MySQL-only features (EXPLAIN columns, WITH ROLLUP, user variables) behave differently here — run those in MySQL Workbench.
Finished? Save your queries in a .sql file and mark the lesson complete.
Answers — IN, BETWEEN, LIKE, DISTINCT, LIMIT
Easy. List the products in the Stationery or Home category using IN. Target: 4 rows: Notebook, Pen, Mug, Planner
SELECT product_name, category FROM products WHERE category IN ('Stationery', 'Home') ORDER BY product_id;Easy. List each city that has a customer, once, A to Z. Target: 4 rows: Delhi, Jaipur, Mumbai, Pune
SELECT DISTINCT city FROM customers ORDER BY city;
Easy. Find products priced from 100 to 300 inclusive, cheapest first. Target: 3 rows: Notebook 100.00, Mug 250.00, Planner 300.00
SELECT product_name, price FROM products WHERE price BETWEEN 100 AND 300 ORDER BY price;
Easy. Find customers whose name starts with E. Target: 1 row: Esha
SELECT customer_name FROM customers WHERE customer_name LIKE 'E%';
Easy. Show the three cheapest products. Target: 3 rows: Pen 20.00, Notebook 100.00, Mug 250.00
SELECT product_name, price FROM products ORDER BY price LIMIT 3;
Medium. List February 2026 orders using BETWEEN on order_date. Target: 3 rows: 103, 104, 105
SELECT order_id, order_date FROM orders WHERE order_date BETWEEN '2026-02-01' AND '2026-02-28' ORDER BY order_id;
Medium. Find products whose name contains the letter o anywhere. Target: 2 rows: Notebook, Keyboard
SELECT product_name FROM products WHERE product_name LIKE '%o%' ORDER BY product_id;
Medium. List customers who are not in Pune or Mumbai. Target: 2 rows: Dev (Delhi), Farah (Jaipur)
SELECT customer_name, city FROM customers WHERE city NOT IN ('Pune', 'Mumbai') ORDER BY customer_id;Medium. List each order status once, A to Z. Target: 3 rows: cancelled, completed, pending
SELECT DISTINCT status FROM orders ORDER BY status;
Medium. Show page 2 of the product list, 2 products per page, in product_id order. Target: 2 rows: Desk lamp, Mug
SELECT product_id, product_name FROM products ORDER BY product_id LIMIT 2 OFFSET 2;
Medium. Find product names that are exactly three characters long using LIKE. Target: 2 rows: Pen, Mug
SELECT product_name FROM products WHERE product_name LIKE '___' ORDER BY product_id;
Hard. Find customers whose email does NOT end in .test — including customers with no email. Target: 1 row: Charu (email NULL)
SELECT customer_name, email FROM customers WHERE email NOT LIKE '%.test' OR email IS NULL;
Hard. List each customer_id that appears in orders, once. Target: 5 rows: 1, 2, 3, 4, 5 (customer 6 never ordered)
SELECT DISTINCT customer_id FROM orders ORDER BY customer_id;
Hard. Find the single most expensive Stationery product. Target: 1 row: Planner 300.00
SELECT product_name, price FROM products WHERE category = 'Stationery' ORDER BY price DESC LIMIT 1;
Hard. List orders from 2026-01-08 to 2026-03-02 inclusive that were not cancelled. Target: 4 rows: 102, 103, 105, 106
SELECT order_id, order_date, status FROM orders WHERE order_date BETWEEN '2026-01-08' AND '2026-03-02' AND status <> 'cancelled' ORDER BY order_id;
Professional. A support agent types “sh” into a search box. Return customers whose name or email contains it. Target: 2 rows: Asha, Esha
SELECT customer_id, customer_name, email FROM customers WHERE customer_name LIKE '%sh%' OR email LIKE '%sh%' ORDER BY customer_id;
Professional. Price-list page 1: non-Electronics products priced 100–800, names A to Z, 2 per page. Target: 2 rows: Mug 250.00, Notebook 100.00
SELECT product_name, price FROM products WHERE category <> 'Electronics' AND price BETWEEN 100 AND 800 ORDER BY product_name LIMIT 2;
Up next · Lesson 6
Functions and CASE
75 min · 17 practice problems