Skip to content
<ReviewPublically/>
  • Data Science
  • Machine Learning
  • Deep Learning
    • Claude 3.5 Sonnet
    • Gemini AI
    • MidJourney AI
    • Sora AI
    • Poe AI
  • Write for Us
Compare AI tools Subscribe
SQL WHERE Clause Explained with Examples (2026)
Home / Data Science / SQL for Data Science / WHERE Clause
🔍 SQL Cluster — 2 of 15

SQL WHERE Clause Explained with Examples (2026)

A query that checks WHERE email = NULL silently returns zero rows — every time, on every database — and most beginners spend twenty minutes debugging the wrong thing before finding out why. This guide covers WHERE from a single condition to combined AND/OR/NOT logic, BETWEEN, IN, LIKE wildcards, NULL handling, and the precedence trap that quietly returns the wrong rows in production.

KH by Khalid Hussain •Published Jul 29, 2026 •🕐 12 min read
In This Article
  1. Quick answer
  2. Comparison operators
  3. AND, OR, NOT
  4. The precedence trap
  5. BETWEEN and IN
  6. LIKE and wildcards
  7. NULL: the operator that isn't
  8. WHERE vs HAVING
  9. Beginner mistakes
  10. Filter early: a performance note
  11. Practice queries
  12. FAQs
  13. Conclusion

Quick Answer: What Does WHERE Actually Filter?

▶ Direct Answer — SQL WHERE Clause

WHERE filters which rows a query returns by testing each row against a condition — only rows where the condition evaluates true are kept. It supports comparison operators (= > < >= <= !=), logical operators (AND, OR, NOT), range and set matching (BETWEEN, IN), pattern matching (LIKE), and NULL checks (IS NULL). It runs early in a database's logical processing order — after FROM, before SELECT, GROUP BY, and ORDER BY — which is exactly why it can't reference a SELECT alias or an aggregate function.

6
core comparison operators every WHERE clause is built from
= > < >= <= !=
0
rows returned by WHERE column = NULL, on any database, ever
Use IS NULL instead
2nd
clause SQL evaluates, right after FROM and before SELECT
Logical processing order

Comparison Operators: The Building Blocks

Every WHERE clause is built from a small set of comparison operators, combined and chained as needed.

sqlCOMPARISON_OPERATORS.SQL
SELECT order_id, order_total
FROM orders
WHERE order_total > 100;

-- not-equal has two spellings, both standard
SELECT * FROM orders WHERE status != 'cancelled';
SELECT * FROM orders WHERE status <> 'cancelled';

The six you need: = equal, != or <> not equal, > greater than, < less than, >= greater than or equal, <= less than or equal. Both not-equal spellings are standard SQL and behave identically — != is more common in practice, but <> shows up often enough in older codebases and other languages' SQL dialects that you should recognize it on sight.

AND, OR, NOT: Combining Conditions

Real filtering rarely stops at one condition. AND requires every condition to be true, OR requires at least one, and NOT inverts whatever follows it.

sqlAND_OR_NOT.SQL
-- both conditions must be true
SELECT * FROM orders
WHERE order_total > 100 AND status = 'shipped';

-- either condition can be true
SELECT * FROM orders
WHERE status = 'pending' OR status = 'processing';

-- invert a condition
SELECT * FROM orders
WHERE NOT status = 'cancelled';

That last example is functionally identical to WHERE status != 'cancelled' — both are valid, and which one reads more naturally depends on the condition. NOT becomes more useful once conditions get more complex, for example WHERE NOT (status = 'cancelled' OR status = 'refunded').

The Precedence Trap: Why Parentheses Aren't Optional

This is the single highest-stakes mistake in this article, because it doesn't error — it silently returns the wrong rows. SQL evaluates AND before OR by default, the same way multiplication is evaluated before addition in arithmetic.

sqlPRECEDENCE_TRAP.SQL
-- INTENT: orders that are (pending OR processing) AND over $100
-- WHAT IT ACTUALLY DOES: (pending) OR (processing AND over $100)
SELECT * FROM orders
WHERE status = 'pending' OR status = 'processing' AND order_total > 100;

-- CORRECT: parentheses force the intended grouping
SELECT * FROM orders
WHERE (status = 'pending' OR status = 'processing') AND order_total > 100;

The broken version silently includes every single pending order regardless of total, because AND binds tighter than OR and grabs status = 'processing' AND order_total > 100 as one unit before OR ever applies. The row count often looks plausible, which is exactly what makes this bug dangerous — it rarely throws an error, it just quietly returns a report that's wrong.

⚠ Rule of thumb

Any time a WHERE clause mixes AND and OR, add parentheses explicitly — even when you're confident about the default precedence. The cost of an extra pair of parentheses is nothing; the cost of a silently wrong report is a bad decision made on bad data.

BETWEEN and IN: Cleaner Range and Set Matching

BETWEEN and IN are shorthand for patterns you'd otherwise write with several chained comparisons.

sqlBETWEEN_IN.SQL
-- BETWEEN is inclusive on both ends
SELECT * FROM orders
WHERE order_date BETWEEN '2026-01-01' AND '2026-01-31';

-- IN replaces a chain of OR = comparisons
SELECT * FROM orders
WHERE status IN ('pending', 'processing', 'shipped');

-- NOT IN excludes a set
SELECT * FROM orders
WHERE status NOT IN ('cancelled', 'refunded');

BETWEEN is inclusive on both boundary values — BETWEEN '2026-01-01' AND '2026-01-31' includes both January 1st and January 31st. This becomes a real trap on datetime columns with a time component: a timestamp of 2026-01-31 14:00:00 is excluded by that same BETWEEN, because it's later than the implicit midnight boundary on the 31st. For datetime ranges, comparing with >= and < against the start of the next day is usually safer than BETWEEN.

LIKE and Wildcards: Pattern Matching Text

LIKE matches text against a pattern using two wildcards: % matches any sequence of characters (including zero), and _ matches exactly one character.

sqlLIKE_WILDCARDS.SQL
-- starts with 'A'
SELECT * FROM customers WHERE first_name LIKE 'A%';

-- ends with '.com'
SELECT * FROM customers WHERE email LIKE '%.com';

-- contains 'gmail' anywhere
SELECT * FROM customers WHERE email LIKE '%gmail%';

-- exactly 5 characters, starting with 'A'
SELECT * FROM products WHERE sku LIKE 'A____';
DatabaseLIKE case sensitivityCase-insensitive option
PostgreSQLCase-sensitiveILIKE
MySQLUsually insensitiveDepends on collation
BigQueryCase-sensitiveLOWER() both sides

A leading % wildcard (LIKE '%gmail%') generally cannot use a standard index efficiently, since the database can't know where in the text to start scanning — worth knowing before reaching for it on a large table in a performance-sensitive query.

NULL: The Operator That Isn't

NULL represents an unknown or missing value — not zero, not an empty string, not "false." Because it's unknown, SQL can't say NULL = NULL is true, since it doesn't know either value. This is why WHERE column = NULL always returns zero rows, silently, on every SQL database.

sqlNULL_HANDLING.SQL
-- WRONG: this returns zero rows, always
SELECT * FROM customers WHERE email = NULL;

-- CORRECT
SELECT * FROM customers WHERE email IS NULL;
SELECT * FROM customers WHERE email IS NOT NULL;
Why this happens

SQL uses three-valued logic: TRUE, FALSE, and UNKNOWN. Any comparison involving NULL — with =, !=, >, anything — evaluates to UNKNOWN, and WHERE only keeps rows where the condition is TRUE. UNKNOWN is treated the same as FALSE for filtering purposes, so the row gets silently dropped either way.

WHERE vs HAVING: Different Points in the Pipeline

WHERE and HAVING both filter, but at different stages, which is why they can't be swapped for each other.

  • WHERE filters individual rows before any grouping or aggregation happens — it operates on raw table data.
  • HAVING filters groups after GROUP BY has aggregated rows — it can reference aggregate functions like SUM() or COUNT() that don't exist yet when WHERE runs.
  • Trying to use an aggregate in WHERE — for example WHERE SUM(order_total) > 1000 — throws an error in every major database, because at that point in the logical order, no aggregation has happened yet.

GROUP BY and HAVING get full treatment in their own article later in this cluster — the distinction here is worth knowing early, since "why can't I use SUM in WHERE" is one of the most common early SQL errors.

Mistakes That Give Away a Beginner

  • Using = NULL instead of IS NULL. Silent, zero rows, no error — the hardest kind of bug to notice.
  • Mixing AND/OR without parentheses. Covered in depth above — the single highest-stakes mistake in this article because it returns a plausible-looking wrong answer instead of an error.
  • Referencing a SELECT alias inside WHERE. WHERE runs before the SELECT list is evaluated, so an alias defined there doesn't exist yet — repeat the full expression instead.
  • Reaching for an aggregate function in WHERE. SUM, COUNT, AVG and friends belong in HAVING, not WHERE, because they don't exist until after grouping.
  • Assuming BETWEEN excludes the boundary. It's inclusive on both ends — a frequent off-by-one source on date ranges with a time component.

Filter Early: A Performance Note

WHERE conditions that run against an indexed column are typically fast even on large tables, since the database can jump directly to matching rows instead of scanning every one. Filtering on a calculated expression — for example WHERE UPPER(email) = 'TEST@EXAMPLE.COM' — usually prevents the database from using a standard index on that column, since it has to compute the expression for every row before it can compare.

Practical habit

When a query involving a join is slow, check whether your WHERE conditions are filtering before or after the join happens in the query plan. Filtering the smaller table down first, before joining, is usually faster than joining everything and filtering the combined result afterward — the query planner often does this automatically, but not always.

Practice: Write These Three Filters Yourself

Using the same orders table from the SELECT article (order_id, customer_id, product_name, price, quantity, order_date, status), try writing these:

1

Combine a range and a set

Return orders placed in March 2026 with a status of either "shipped" or "delivered."

2

Handle a missing value

Return every order where customer_id is missing (never assume you can use = for this).

3

Force the right precedence

Return orders that are either "pending" or "processing," and separately, always over $50 — using parentheses to guarantee correct grouping.

Frequently Asked Questions

What does the WHERE clause do in SQL?

WHERE filters which rows a query returns by testing each row against a condition — only rows where the condition evaluates true are included. It runs after FROM but before SELECT, GROUP BY, and ORDER BY in the database's logical processing order.

Why doesn't WHERE column = NULL work in SQL?

NULL represents an unknown value, and in SQL's three-valued logic, any comparison to NULL using = returns unknown rather than true, so no rows match. Use IS NULL or IS NOT NULL instead, which are specifically designed to test for the presence or absence of a value.

What is the difference between WHERE and HAVING in SQL?

WHERE filters individual rows before any grouping or aggregation happens. HAVING filters groups after GROUP BY has aggregated them, and can reference aggregate functions like SUM() or COUNT() that WHERE cannot use, because those aggregates don't exist yet at the point WHERE runs.

How do you combine multiple conditions in a WHERE clause?

Use AND to require both conditions, OR to require either, and NOT to invert a condition. When mixing AND and OR in the same clause, use parentheses explicitly, since AND has higher precedence than OR by default and relying on that default silently changes which rows match.

What does the SQL LIKE operator do?

LIKE matches text against a pattern using two wildcards: percent (%) matches any sequence of characters, including none, and underscore (_) matches exactly one character. For example WHERE name LIKE 'A%' matches any name starting with A.

Is SQL LIKE case-sensitive?

It depends on the database. PostgreSQL's LIKE is case-sensitive by default, with a separate ILIKE operator for case-insensitive matching. MySQL's LIKE is case-insensitive by default under typical collations. Always verify behavior on the specific database you're using rather than assuming.

🗃️
SQL for Data Science: The Complete GuideThe full pillar — where WHERE fits in the bigger picture
🔍
SQL SELECT Statement: A Complete GuideChoosing the columns WHERE will filter
⇅️
SQL ORDER BY and LIMITSorting and capping the rows WHERE returns
📊
SQL GROUP BY and HAVINGFiltering groups instead of individual rows

Conclusion: Filter Deliberately, Not by Default

WHERE gives you comparison operators, AND/OR/NOT, BETWEEN, IN, LIKE, and NULL checks — a small toolkit that covers nearly every filtering need once you know exactly how each piece behaves. The two habits worth carrying forward from this article: always use IS NULL instead of = NULL, and always add parentheses the moment AND and OR appear in the same clause. Neither costs you anything, and both prevent the specific kind of bug that doesn't error — it just quietly returns the wrong answer.

Practice the three filters above against a real table, then move to the next article in this cluster, which covers ORDER BY and LIMIT — sorting and capping the rows WHERE hands back.

🗃️ Continue the SQL Cluster

Next Up: ORDER BY and LIMIT

WHERE decides which rows survive — ORDER BY and LIMIT decide what order they come back in and how many. Continue the fundamentals tier of this cluster.

▶  Read the ORDER BY & LIMIT Guide
references — primary sources
  1. PostgreSQL SELECT / WHERE Documentation — postgresql.org
  2. MySQL Expression & Operator Reference — dev.mysql.com
  3. PostgreSQL Comparison Operators & NULL Handling — postgresql.org
  4. Review Publically — SQL SELECT Statement: A Complete Guide
  5. Review Publically — SQL for Data Science: The Complete Guide
#SQL #SQLWhere #DataScience #Beginner #SQLSyntax
Share X in 🔗
KH

Khalid Hussain

Founder of Review Publically. MSc holder and Google Advanced Data Analytics certified. Teaches SQL and Python data analysis with a focus on current, correct, production-ready syntax rather than outdated conventions.

About Khalid GitHub Twitter / X

Related Articles

Keep building your SQL skills

SQL

SQL SELECT Statement: A Complete Guide

The columns WHERE filters

SQL

SQL for Data Science: The Complete Guide

The full 15-article pillar and cluster

Data Science

Data Science Tutorials & Resources

Free roadmap from SQL to MLOps

ReviewPublically

Your trusted platform for AI reviews, data science guides and machine learning insights to stay ahead in tech.

FB X GH

Data Science

  • Descriptive statistics
  • Inferential statistics
  • Python for data science
  • Pandas

Machine Learning

  • Concept drift
  • Random forest
  • Imbalanced datasets
  • Decision tree

Deep Learning

  • Convolutional neural network
  • Linear regression
  • Logistic regression

AI Reviews

  • Gemini AI
  • MidJourney AI
  • Claude 3.5 Sonnet
  • Brisk Teaching AI

Site

  • About
  • Write for us
  • Contact
  • Privacy policy
  • Terms

© 2026 Review Publically — All rights reserved.

Written and reviewed by practitioners.

  • About Us
  • AI Comparison Tool l Reviewpublically
  • AI for Excel Analysis: Best Tools to Automate Spreadsheets in 2026
  • AI Model Pricing
  • AI Reviews Hub – Honest & In-Depth Reviews
  • Articles
  • Blog – Latest AI Tools Reviews
  • Contact
  • Data Science Tutorials & Resources
    • Pandas Library Python: Complete Guide for Data Analysis (2026)
  • Disclaimer
  • Editorial Policy
  • Guest Post on ReviewPublically: Write for Us
  • MidJourney AI Guide (2025): Features, Pricing, Versions & Use Cases
  • Model Interpretability Techniques: A Complete Learning Guide
  • Privacy Policy
  • Review Publically: Your Trusted Hub for AI, Data Science & Tech Insights
  • SQL for Data Science
  • Terms & Conditions
  • What is Deep Learning
  • What Is Gemini AI (Gemini 3)? Complete Guide to Google’s Multimodal Intelligence, Image Prompts & Search Benefits
  • What is Machine Learning?
    • Decision Tree in Machine Learning – Complete Guide & Practical Tutorial
  • 📊 Excel Spreadsheet: How to Create, Use & Automate Spreadsheets with AI
Manage Consent
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
View preferences
  • {title}
  • {title}
  • {title}