NULL Values: Beginner

In 2012, Knight Capital lost $440 million in 45 minutes when a deployment error left dead code active on one of eight servers, and that server silently routed millions of market orders without the risk checks applied by the other seven. No error was thrown; the system appeared healthy in every log while hemorrhaging money at roughly $10 million per minute. The incident, documented in SEC Order 34-70694 and Doug Seven's widely-read post-mortem, is a canonical example of a silent, non-crashing failure. NULL values create this same class of failure in SQL: they are not zero, not empty string, and they do not equal themselves, so a single missed IS NULL check silently drops rows or corrupts aggregations with no error and no warning. In this lesson you will learn exactly what NULL means, how to safely detect it, and how it changes the behavior of every function that touches it.

NULL vs zero vs empty string

Daily Life
Interviews

Tell the difference between empty and missing

NULL is not a value; it is the absence of a value. Think of it as a placeholder that says "we don't know what goes here" or "this information wasn't provided." This is fundamentally different from zero, an empty string, or the word "null" as text.

Understanding NULL

These three concepts are often confused, but they represent completely different things:
NULL vs Zero vs Empty
  • NULL: Unknown or not provided. Example: user never entered age
  • 0: A known quantity of zero. Example: account balance is $0
  • '' (empty string): An empty text value. Example: name field left blank

Imagine a survey asking for income. NULL means the person skipped the question entirely. Zero means they answered and said they have no income. An empty string would typically be an input error.

Purpose of NULL

Real-world data is incomplete. Not every customer provides a phone number. Not every product has a discount price. Not every employee has a manager. NULL lets databases store this reality without forcing fake values into columns.

1SELECT
2 employee_id,
3 name,
4 manager_id
5FROM employees
Result
employee_idnamemanager_id
1Sarah ChenNULL
2Marcus Lee1
3Priya Singh1
4Omar Davis2

Sarah Chen has NULL for manager_id because she is the CEO and has no manager. This is accurate information, not missing data.

> Complete this query to find orders with missing region data.

SELECT
  order_id,
  region
FROM orders
WHERE region ___ ___
NOT
IS
=
NULL

Understanding the distinction between NULL, zero, and empty string is foundational because each requires a different query pattern and represents a fundamentally different real-world situation.

NULL as a concept reflects an honest acknowledgment that some information is simply unavailable, and databases that store NULL correctly are more truthful than those that substitute zeros or placeholder text.

When you encounter unexpected results in a query involving optional columns, checking whether those columns contain NULL values is almost always the first diagnostic step to take.

Three-Valued Logic

Daily Life
Interviews

Predict how NULLs change query results

Most programming uses two-valued logic: things are either true or false. SQL uses three-valued logic: true, false, or unknown. Any comparison involving NULL returns unknown, not true or false.

Three-Valued Logic

This is why the following comparisons don't work as you might expect:
1SELECT
2 NULL = NULL AS null_equals_null,
3 NULL = 5 AS null_equals_five,
4 NULL != 5 AS null_not_five,
5 NULL > 0 AS null_greater_zero,
6 5 + NULL AS five_plus_null
Result
null_equals_nullnull_equals_fivenull_not_fivenull_greater_zerofive_plus_null
NULLNULLNULLNULLNULL
TIP
NULL is not equal to anything, including itself. This surprises many beginners but makes logical sense: if you don't know what two things are, you can't know if they're equal.

WHERE Clause Behavior

In WHERE clauses, rows only pass through when the condition is true. Unknown conditions filter out the row just like false does.

1SELECT
2 name,
3 age
4FROM users
5WHERE age = 25
Result
nameage
Alice25
Bob25

Users with NULL ages are excluded because comparing NULL to any value yields unknown. They don't appear in the results even though they might be 25 years old.

//

IS NULL vs = NULL

Which query correctly finds rows where region is NULL?

This returns zero rows. The = operator cannot compare to NULL because NULL is not a value. The expression evaluates to UNKNOWN, so no rows pass the filter.
1SELECT
2 *
3FROM orders
4WHERE region = NULL

Now practice with an aggregate function to see how NULL values are excluded from calculations.

> Complete the query to calculate the average discount, keeping in mind how missing values are handled.

SELECT
  ___(___) AS avg_discount
FROM orders
COUNT
AVG
SUM
discount

Three-valued logic is not just an academic curiosity; it has practical consequences every time you write a WHERE clause that filters on a column that can be NULL, because UNKNOWN rows are silently excluded from the result.

The reason NULL does not equal itself is logically sound: if the value is unknown, you cannot make any truthful claim about whether two unknown values are the same or different.

Building the habit of asking "can this column be NULL?" before writing comparison conditions prevents an entire class of silent filtering errors that produce results that look correct but exclude important rows.

IS NULL and IS NOT NULL operators

Daily Life
Interviews

Find or exclude missing values

Since you can't use = or != to check for NULL, SQL provides special operators: IS NULL and IS NOT NULL. These are the only correct ways to filter for NULL values.

Basic NULL Checks

Use IS NULL to find rows where a column has no value:

1SELECT
2 customer_id,
3 name,
4 phone
5FROM customers
6WHERE phone IS NULL
Result
customer_idnamephone
C-103Maya RiveraNULL
C-107Liam ChenNULL
C-112Aisha PatelNULL

This returns only customers who have not provided a phone number. Using WHERE phone = NULL would return zero rows because that comparison is always UNKNOWN.

//

IS NOT NULL

Use IS NOT NULL to find rows where a column has any value:

1SELECT
2 customer_id,
3 name,
4 phone
5FROM customers
6WHERE phone IS NOT NULL
Result
customer_idnamephone
C-101Sarah Chen555-0101
C-102Marcus Lee555-0188
C-105Priya Singh555-0234

This returns customers who have provided phone numbers, excluding anyone with NULL.

Do
  • Always use IS NULL and IS NOT NULL to test for NULL
  • Use COALESCE to provide default values for NULL columns
  • Account for NULL in every WHERE clause that filters optional data
Don't
  • Don't use = NULL or != NULL because they always return unknown
  • Don't assume NULL behaves like zero or empty string
  • Don't forget that NULL propagates through arithmetic

Common Mistakes

This is one of the most common SQL mistakes:
1SELECT
2 *
3FROM customers
4WHERE phone IS NULL
Result
customer_idnamephone
C003CarolNULL
C007GraceNULL

The first query returns nothing because comparing NULL to itself doesn't yield true. The second query correctly identifies NULL values using IS NULL.

> Complete this query to find only customers who have provided a phone number.

SELECT
  name,
  phone
FROM customers
WHERE phone ___ ___ ___
=
NOT
NULL
IS

IS NULL and IS NOT NULL are the only correct tools for testing whether a value is absent, and memorizing this as a rule rather than a guideline will save you from a common category of hard-to-debug errors.

IS NOT NULL is especially useful at the start of a WHERE clause to exclude incomplete records before applying further conditions, ensuring those conditions are evaluated against known values rather than unknowns.

The combination of IS NULL for finding missing data and IS NOT NULL for excluding it covers the vast majority of NULL-filtering scenarios you will encounter in practice.

COUNT(*) vs COUNT(column)

Daily Life
Interviews

Count accurately when data is missing

Aggregate functions like COUNT, SUM, AVG, MIN, and MAX handle NULL in specific ways that can produce unexpected results if you don't understand the rules.

COUNT Behaviors

Consider this orders table with some NULL values in the discount column:

order_idamountdiscount
ORD-00110010
ORD-002200NULL
ORD-00315015
ORD-004300NULL
ORD-00525025
//

COUNT Behaviors

COUNT has two distinct behaviors depending on what you count:

1SELECT
2 COUNT(*) AS total_rows,
3 COUNT(discount) AS rows_with_discount
4FROM orders
Result
total_rowsrows_with_discount
53
COUNT Behavior
  • COUNT(*) counts all rows, including those with NULL values
  • COUNT(column) counts only rows where that column is NOT NULL
  • This difference is intentional and very useful for data quality checks

> Complete this query to count only the valid discount values, skipping any missing entries.

SELECT
  ___(___) AS non_null_count
FROM orders
discount
SUM
COUNT
*

The difference between COUNT(*) and COUNT(column) is one of the most practical distinctions in SQL, because using the wrong one can make a dataset appear more complete than it actually is.

Using both COUNT(*) and COUNT(column) together in a single query is a quick and readable data quality check that immediately shows how many rows have a value in the column of interest.

When reporting on data completeness to stakeholders, the gap between COUNT(*) and COUNT(column) is the number you want to highlight because it represents records that may need to be followed up on.

Aggregates with NULLs

Daily Life
Interviews

Get correct totals despite missing values

Beyond COUNT, other aggregate functions also interact with NULL values in ways that can quietly affect your results.

Other Aggregate Behaviors

SUM and AVG skip NULL values entirely. They don't treat NULL as zero; they pretend those rows don't exist for the calculation.

1SELECT
2 SUM(discount) AS total_discount,
3 AVG(discount) AS avg_discount
4FROM orders
Result
total_discountavg_discount
5016.67

The SUM is 10 + 15 + 25 = 50 (NULL values ignored). The AVG is 50 / 3 = 16.67 (dividing by 3 non-NULL values, not 5 total rows).

TIP
If you expect AVG to treat missing discounts as zero, you'll get wrong results. A 16.67 average looks healthy, but the true average across all orders (treating NULLs as 0) would be 50 / 5 = 10.
//

MIN/MAX Skip NULLs

MIN and MAX also ignore NULL values when finding extremes in a column.

1SELECT
2 MIN(discount) AS min_discount,
3 MAX(discount) AS max_discount
4FROM orders
Result
min_discountmax_discount
1025

MIN and MAX only consider non-NULL values. This is usually the desired behavior, but be aware that it means "minimum discount applied" not "minimum discount overall."

//

All NULLs: Special Case

What happens when ALL values in a column are NULL?

1SELECT
2 SUM(bonus) AS total_bonus,
3 AVG(bonus) AS avg_bonus,
4 COUNT(bonus) AS bonus_count
5FROM employees
Result
total_bonusavg_bonusbonus_count
NULLNULL0

When all values are NULL, SUM and AVG return NULL (not zero), while COUNT returns 0. This distinction can cause issues if you later do calculations with these results.

Use NULL checks to audit data completeness:

1SELECT
2 COUNT(*) AS total_users,
3 COUNT(email) AS with_email,
4 COUNT(phone) AS with_phone,
5 COUNT(*) - COUNT(email) AS missing_email
6FROM users
Result
total_userswith_emailwith_phonemissing_email
100095072050
This quickly shows how complete your data is for different columns.
//

Incomplete Records

Finding records with missing data is essential for data quality monitoring.
1SELECT
2 order_id,
3 customer_id,
4 shipping_address
5FROM orders
6WHERE shipping_address IS NULL
7AND status = 'pending'
Result
order_idcustomer_idshipping_address
ORD-234C-101NULL
ORD-267C-145NULL
This finds pending orders that can't ship because they're missing an address.

Finding Missing Data

Use the IS NULL operator to identify rows where a column has no value assigned.

> Complete this query to find how many orders are missing a discount value.

SELECT
  ___ - ___ AS missing_discounts
FROM orders
AVG(discount)
COUNT(*)
SUM(discount)
COUNT(discount)

The fact that SUM and AVG silently skip NULLs rather than treating them as zero means you must always be clear about whether your business definition of "average discount" includes or excludes orders that had no discount.

When aggregate functions return NULL because all input values are NULL, you can protect downstream calculations by wrapping the aggregate with COALESCE to substitute a sensible default.

Data audits using COUNT(*) minus COUNT(column) are one of the fastest ways to quantify data quality issues in a table and communicate the scope of missing data to the team responsible for fixing it.

PUTTING IT ALL TOGETHER

> You are a data analyst at HubSpot preparing a contact completeness report before a CRM data quality sprint. Marketing needs to know which fields are missing so the team can prioritize outreach campaigns on records that are actually usable.

IS NULL pinpoints contacts missing phone or email, surfacing exactly which records block outreach campaigns.
Three-valued logic explains why WHERE phone = NULL silently drops rows that should appear in your report.
COUNT(*) minus COUNT(column) quantifies incomplete records per field, giving the team a prioritized gap list.
SUM and AVG silently skip NULLs, so aggregate completeness scores only reflect contacts with actual values.
KEY TAKEAWAYS
NULL means "unknown" or "not provided"; it is not the same as zero or empty string
Never use = NULL or != NULL; always use IS NULL or IS NOT NULL
Any comparison with NULL returns UNKNOWN, which is treated as FALSE in WHERE
COUNT(*) counts all rows including NULLs; COUNT(column) counts only non-NULL values
SUM, AVG, MIN, MAX all ignore NULL values; they operate only on non-NULL values
NULL in arithmetic: any operation with NULL returns NULL
Real data is incomplete; NULL lets databases represent this truth
Understanding NULL prevents silent data loss and incorrect calculations

NULL: the billion dollar mistake

Category
SQL
Difficulty
beginner
Duration
25 minutes
Challenges
3 hands-on challenges

Topics covered: NULL vs zero vs empty string, Three-Valued Logic, IS NULL and IS NOT NULL operators, COUNT(*) vs COUNT(column), Aggregates with NULLs

Lesson Sections

  1. NULL vs zero vs empty string (concepts: sqlNullPropagation)

    Understanding NULL These three concepts are often confused, but they represent completely different things: Purpose of NULL

  2. Three-Valued Logic (concepts: sqlThreeValuedLogic)

    Three-Valued Logic This is why the following comparisons don't work as you might expect: WHERE Clause Behavior IS NULL vs = NULL

  3. IS NULL and IS NOT NULL operators (concepts: sqlIsNull)

    Basic NULL Checks IS NOT NULL Common Mistakes This is one of the most common SQL mistakes:

  4. COUNT(*) vs COUNT(column)

    COUNT Behaviors COUNT Behaviors

  5. Aggregates with NULLs

    Other Aggregate Behaviors MIN/MAX Skip NULLs All NULLs: Special Case This quickly shows how complete your data is for different columns. Incomplete Records Finding records with missing data is essential for data quality monitoring. This finds pending orders that can't ship because they're missing an address. Finding Missing Data