Phase 1 · Reading data: SELECT, WHERE and sorting · Topic 1.3

IN, BETWEEN and LIKE: shorter conditions

Must know

IN checks a value against a list, BETWEEN checks a range (both ends included), and LIKE matches text against a pattern with % (any number of characters) and _ (exactly one).

Not started

Step 1 Understand it

Why you need it. status = 'shipped' OR status = 'pending' OR status = 'cancelled' is long and easy to get wrong. Questions like "names starting with P" or "orders in February" come up all the time. These three words make such conditions short and readable.

New words in this topic (tap one to see what it means)

Watch it happen

AnimationShorter conditions: a list, a range, a pattern
Read the animation as text
  1. IN checks a value against a list: status IN ('shipped', 'pending') is true when status equals any value in it.
  2. Each row is compared with the list. Only 105 and 110 match — the same as status = 'shipped' OR status = 'pending', but shorter.

Picture it

flowchart TD
  V["a value in a row"] --> I["IN (a, b, c)<br/>equal to any one of them?"]
  V --> B["BETWEEN low AND high<br/>low or more, and high or less?"]
  V --> L["LIKE pattern<br/>% any run of characters<br/>_ exactly one character"]
Three shortcuts for common conditions: for a list of values, for a range with both ends included, and for a text pattern.

The idea

IN: status IN ('shipped', 'pending') is true when status equals any value in the list. BETWEEN: amount BETWEEN 50 AND 100 means amount >= 50 AND amount <= 100, ends included. LIKE: product_name LIKE 'P%' matches text starting with P; % stands for any number of characters (even none) and _ for exactly one. Put in front of any of them to flip it: , NOT BETWEEN, NOT LIKE.

The shape of it

sql
WHERE column IN (value1, value2)
WHERE column BETWEEN low AND high
WHERE text_column LIKE 'pattern%'

Words in lower case are the parts you fill in.

How it works, step by step

  1. status IN ('shipped', 'pending') is checked against each order: shipped matches, pending matches, delivered doesn't.
  2. order_date BETWEEN '2024-02-01' AND '2024-02-29' keeps every date from the 1st to the 29th of February, both days included.
  3. product_name LIKE 'P%' keeps Pen and Phone case: P, then anything.
  4. LIKE '%s' keeps names ending in s: Headphones.
  5. LIKE '_en' means exactly one character, then "en": Pen matches, but Phone case doesn't.

Analogy

IN is a guest list: is your name on it? BETWEEN is a height limit at a fair ride: between 1.2 m and 1.9 m, both ends allowed. LIKE is a crossword clue with blanks: "P _ _" fits Pen.

Where the analogy breaks

A guest list doesn't care about missing names, but does: if the list after NOT IN contains a , nothing matches at all. Phase 4 shows this trap.

Worked examples

IN: one of a list

sql
SELECT order_id, status
FROM orders
WHERE status IN ('shipped', 'pending')
ORDER BY order_id;

2 rows

order_idstatus
105shipped
110pending

The same as status = 'shipped' OR status = 'pending', but shorter and harder to get wrong.

BETWEEN: a range of dates

sql
SELECT order_id, order_date, amount
FROM orders
WHERE order_date BETWEEN '2024-02-01' AND '2024-02-29'
ORDER BY order_date;

3 rows

order_idorder_dateamount
1052024-02-02150
1062024-02-12NULL
1072024-02-2060

Both ends are included. This works because the dates are YYYY-MM-DD text; with real timestamps, see the mistakes below.

LIKE: text patterns

sql
SELECT product_name
FROM products
WHERE product_name LIKE 'P%' OR product_name LIKE '%s'
ORDER BY product_name;

3 rows

product_name
Headphones
Pen
Phone case

'P%' finds names starting with P; '%s' finds names ending in s.

Must-know points

  • x IN (a, b) means x = a OR x = b.
  • x BETWEEN a AND b means x >= a AND x <= b — both ends included, and a must be the smaller value.
  • LIKE : % is any number of characters (including none); _ is exactly one character.
  • NOT IN, NOT BETWEEN and NOT LIKE flip each test.
  • A LIKE pattern that starts with % ('%son') can't use a normal , so it is slow on big .

Common mistakes

  • Using BETWEEN on timestamps: BETWEEN '2024-02-01' AND '2024-02-29' misses everything after midnight on the 29th. Use >= '2024-02-01' AND < '2024-03-01' instead.
  • Writing BETWEEN with the bigger value first: BETWEEN 100 AND 50 returns nothing.
  • Forgetting the % in LIKE: LIKE 'P' only matches the exact text P.

In other databases

  • Case: LIKE ignores case in and usually in and , but is case-sensitive in , which has ILIKE for case-insensitive matching.
  • SQL Server also allows [abc] sets in LIKE patterns; PostgreSQL has full regular with ~.

Step 2 Go further (free, optional)

Optional. The notes above are written to be enough on their own. These free resources give a second explanation and more practice.

Step 3 Practise

Try each one yourself first: out loud, or written and run in the practice box below, which saves every query you run. Then open the answer and compare.

  1. ExplainSay what it does and when to use it, in plain words, with no notes.

    Explain what % and _ mean in a LIKE pattern, with one example of each.

    Show answer

    % means "any number of characters, including none". LIKE 'P%' matches anything starting with P: Pen and Phone case.

    _ means "exactly one character". LIKE '_en' matches three-letter words ending in "en": Pen, but not "Phone case" or "en".

    Without % or _, LIKE is just an exact match. In SQLite, LIKE ignores upper and lower case for plain English letters; in PostgreSQL it doesn't (use ILIKE there).

    sql
    SELECT product_name
    FROM products
    WHERE product_name LIKE '_en' OR product_name LIKE 'P%'
    ORDER BY product_name;

    2 rows

    product_name
    Pen
    Phone case
  2. Writefrom a blank page, then run it

    Write a for employees hired in 2020 or 2021, using BETWEEN, showing name and hire_date, sorted by hire_date.

    Show answer

    BETWEEN includes both ends, so run from the first day of 2020 to the last day of 2021. Dates stored as YYYY-MM-DD text compare correctly as text.

    sql
    SELECT name, hire_date
    FROM employees
    WHERE hire_date BETWEEN '2020-01-01' AND '2021-12-31'
    ORDER BY hire_date;

    4 rows

    namehire_date
    Dara2020-02-20
    Ben2020-06-15
    Chen2021-01-10
    Fatima2021-09-12
  3. Predictsay it before you run it

    Which product names match LIKE '%o%'? List them before you run it.

    Show answer

    Headphones, Notebook and Phone case: every name with an "o" anywhere in it. %o% means "anything, then an o, then anything". Pen, Mug, Desk lamp and Backpack have no o.

    sql
    SELECT product_name
    FROM products
    WHERE product_name LIKE '%o%'
    ORDER BY product_name;

    3 rows

    product_name
    Headphones
    Notebook
    Phone case
  4. Edge casesSay what happens with NULLs, ties, duplicates or no rows at all, and fix it.

    Order 106 has a NULL amount. Is it returned by WHERE amount BETWEEN 0 AND 1000? By WHERE amount NOT BETWEEN 0 AND 1000? Why?

    Show answer

    Neither returns it.

    NULL BETWEEN 0 AND 1000 is unknown, because you can't say whether an unknown number is in the range. NOT BETWEEN is NOT unknown, which is still unknown. keeps only where the condition is true, so order 106 falls through both.

    That means "in range" plus "not in range" does not add up to every row when there are NULLs. The query below shows both tests for customer 3's orders.

    sql
    SELECT order_id, amount,
           amount BETWEEN 0 AND 1000 AS in_range,
           amount NOT BETWEEN 0 AND 1000 AS out_of_range
    FROM orders
    WHERE customer_id = 3
    ORDER BY order_id;

    2 rows

    order_idamountin_rangeout_of_range
    106NULLNULLNULL
    1076010

Practice box: write and run your answers here

Ctrl/⌘ + Enter runs it. Select part of the query to run only that part.

Step 4 Interview-ready, then prove it

Your interview answer

About 20 to 40 seconds, said out loud.

IN tests membership in a list and is shorthand for several ORs; BETWEEN tests an inclusive range; LIKE matches text patterns, where percent is any sequence of characters and underscore is exactly one. Two cautions: for timestamps I use a half-open range — greater-or-equal the start and less-than the next day — rather than BETWEEN, and a leading-wildcard LIKE can't use a index.

Follow-up questions

Is BETWEEN inclusive?

Yes, at both ends. BETWEEN 1 AND 5 includes 1 and 5.

How would you find names containing an actual % sign?

Escape it: LIKE '%!%%' ESCAPE '!'. The ESCAPE character says the next % is a real percent sign.

Why is LIKE '%term%' slow?

An index is sorted from the first character, so a pattern that can start anywhere forces a scan of every row. Full-text search indexes solve that.

Tick each check when you can do it without notes

A topic is finished when you pass all four checks, not when you have read it. Be strict: if you had to look at the notes, it is not ticked yet.

  • Explain Say what it does and when to use it, in plain words, with no notes.
  • Write Write the query from a blank page, then run it to check.
  • Predict Read a query and say which rows it returns before you run it.
  • Edge cases Say what happens with NULLs, ties, duplicates or no rows at all, and fix it.

0 of 4 checks ticked.

Saved in this browser. Back it up or move it to another device.