SQLab Hub
Lesson 5 · LIKE
Lesson 5 · Fundamentals

SQL LIKE: Pattern Matching With % and _

LIKE matches text against a pattern instead of an exact value. In the pattern, % stands for any number of characters and _ for exactly one. That gives you "starts with", "ends with" and "contains" searches.

% and _ wildcards Starts with · ends with · contains ▶ Runnable Playground examples 🧪 5 practice exercises 📝 6-question quiz ⏱ ~15 min

What Does LIKE Do?

= only finds values that are exactly equal. LIKE finds values that fit a pattern. Every Gmail user:

SQLite · runs in the Playground
SELECT first_name, last_name, email
FROM users
WHERE email LIKE '%@gmail.com'
ORDER BY last_name
LIMIT 5;

▶ Run this query in the SQL Playground

Users with a Gmail address
first_namelast_nameemail
DonnaAdamsdonna.adams52@gmail.com
SusanAndersonsusan.anderson87@gmail.com
BrianAndersonbrian.anderson56@gmail.com
ThomasBakerthomas.baker10@gmail.com
SarahBrownsarah.brown74@gmail.com
✓ 5 rows · real output from the Playground database
SQL · syntax
WHERE column LIKE 'pattern'
WHERE column NOT LIKE 'pattern'
WildcardMatchesExampleMatches values like
%Zero or more characters'Ja%'Ja, James, Jason
_Exactly one character'_ar%'Mark, Sarah, Karen (any first letter, then "ar")

Starts With, Ends With, Contains

SearchPatternMeaning
Starts withLIKE 'abc%'abc, then anything
Ends withLIKE '%abc'Anything, then abc
ContainsLIKE '%abc%'abc anywhere
Exact lengthLIKE '_____'Exactly five characters
Fixed formatLIKE '+1-___-___-____'A phone number in that layout

Starts with

SQLite · runs in the Playground
SELECT name, category
FROM products
WHERE name LIKE 'Pro%'
ORDER BY name;

▶ Run this query in the SQL Playground

Products whose name starts with "Pro"
namecategory
Professional Car Wax KitAutomotive
✓ 1 row · real output from the Playground database

Ends with

SQLite · runs in the Playground
SELECT DISTINCT last_name
FROM users
WHERE last_name LIKE '%son'
ORDER BY last_name;

▶ Run this query in the SQL Playground

Last names ending in "son"
last_name
Anderson
Jackson
Johnson
Nelson
Robinson
Thompson
Wilson
✓ 7 rows · real output from the Playground database

Contains

SQLite · runs in the Playground
SELECT DISTINCT name
FROM products
WHERE name LIKE '%Set%'
ORDER BY name;

▶ Run this query in the SQL Playground

Product names containing "Set"
name
LEGO Creator Set 742pcs
Luxury Shower Gel Gift Set
Resistance Bands Set
Soy Wax Candle Set
Succulent Plant Set
✓ 5 rows · real output from the Playground database

Matching One Character With _

_ stands for exactly one character, so it fixes the position of what follows. First names whose second and third letters are "ar":

SQLite · runs in the Playground
SELECT DISTINCT first_name
FROM users
WHERE first_name LIKE '_ar%'
ORDER BY first_name;

▶ Run this query in the SQL Playground

First names with "ar" in positions 2 and 3
first_name
Barbara
Carol
Karen
Maria
Mark
Sarah
✓ 6 rows · real output from the Playground database

It is also handy for codes with a fixed layout. Every Playground SKU is SKU- plus six digits, so this finds SKU-000010 to SKU-000019:

SQLite · runs in the Playground
SELECT sku, name
FROM products
WHERE sku LIKE 'SKU-00001_'
ORDER BY sku;

▶ Run this query in the SQL Playground

SKUs from 000010 to 000019
skuname
SKU-000010Magnetic Phone Mount Pro
SKU-000011Blender Pro 1200W
SKU-000012Ergonomic Desk Mat XL
SKU-000013Retinol Eye Cream 30ml
SKU-000014Play Kitchen Deluxe
SKU-000015Japanese Green Tea 50 bags
SKU-000016Sticky Notes Assorted 18pk
SKU-000017A5 Hardcover Notebook 3pk
SKU-000018Winter Parka Jacket
SKU-000019Resistance Bands Set
✓ 10 rows · real output from the Playground database

And a format check: every user's phone number fits the pattern +1-___-___-____:

SQLite · runs in the Playground
SELECT COUNT(*) AS users,
       SUM(phone LIKE '+1-___-___-____') AS phones_in_format
FROM users;

▶ Run this query in the SQL Playground

Phone numbers that match the expected layout
usersphones_in_format
150150
✓ 1 row · real output from the Playground database

NOT LIKE

NOT LIKE keeps the rows that do not match. Users on email providers other than Gmail, Yahoo and Hotmail:

SQLite · runs in the Playground
SELECT COUNT(*) AS other_providers
FROM users
WHERE email NOT LIKE '%@gmail.com'
  AND email NOT LIKE '%@yahoo.com'
  AND email NOT LIKE '%@hotmail.com';

▶ Run this query in the SQL Playground

Users on other email providers
other_providers
62
✓ 1 row · real output from the Playground database

Each pattern needs its own LIKE or NOT LIKE, joined with AND or OR; LIKE does not take a list. Rows where the column is NULL match neither LIKE nor NOT LIKE.

Is LIKE Case-Sensitive?

It depends on the database:

DatabaseLIKECase-insensitive option
SQLite (Playground)Case-insensitive for A-ZGLOB is the case-sensitive alternative
MySQLCase-insensitive with the default collationsUse a binary or _cs collation for case-sensitive
PostgreSQLCase-sensitiveILIKE
SQL ServerDepends on the collation; usually case-insensitiveCOLLATE ... _CS_ ... for case-sensitive
OracleCase-sensitiveLOWER(col) LIKE 'abc%'

In the Playground, LIKE ignores case while GLOB (which uses * and ? as wildcards) does not:

SQLite · runs in the Playground
SELECT SUM(name LIKE '%set%') AS like_lowercase,
       SUM(name LIKE '%SET%') AS like_uppercase,
       SUM(name GLOB '*set*')  AS glob_lowercase,
       SUM(name GLOB '*Set*')  AS glob_capital_s
FROM products;

▶ Run this query in the SQL Playground

LIKE ignores case in SQLite, GLOB does not
like_lowercaselike_uppercaseglob_lowercaseglob_capital_s
8808
✓ 1 row · real output from the Playground database

The portable way to search regardless of case is to lowercase both sides: WHERE LOWER(name) LIKE '%set%'.

Searching for a Literal % or _

To find a real percent sign or underscore, tell LIKE which character escapes the next one. The sample values below are written into the query:

SQLite · runs in the Playground
WITH promos(code) AS (
  VALUES ('SAVE10%'), ('SAVE10'), ('NEW_USER'), ('NEWUSER')
)
SELECT code,
       code LIKE '%!%%' ESCAPE '!' AS has_percent_sign,
       code LIKE '%!_%' ESCAPE '!' AS has_underscore,
       code LIKE '%_%'             AS unescaped_underscore
FROM promos;

▶ Run this query in the SQL Playground

Escaped and unescaped wildcards
codehas_percent_signhas_underscoreunescaped_underscore
SAVE10%101
SAVE10001
NEW_USER011
NEWUSER001
✓ 4 rows · real output from the Playground database

Unescaped, '%_%' means "at least one character", so it matches every code. With ! as the escape character, !_ means a real underscore. Any character not used in the data can be the escape character.

LIKE on Numbers and Dates

LIKE works on text. Dates in the Playground are text in YYYY-MM-DD form, so a prefix pattern finds a month:

SQLite · runs in the Playground
SELECT COUNT(*) AS orders_in_dec_2024
FROM orders
WHERE order_date LIKE '2024-12-%';

▶ Run this query in the SQL Playground

Orders in December 2024 found with LIKE
orders_in_dec_2024
6
✓ 1 row · real output from the Playground database

It works, but a range (order_date >= '2024-12-01' AND order_date < '2025-01-01') is the better habit: it works for real date types in every database and can use an index. For numbers, compare numerically with BETWEEN or >; CAST(price AS TEXT) LIKE '1%' runs but is rarely what you mean.

LIKE and Indexes

PatternCan use a normal index?Why
LIKE 'Pro%'Often yesA fixed prefix is a range in the sorted index (SQLite needs case-insensitive matching or a matching collation)
LIKE '%son'NoAny value could end with "son", so every row is checked
LIKE '%Set%'NoSame: a leading wildcard
LOWER(name) LIKE 'pro%'Only with an expression index on LOWER(name)The function hides the column

For "contains" searches over large text, databases offer full-text search: FTS5 in SQLite, tsvector in PostgreSQL, FULLTEXT indexes in MySQL and SQL Server.

Common LIKE Mistakes

Five errors and how to avoid them.

1. Using = with wildcards

❌ Looks for a literal %
SQL
SELECT * FROM users
WHERE last_name = 'A%';
✅ LIKE activates the wildcards
SQL
SELECT * FROM users
WHERE last_name LIKE 'A%';

With =, the % is just a character, so only a name that is literally "A%" would match.

2. Forgetting a % in a contains search

❌ Only names starting with Set
SQL
WHERE name LIKE 'Set%'
✅ Set anywhere
SQL
WHERE name LIKE '%Set%'

Each side of the word needs its own % to allow text before and after it.

3. Assuming LIKE ignores case everywhere

❌ Misses rows in PostgreSQL
SQL
WHERE name LIKE '%set%'  -- 0 rows in PostgreSQL
✅ Portable
SQL
WHERE LOWER(name) LIKE '%set%'

SQLite and MySQL ignore case by default; PostgreSQL and Oracle do not.

4. One LIKE with several values

❌ Not valid
SQL
WHERE email LIKE ('%@gmail.com', '%@yahoo.com')
✅ One LIKE per pattern
SQL
WHERE email LIKE '%@gmail.com'
   OR email LIKE '%@yahoo.com'

LIKE compares with one pattern. Combine several with OR.

5. Leading wildcards on a big table

❌ Full scan every time
SQL
WHERE name LIKE '%phone%'   -- millions of rows
✅ Prefix search or full-text
SQL
WHERE name LIKE 'phone%'
-- or a full-text index for word searches

A leading % rules out an index range. On large tables, design the search so it can use an index.

LIKE Cheat Sheet

TaskPattern
Starts with abcLIKE 'abc%'
Ends with abcLIKE '%abc'
Contains abcLIKE '%abc%'
Second letter is aLIKE '_a%'
Exactly 4 charactersLIKE '____'
Does not contain abcNOT LIKE '%abc%'
Literal %LIKE '%!%%' ESCAPE '!'
Ignore case anywhereLOWER(col) LIKE '%abc%' (PostgreSQL: ILIKE)

Practice LIKE Queries

5 exercises on the real Playground tables.

Write each query yourself first. Every solution has been run against the Playground database.

  1. 1Easy List the products whose name ends with "Kit". Table: products

    Show solution
    SQLite · runs in the Playground
    SELECT name, category
    FROM products
    WHERE name LIKE '%Kit'
    ORDER BY name;

    ▶ Run this query in the SQL Playground

    The % goes before the fixed ending.

  2. 2Easy Count the employees whose title contains "Engineer". Table: employees

    Show solution
    SQLite · runs in the Playground
    SELECT COUNT(*) AS engineers
    FROM employees
    WHERE title LIKE '%Engineer%';

    ▶ Run this query in the SQL Playground

    Contains needs % on both sides; it also matches "Engineering".

  3. 3Medium List the distinct first names that are exactly four letters long. Table: users

    Show solution
    SQLite · runs in the Playground
    SELECT DISTINCT first_name
    FROM users
    WHERE first_name LIKE '____'
    ORDER BY first_name
    LIMIT 8;

    ▶ Run this query in the SQL Playground

    Four underscores mean exactly four characters.

  4. 4Medium Count the users per email provider for Gmail, Yahoo and everyone else. Table: users

    Show solution
    SQLite · runs in the Playground
    SELECT CASE WHEN email LIKE '%@gmail.com' THEN 'Gmail'
                WHEN email LIKE '%@yahoo.com' THEN 'Yahoo'
                ELSE 'Other'
           END AS provider,
           COUNT(*) AS users
    FROM users
    GROUP BY provider
    ORDER BY users DESC;

    ▶ Run this query in the SQL Playground

    LIKE works inside CASE as well as in WHERE.

  5. 5Medium Count the reviews whose comment mentions "price" in any capitalisation. Table: reviews

    Show solution
    SQLite · runs in the Playground
    SELECT COUNT(*) AS mentions_price
    FROM reviews
    WHERE LOWER(comment) LIKE '%price%';

    ▶ Run this query in the SQL Playground

    LOWER makes the search work the same way in every database.

📝 Quiz — LIKE

Test your understanding · 0/6 answered

Question 1 of 6

What does the SQL LIKE operator do?

Question 2 of 6

Which condition finds names starting with "Ra"?

Question 3 of 6

What does % match?

Question 4 of 6

What does LIKE '_erry' match?

Question 5 of 6

Which pattern finds values containing "phone"?

Question 6 of 6

What does NOT LIKE do?

LIKE Interview Questions

Q1. What is the difference between % and _?

% matches any number of characters, including none; _ matches exactly one character.

Q2. Is LIKE case-sensitive?

It depends on the database. SQLite and MySQL (default collations) ignore case, PostgreSQL and Oracle do not, and SQL Server depends on the collation. PostgreSQL has ILIKE; LOWER(col) LIKE works everywhere.

Q3. Why is LIKE '%abc' slow on large tables?

A leading wildcard means the value can start with anything, so a sorted index cannot narrow the search and every row is checked. Use a prefix search or full-text search.

Q4. How do you search for a literal underscore?

Escape it: LIKE '%!_%' ESCAPE '!'. Without the escape, _ means any single character.

Q5. How do you match several patterns?

Combine LIKE conditions with OR. PostgreSQL also has LIKE ANY (ARRAY[...]) and SIMILAR TO, and several databases offer regular expressions (REGEXP, ~, REGEXP_LIKE).

Frequently Asked Questions

What does the SQL LIKE operator do?

LIKE searches for a pattern in a text value instead of an exact match. It uses two wildcards: % (any number of characters) and _ (exactly one character), usually in a WHERE clause. Example: WHERE email LIKE '%@gmail.com'.

What is the difference between % and _ in SQL LIKE?

% matches zero or more characters, so 'Ja%' matches Ja, James and Jason. _ matches exactly one character, so '_ar%' matches Mark and Sarah but not Arthur.

Why does 'A%' not work with =?

With =, the percent sign is treated as an ordinary character, so WHERE name = 'A%' only finds a name that is literally A%. Use LIKE to make % a wildcard.

Is SQL LIKE case-sensitive?

It depends on the database. SQLite and MySQL (with default collations) ignore case. PostgreSQL and Oracle are case-sensitive; PostgreSQL offers ILIKE. SQL Server depends on the collation. The portable approach is WHERE LOWER(name) LIKE '%abc%'.

What does NOT LIKE do?

NOT LIKE returns the rows whose value does not match the pattern. WHERE name NOT LIKE 'A%' returns every name that does not start with A. Rows where the column is NULL are returned by neither LIKE nor NOT LIKE.

Can SQL LIKE search numbers?

Only as text: a text column, or a number converted with CAST. For numeric conditions, BETWEEN and comparison operators are clearer and faster.

Can SQL LIKE search dates?

If dates are stored as text in YYYY-MM-DD form, as in the Playground, WHERE order_date LIKE '2024-12-%' works. A date range (>= start AND < end) is better: it works with real date types and can use an index.

Does SQL LIKE use indexes?

Only when the pattern starts with fixed text. LIKE 'Ra%' can use an index; LIKE '%Ra%' cannot and reads every row. For large contains searches, use full-text search.

What is PostgreSQL ILIKE?

ILIKE is PostgreSQL's case-insensitive LIKE: WHERE name ILIKE 'a%' matches Alice, alice and ALICE. It is not available in MySQL, SQL Server or SQLite.

What is the difference between LIKE and ILIKE?

In PostgreSQL, LIKE is case-sensitive and ILIKE is not. In databases where LIKE already ignores case, such as SQLite and MySQL, ILIKE does not exist.

Can SQL LIKE search email addresses?

Yes. WHERE email LIKE '%@gmail.com' finds Gmail addresses, WHERE email LIKE 'john%' finds addresses starting with john, and WHERE email LIKE '%@%.edu' finds .edu addresses.

Can SQL LIKE search phone numbers?

Yes, as text. WHERE phone LIKE '+1-%' finds numbers with that prefix, and WHERE phone LIKE '+1-___-___-____' checks a fixed layout: every phone number in the Playground matches it.

Can SQL LIKE match special characters?

Only % and _ have a special meaning; dashes, dots, @ and spaces match literally. To search for a literal % or _, use ESCAPE, for example WHERE code LIKE '%!%%' ESCAPE '!'.