SQL LIKE, IN and BETWEEN Explained Simply

Once you know WHERE with =, > and <, you’ll quickly want more: names that start with “Dell”, products in these three categories, orders between two dates. SQL has three short operators for exactly these jobs: LIKE, IN and BETWEEN.

They look simple, and they are. But each one has a trap that quietly returns the wrong rows. This guide covers the normal use and the trap for each, in SQL Server and MySQL.

SQL LIKE, IN and BETWEEN cheat sheet with wildcard examples

All examples use this small Products table:

ProductIDProductNameCategoryPriceAddedOn
1Dell XPS 13Laptops1299.002026-03-02 09:15
2Dell Inspiron 15Laptops649.002026-03-15 14:30
3HP Pavilion 14Laptops579.002026-03-31 16:45
4Logitech MX Master 3SMice99.002026-04-01 00:00
5Dell 24″ MonitorMonitors189.002026-04-10 11:00
6Samsung 27″ MonitorMonitors249.00NULL
7USB-C Hub 7-in-1Accessories39.002026-02-20 10:00
8Laptop Stand 100% AluminiumAccessories45.002026-03-31 08:00

1. LIKE: search inside text

LIKE compares text against a pattern. The pattern uses two wildcards:

WildcardMeansExampleMatches
%Any number of characters (even zero)'Dell%'Dell XPS 13, Dell 24″ Monitor
_Exactly one character'HP Pavilion 1_'HP Pavilion 14 (but not HP Pavilion 140)

Starts with, ends with, contains

-- Starts with "Dell"
SELECT ProductName FROM Products WHERE ProductName LIKE 'Dell%';
-- Dell XPS 13, Dell Inspiron 15, Dell 24" Monitor

-- Ends with "Monitor"
SELECT ProductName FROM Products WHERE ProductName LIKE '%Monitor';

-- Contains "monitor" anywhere
SELECT ProductName FROM Products WHERE ProductName LIKE '%monitor%';
-- Dell 24" Monitor, Samsung 27" Monitor

Notice the last query found “Monitor” with a capital M even though the pattern used lower case. That’s because the default settings in both SQL Server and MySQL are case-insensitive. This depends on the column’s collation, so a case-sensitive database will behave differently. (PostgreSQL is case-sensitive and uses ILIKE for case-insensitive searches.)

NOT LIKE

SELECT ProductName FROM Products WHERE ProductName NOT LIKE 'Dell%';

This returns every product whose name does not start with “Dell”. Rows where ProductName is NULL are not returned by either LIKE or NOT LIKE, because comparing with NULL gives “unknown”. (More on that in NULL in SQL Explained Simply.)

Trap: searching for a real % or _

What if you want the products whose name contains a real percent sign? This looks right, but it isn’t:

-- WRONG: '%%%' means "anything, anything, anything" and matches every row
SELECT ProductName FROM Products WHERE ProductName LIKE '%%%';

You must escape the wildcard so SQL treats it as a normal character. The ESCAPE clause works in both SQL Server and MySQL:

-- Pick any character as the escape character; here it's !
SELECT ProductName FROM Products WHERE ProductName LIKE '%100!%%' ESCAPE '!';
-- Laptop Stand 100% Aluminium

-- SQL Server also lets you put the wildcard in square brackets
SELECT ProductName FROM Products WHERE ProductName LIKE '%100[%]%';

The underscore has the same problem. LIKE '%_%' matches every non-empty value, so a column of codes like INV_001 needs LIKE '%!_%' ESCAPE '!'.

Trap: a leading % is slow on big tables

LIKE 'Dell%' can use an index on ProductName, because the database knows where names starting with “Dell” begin, just like finding a word in a dictionary. LIKE '%Dell%' can’t: the text could be anywhere, so the database reads every row. On 8 rows you won’t notice. On 5 million rows you will. See Index Seek vs Index Scan for why.

2. IN: match any value in a list

IN is a short way to write several OR conditions on the same column:

-- Long way
SELECT ProductName, Category FROM Products
WHERE Category = 'Mice' OR Category = 'Monitors';

-- Same result, shorter and easier to read
SELECT ProductName, Category FROM Products
WHERE Category IN ('Mice', 'Monitors');
-- Logitech MX Master 3S, Dell 24" Monitor, Samsung 27" Monitor

NOT IN does the opposite:

SELECT ProductName FROM Products
WHERE Category NOT IN ('Laptops', 'Accessories');

IN with a subquery

The list can also come from another query. For example, all products that appear in a Discontinued table:

SELECT ProductName FROM Products
WHERE ProductID IN (SELECT ProductID FROM Discontinued);

Trap: NOT IN with a NULL returns nothing

This is one of the most famous SQL bugs. Suppose Discontinued contains two rows: 7 and NULL. You want the products that are still active:

SELECT COUNT(*) FROM Products
WHERE ProductID NOT IN (SELECT ProductID FROM Discontinued);
-- 0  (!)

Zero rows, not seven. Here’s why. NOT IN (7, NULL) means ProductID <> 7 AND ProductID <> NULL. Any comparison with NULL is “unknown”, so the whole condition is never true, and no rows come back.

The safe fix is NOT EXISTS, which handles NULL correctly:

SELECT COUNT(*) FROM Products p
WHERE NOT EXISTS (SELECT 1 FROM Discontinued d WHERE d.ProductID = p.ProductID);
-- 7

Rule of thumb: use IN freely, but when the list comes from a subquery, prefer NOT EXISTS over NOT IN. Or add WHERE ProductID IS NOT NULL inside the subquery.

3. BETWEEN: filter a range

BETWEEN keeps the values inside a range, and it includes both ends:

SELECT ProductName, Price FROM Products
WHERE Price BETWEEN 99 AND 249;
-- Logitech MX Master 3S  99.00
-- Dell 24" Monitor      189.00
-- Samsung 27" Monitor   249.00

BETWEEN 99 AND 249 is exactly the same as Price >= 99 AND Price <= 249. Both 99 and 249 are included.

Trap: the order matters

The smaller value must come first. BETWEEN 249 AND 99 doesn’t give an error. It just quietly returns 0 rows, because no price is both 249 or more and 99 or less.

Trap: BETWEEN with dates and times

This is the mistake that hides real data in reports. You want everything added in March:

-- Looks right, but misses rows
SELECT ProductName, AddedOn FROM Products
WHERE AddedOn BETWEEN '2026-03-01' AND '2026-03-31';
-- Dell XPS 13, Dell Inspiron 15  (only 2 rows)

Two products added on March 31 are missing. '2026-03-31' means March 31 at midnight (00:00:00), so anything later that day, like 08:00 or 16:45, is outside the range.

The safe pattern works for every date and time type: greater than or equal to the first day, and less than the day after the last day.

SELECT ProductName, AddedOn FROM Products
WHERE AddedOn >= '2026-03-01' AND AddedOn < '2026-04-01';
-- 4 rows, including both March 31 products

You never need to know whether March has 30 or 31 days, or how precise the time column is. More date patterns are in SQL Date Functions Explained Simply.

BETWEEN with text

BETWEEN works on text too, in alphabetical order. But it’s rarely what you want:

SELECT ProductName FROM Products WHERE ProductName BETWEEN 'D' AND 'H';
-- Dell XPS 13, Dell Inspiron 15, Dell 24" Monitor

“HP Pavilion” is not included, because “HP Pavilion” comes after the single letter “H” in alphabetical order. If you mean “names starting with D to H”, use LIKE or LEFT(ProductName, 1) BETWEEN 'D' AND 'H'.

Putting them together

The three operators combine naturally with AND, OR and ORDER BY:

-- Dell laptops and monitors between 100 and 1,000, most expensive first
SELECT ProductName, Price
FROM Products
WHERE Category IN ('Laptops', 'Monitors')
  AND ProductName LIKE 'Dell%'
  AND Price BETWEEN 100 AND 1000
ORDER BY Price DESC;
-- Dell Inspiron 15   649.00
-- Dell 24" Monitor   189.00

Cheat sheet

You wantWriteWatch out for
Text starts with XLIKE 'X%'Case sensitivity depends on collation
Text contains XLIKE '%X%'Can’t use an index: slow on big tables
A real % or _LIKE '%!%%' ESCAPE '!'Without escaping, it matches everything
One of several valuesIN ('a', 'b', 'c')
Not in a subquery’s resultsNOT EXISTS (...)NOT IN returns nothing if the list has a NULL
A number rangeBETWEEN 10 AND 20Both ends included; smaller value first
A date range>= '2026-03-01' AND < '2026-04-01'BETWEEN misses times on the last day

Practice exercises

Try these on the Products table before you look at the answers.

  1. Find all products whose name contains a double quote (").
  2. Find all products in the Laptops or Mice categories that cost less than 600.
  3. Find all products added in the first quarter of 2026 (January to March).

Answers:

-- 1
SELECT ProductName FROM Products WHERE ProductName LIKE '%"%';

-- 2
SELECT ProductName FROM Products
WHERE Category IN ('Laptops', 'Mice') AND Price < 600;

-- 3
SELECT ProductName FROM Products
WHERE AddedOn >= '2026-01-01' AND AddedOn < '2026-04-01';

Summary

  • LIKE searches text with % (any characters) and _ (one character). Escape them to search for the real characters.
  • IN replaces a chain of OR conditions. Prefer NOT EXISTS over NOT IN with subqueries, because of NULL.
  • BETWEEN includes both ends. For dates with times, use >= and < instead.

Related articles

Scroll to Top