Filtering: Intermediate

When you search Airbnb for a place to stay in Paris for under 150 dollars a night with a kitchen, Airbnb queries millions of listings using exactly the kind of filtering you are about to learn. It combines date availability checks, price range filters, location matching, and amenity conditions to return personalized results in under a second. A query that complex requires BETWEEN for price ranges, LIKE for location pattern matching, IN for amenity lists, and OR logic to handle alternative criteria. The intermediate filtering techniques in this lesson are what power that search.

OR and CASE expressions

Daily Life
Interviews

Branch logic inside your queries

SQL has two core tools for branching logic. OR branches in the WHERE clause to decide which rows to keep. CASE WHEN branches in SELECT to decide what value each row should produce.

OR: Branching in WHERE

The OR operator returns rows that satisfy at least one of multiple conditions. Unlike AND, which requires all conditions to be true, OR is inclusive. A row passes the filter if any single condition evaluates to true.

1SELECT
2 user_id,
3 country
4FROM users
5WHERE country = 'US'
6OR country = 'CA'
7OR country = 'UK'
Result
user_idcountry
user_42US
user_89CA
user_156UK

Each condition is checked in sequence. If any evaluates to true, the row is included. When you have many OR conditions on the same column, the IN operator is a cleaner shorthand.

CASE WHEN in SELECT

While OR decides which rows to include, CASE WHEN decides what value to produce for each row. It evaluates conditions top to bottom and returns the value for the first match:

1SELECT
2 order_id,
3 amount,
4 CASE
5 WHEN amount >= 500 THEN 'high'
6 WHEN amount >= 100 THEN 'medium'
7 ELSE 'low'
8 END AS priority
9FROM orders
Result
order_idamountpriority
1001720high
100245low
1003250medium
100490low

The CASE expression checks each WHEN condition in order. The first true condition determines the result. If none match, ELSE provides a default. Without ELSE, unmatched rows return NULL.

CASE WHEN SYNTAX
  • CASE starts the expression
  • WHEN condition THEN value: one branch (repeat as needed)
  • ELSE value: default if no conditions match (optional)
  • END closes the expression (required)

How They Compare

Both OR and CASE WHEN evaluate conditions, but they serve different purposes:

OR vs CASE WHEN
  • OR is used in WHERE to filter rows (keep or discard)
  • CASE is used in SELECT to produce a new column value per row
  • OR changes which rows appear in results
  • CASE changes what values appear in results
Which approach labels users as admin vs non-admin?
OR filters to only matching rows. Other users are excluded entirely.
1SELECT
2 *
3FROM users
4WHERE role = 'admin'
5OR role = 'editor'

Try using CASE WHEN to classify rows based on a condition.

> Complete this query to label orders as "high" when the amount is 500 or more, and "low" otherwise.

SELECT
  order_id,
  amount,
  ___
    ___ amount >= 500 THEN 'high'
    ELSE 'low'
  END AS priority
FROM orders
OR
WHEN
CASE
WHERE

OR is fundamentally different from AND: it expands your result set rather than narrowing it, so a single true condition is enough to keep a row.

CASE WHEN is one of the most versatile tools in SQL because it lets you embed conditional logic directly inside a SELECT list without filtering any rows out.

When you have many OR conditions on the same column, replacing them with an IN list makes the query significantly easier to read and extend.

Operator precedence

Daily Life
Interviews

Control how filter conditions evaluate

SQL evaluates operators in a specific order. Knowing this order prevents logical errors in complex conditions.
//

Default Evaluation Order

Parentheses () control the order in which SQL evaluates conditions. They act as explicit grouping tools that override default logical precedence. Without parentheses, SQL follows a fixed hierarchy:

• Comparison operators (=, <, >, IN) • Logical NOT • Logical AND • Logical OR

When a condition involves multiple operators, parentheses ensure the database interprets your intent correctly. They determine which comparisons are grouped and how combined conditions interact.
//

Without Parentheses

1SELECT
2 user_id,
3 country,
4 status,
5 total_spent
6FROM users
7WHERE country = 'US'
8AND status = 'active'
9OR total_spent > 1000
Result
user_idcountrystatustotal_spent
user_42USactive500
user_89USactive750
user_156CAinactive1200
user_203UKinactive1500

The animation below shows how SQL actually evaluates this WHERE clause. Notice the order of operations: comparisons first, then the AND, then the OR.

Multi Condition Or
users
user_idcountrystatustotal_spent
user_42USactive500
user_89USactive750
user_156CAinactive1200
user_203UKinactive1500
user_310USinactive300
result
user_idcountrystatustotal_spent
Step 1/5

Without parentheses, this expression evaluates as: (country = 'US' AND status = 'active') OR (total_spent > 1000)

The AND executes before OR. As a result, it returns both active U.S. users and any users (in any country) who have spent more than 1000.

Parentheses for Control

Parentheses let you override the default precedence and group conditions exactly how you intend.
//

Explicit Grouping

1SELECT
2 user_id,
3 country,
4 status,
5 total_spent
6FROM users
7WHERE country = 'US'
8AND (
9 status = 'active'
10 OR total_spent > 1000
11)
Result
user_idcountrystatustotal_spent
user_42USactive500
user_89USactive750
user_305USinactive1200

Now the parentheses force SQL to evaluate the OR condition first. The query returns only users in the U.S. who are either active or high spenders. This difference in parentheses changes the meaning, and the result set, completely.

//

Nested Parentheses

Parentheses can also be nested to group multiple logical layers:
1SELECT
2 order_id,
3 region,
4 total
5FROM orders
6WHERE (
7 region IN (
8 'US',
9 'CA'
10 )
11 AND total > 500
12)
13OR (
14 region = 'UK'
15 AND total > 1000
16)
Result
order_idregiontotal
ORD-101US750
ORD-203CA685
ORD-405UK1200
Here, parentheses group conditions by region, creating two distinct rule sets: • U.S. or Canadian orders over 500 • U.K. orders over 1000

The database evaluates each group independently, then combines them using OR.

Explicit Grouping
Parentheses override default precedence rules
Readability
Prevent logical ambiguity for future readers
Nested Evaluation
Innermost parentheses are evaluated first
Don't Overdo It
Use parentheses for clarity, not clutter
Key Insight: Parentheses don't make queries faster, but they make them correct. Logical grouping defines your analytical logic precisely, ensuring SQL interprets filters exactly as intended.
Do these two queries return the same results?
Without parentheses, AND binds tighter: this returns ALL US orders plus only CA orders over 500.
1SELECT
2 *
3FROM orders
4WHERE country = 'US'
5OR country = 'CA'
6AND total > 500
TIP
When mixing AND and OR, always use parentheses. Even if you know the precedence rules, the next person reading your query might not.

> Complete this query to find US or Canadian orders over 500, using parentheses to group correctly.

SELECT
  order_id,
  country,
  total
FROM orders
WHERE (
  country = 'US'
  ___ country = 'CA'
)
___ total > 500
AND
NOT
IN
OR
Parentheses cost nothing in terms of query performance but prevent an entire class of logical bugs that are notoriously hard to catch during code review.

The AND-before-OR precedence rule trips up experienced engineers regularly. Treating parentheses as mandatory whenever you mix AND and OR is the safest habit to develop.

Operator precedence becomes especially important in compliance or financial queries where an incorrect logical grouping can include or exclude thousands of rows silently.

LIKE for pattern matching

Daily Life
Interviews

Search text with wildcard patterns

When exact matching is too restrictive, pattern matching lets you find rows based on partial values.
//

Why use LIKE?

When you only know part of a value, such as the prefix of an email, the substring of a URL, or the final digits of an ID, LIKE lets you match flexible patterns without writing multiple OR clauses.

LIKE supports two wildcards: % matches zero or more characters, and _ matches exactly one character. Combine them to target just the pieces you care about.

Common LIKE patterns:

1SELECT
2 *
3FROM users
4WHERE name LIKE 'Ann%'
Result
user_idnameemail
U001Annaanna@email.com
U015Annieannie@work.com
U023Annetteannette@mail.org
The first pattern starts with Ann, the second ends with @company.com, and the third uses underscores for unknown digits.

Wildcard Patterns

The power of LIKE comes from wildcards that match variable portions of text.

//

Suffix Matching

1SELECT
2 customer_id,
3 email
4FROM customers
5WHERE email LIKE '%@orbit.ai'
Result
customer_idemail
cust_041maria@orbit.ai
cust_088logan@orbit.ai
cust_134xi.chen@orbit.ai
This filter keeps any email ending with @orbit.ai regardless of the username. The database scans the email column row by row and keeps entries whose suffix matches the wildcard pattern.

You can invert the logic with NOT LIKE, or add multiple patterns using OR/AND for more explicit control.

Which pattern finds emails ending in .com?
This looks for emails that start with ".com", which is not what we want.
1SELECT
2 *
3FROM users
4WHERE email LIKE '.com%'

Pattern matching with LIKE is one of the most practical filtering techniques in everyday SQL.

> Complete this query to find all products whose name starts with "Pro".

SELECT
  product_id,
  product_name
FROM products
WHERE product_name ___ ___
LIKE
'%Pro'
'Pro%'
=
The percent wildcard % matches zero or more characters, while the underscore _ matches exactly one character.
Place % before a term to match endings, after a term to match beginnings, or on both sides to match anywhere in the string.

LIKE is case-sensitive by default in most databases. Wrap both sides in LOWER() for case-insensitive matching.

LIMIT and OFFSET for pagination

Daily Life
Interviews

Return results one page at a time

Large tables can return millions of rows. LIMIT keeps results manageable and queries performant.

//

Why limit rows?

Production tables regularly hold millions of rows, but dashboards rarely need the full data set. LIMIT lets you cap how many rows return, keeping result sets predictable and fast.

LIMIT is typically paired with ORDER BY so the "top" rows are deterministic. Otherwise you may get a different subset on each run.

//

Example

1SELECT
2 customer_id,
3 total_spent
4FROM customer_metrics
5ORDER BY total_spent DESC
6LIMIT 5
Result
customer_idtotal_spent
cust_48219450.00
cust_07718825.00
cust_92117290.00
cust_15616890.00
cust_40315740.00

Here we sort by the metric we care about, then keep only the first five rows. LIMIT always goes at the end of the statement.

Navigating Large Datasets

OFFSET lets you skip rows, enabling pagination through results page by page.

//

Pagination Syntax

Pair LIMIT with OFFSET to skip rows and paginate through result pages:

1SELECT
2 customer_id,
3 total_spent
4FROM customer_metrics
5ORDER BY total_spent DESC
6LIMIT 5
7OFFSET 10
Result
customer_idtotal_spent
C0894250.00
C1564180.50
C0424095.00
C2013980.25
C1183875.00
This skips the first 10 rows and returns the next 5 (rows 11-15).
BEST PRACTICES
  • Always combine LIMIT with ORDER BY so the returned slice is stable.
  • When sampling data for debugging, LIMIT keeps result sets readable and reduces query costs.
  • Use OFFSET for pagination, but be aware that large offsets can be slow on huge tables.
Which query safely gets the top 5 spenders?
Without ORDER BY, LIMIT returns an arbitrary 5 rows. The result is unpredictable.
1SELECT
2 customer_id,
3 total_spent
4FROM customers
5LIMIT 5

Controlling result size with LIMIT is essential for both performance and usability.

> Complete this query to get the 3 most expensive products.

SELECT
  product_name,
  price
FROM products
ORDER BY price ___
LIMIT ___
ASC
10
DESC
3

Always pair LIMIT with ORDER BY to get deterministic results. Without ORDER BY, the rows returned by LIMIT are unpredictable.

OFFSET skips rows before starting to return results, enabling pagination through large datasets page by page.

Large OFFSET values can be slow because the database must still process all skipped rows internally.

BETWEEN for range filtering

Daily Life
Interviews

Select rows within a value range

BETWEEN provides a clean syntax for filtering values within an inclusive range.

//

What BETWEEN does

BETWEEN expresses inclusive ranges. It translates to "greater than or equal to the lower bound AND less than or equal to the upper bound." It works with numbers, dates, and even text (alphabetical ranges).

It keeps range logic concise, especially when both bounds are constants or parameters.

Combining Multiple Ranges

BETWEEN works seamlessly with AND to filter on multiple range criteria simultaneously.

//

Multi-Range Filtering

1SELECT
2 order_id,
3 order_date,
4 total
5FROM orders
6WHERE order_date BETWEEN '2024-01-01' AND '2024-03-31'
7AND total BETWEEN 500 AND 1500
Result
order_idorder_datetotal
ORD-2042024-01-18640
ORD-2752024-02-05890
ORD-3192024-03-221,420

This query narrows the data set to Q1 orders whose totals fall within a band. Stacking BETWEEN with AND combines date and numeric ranges cleanly.

TIP
BETWEEN is inclusive on both ends. For TIMESTAMP columns, this means BETWEEN '2024-01-01' AND '2024-03-31' includes midnight on March 31st. Use explicit >= / < when you need half-open ranges.

> Complete this query to find orders placed between January 1st and March 31st, 2024.

SELECT
  order_id,
  order_date,
  total
FROM orders
WHERE order_date ___ '2024-01-01'
___ '2024-03-31'
AND
BETWEEN
OR
IN

BETWEEN provides the most readable syntax for inclusive range queries and communicates intent clearly to anyone reviewing the code later.

For date range queries, always consider whether you need inclusive or exclusive boundaries because including midnight on the last day can pull in unexpected records.

Stacking multiple BETWEEN conditions with AND is a clean pattern for filtering data across several dimensions simultaneously, such as date range and value range together.

PUTTING IT ALL TOGETHER

> You are a marketing analyst at Uber building a customer segmentation query that identifies high-value riders for a re-engagement campaign. You need to surface riders who match several overlapping criteria across spend, activity date, and email domain without writing unwieldy chains of conditions.

OR and CASE expressions flag riders who match any one of several high-value tiers such as frequent or premium without requiring separate queries per tier.
Operator precedence rules determine which AND and OR conditions bind first, so parentheses are used to ensure the tier logic groups correctly.
LIKE with wildcard patterns filters email addresses matching company domains like %@corp.com to identify business account riders eligible for enterprise offers.
BETWEEN applies an inclusive date range to restrict the dataset to riders who took at least one trip within the past 90-day re-engagement window.
KEY TAKEAWAYS
OR returns rows matching any of several conditions; a row passes if any single condition is true
AND has higher precedence than OR, so SQL evaluates AND conditions first by default
Parentheses () override default precedence and group conditions explicitly
Always use parentheses when combining AND and OR to make your intent clear
LIKE with % matches zero or more characters; _ matches exactly one character
LIMIT caps the number of returned rows; pair with ORDER BY for consistent results
OFFSET skips rows for pagination (e.g., LIMIT 10 OFFSET 20 returns rows 21-30)
BETWEEN provides inclusive range filtering and works with numbers, dates, and text

Filtering: Intermediate

Boolean logic: it\

Boolean logic: it's complicated

Category
SQL
Difficulty
intermediate
Duration
24 minutes
Challenges
0 hands-on challenges

Topics covered: OR and CASE expressions, Operator precedence, LIKE for pattern matching, LIMIT and OFFSET for pagination, BETWEEN for range filtering

Lesson Sections

  1. OR and CASE expressions (concepts: sqlCaseWhen)

    OR: Branching in WHERE CASE WHEN in SELECT How They Compare Which approach labels users as admin vs non-admin?

  2. Operator precedence (concepts: sqlOperatorPrecedence)

    SQL evaluates operators in a specific order. Knowing this order prevents logical errors in complex conditions. Default Evaluation Order Parentheses () control the order in which SQL evaluates conditions. They act as explicit grouping tools that override default logical precedence. Without parentheses, SQL follows a fixed hierarchy: When a condition involves multiple operators, parentheses ensure the database interprets your intent correctly. They determine which comparisons are grouped and how c

  3. LIKE for pattern matching (concepts: sqlLike)

    When exact matching is too restrictive, pattern matching lets you find rows based on partial values. Why use LIKE? The first pattern starts with Ann, the second ends with @company.com, and the third uses underscores for unknown digits. Wildcard Patterns Suffix Matching This filter keeps any email ending with @orbit.ai regardless of the username. The database scans the email column row by row and keeps entries whose suffix matches the wildcard pattern. Which pattern finds emails ending in .com? T

  4. LIMIT and OFFSET for pagination

    Why limit rows? Example Navigating Large Datasets Pagination Syntax This skips the first 10 rows and returns the next 5 (rows 11-15). Which query safely gets the top 5 spenders?

  5. BETWEEN for range filtering (concepts: sqlBetween)

    What BETWEEN does It keeps range logic concise, especially when both bounds are constants or parameters. Combining Multiple Ranges Multi-Range Filtering For date range queries, always consider whether you need inclusive or exclusive boundaries because including midnight on the last day can pull in unexpected records.