SQL IS NULL and IS NOT NULL: Find Missing Values

IS NULL tests whether a value is missing, while IS NOT NULL tests whether it is present; neither uses ordinary equality.

Lesson 33 of 102Beginner10 min read

IS NULL tests whether a value is missing, while IS NOT NULL tests whether it is present; neither uses ordinary equality.

An unknown amount is different from a zero amount, and an unknown city is different from an empty city label. Treating those values as equivalent can create false totals or hide records that need attention. SQL provides dedicated tests for missing information.

This reference adds detail to the main course. You can read it independently: the small database below supplies every table and row used in the examples. Start with the question each query answers, then compare the returned values with the data rather than memorising a line of syntax.

Set up the practice database

Run this setup once in a new practice database, before the examples. It uses four customers and six sales. Ana has two sales, Ben has one, Cara has two, and Dev has none.

Sale 106 has no customer link; sale 104 has an unknown amount. These deliberate test cases expose missing information and unmatched relationships.

SQL
CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name VARCHAR(40) NOT NULL,
  city VARCHAR(40),
  manager_id INTEGER
);
CREATE TABLE sales (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER,
  amount DECIMAL(10,2),
  status VARCHAR(20) NOT NULL,
  created_on DATE NOT NULL
);
INSERT INTO customers (id,name,city,manager_id) VALUES
  (1,'Ana','Leeds',NULL),(2,'Ben','Leeds',1),
  (3,'Cara','Porto',1),(4,'Dev',NULL,2);
INSERT INTO sales (id,customer_id,amount,status,created_on) VALUES
  (101,1,10,'paid','2026-01-01'),
  (102,1,30,'pending','2026-01-02'),
  (103,2,20,'paid','2026-01-02'),
  (104,3,NULL,'pending','2026-02-01'),
  (105,3,20,'paid','2026-02-02'),
  (106,NULL,5,'paid','2026-02-03');

An amount of zero would be a known value. The NULL amount here means the value is unknown. A customer with no matching sale differs from a sale whose customer_id is NULL.

The primary keys identify individual records even when amounts or cities repeat. Dates use year-month-day format. The examples specify sorting whenever order matters; insertion order alone does not guarantee display order.

How IS NULL and IS NOT NULL works

NULL is a marker for missing or unknown information, not a particular string or number. The expression amount = NULL does not ask the database to identify missing amounts in the intended way. Ordinary comparison with NULL yields unknown, including NULL = NULL. Since WHERE retains only true conditions, = NULL generally returns no rows. Write amount IS NULL to test the marker directly, and amount IS NOT NULL to require a known value.

Three-valued logic explains many surprising filters. amount <> 20 excludes the missing amount as well as the known twenties: the unknown amount cannot be established as different from twenty. If the report intends to include unknown amounts, write amount <> 20 OR amount IS NULL. Conversely, IS NOT NULL only confirms presence. It says nothing about whether a string is meaningful, a number is positive, or a date is inside an acceptable range. Add the appropriate separate checks.

NULL in calculations and aggregates

Most arithmetic with NULL produces NULL. Adding an unknown fee to a known price produces an unknown total unless the application deliberately defines a replacement. Most ordinary aggregate functions skip NULL inputs, while COUNT(*) counts rows regardless. Consequently a report should distinguish total records from records with known amounts. Sale 104 still exists even though its amount is missing. Counting known amounts alone does not reveal how many sales need correction unless you also compare with the row count.

Outer joins can introduce NULL placeholders for an absent matching row. A LEFT JOIN customer with no sale produces a missing sales.id even if the sales table defines that id as a non-NULL primary key. Testing the right-side primary key for NULL can identify unmatched customers. Testing sales.amount instead is unsafe here, because sale 104 is a real match with a missing amount. Choose the column whose NULL status proves the specific fact you want to detect.

MySQL, PostgreSQL, SQL Server and SQLite

IS NULL and IS NOT NULL are portable across all four systems. Empty text generally differs from NULL in these systems. NULL sort position varies by engine, and unique-constraint treatment of NULL has differences too. Use explicit NULL tests rather than applying assumptions from sorting or uniqueness to ordinary comparisons.

Check the engine-specific syntax and version requirements in PostgreSQL comparison and NULL predicates.

Practice task and worked solution

Return the customer names with a known city. Sort by customer id, and do not replace the missing city with a display label.

Try the task before reading its worked solution. The supplied rows make the expected answer checkable by hand.

SQL
SELECT id,name FROM customers
WHERE city IS NOT NULL ORDER BY id;
Output
id | name
1 | Ana
2 | Ben
3 | Cara

Ana and Ben have Leeds, while Cara has Porto. Dev’s city is missing, so the presence predicate is false for him. The query keeps the saved city values intact and simply filters which customer rows appear.

Compare amount<>20 with amount<>20 OR amount IS NULL. The second version should include sale 104 while the first should not. Then use IS NULL on customer.city to find Dev. If you add a known zero amount in a disposable table, verify it appears under IS NOT NULL; a numeric zero must never become a missing-value match.

SQL IS NULL and IS NOT NULL: Find Missing Values Syntax

IS NULL and IS NOT NULL

SELECT id, customer_id FROM sales
WHERE amount IS NULL ORDER BY id;

SQL IS NULL and IS NOT NULL: Find Missing Values Summary

  • NULL marks a missing or unknown value; it isn't zero and it isn't empty text.
  • Test it with IS NULL and IS NOT NULL, because = NULL is unknown and never keeps a row.
  • Most arithmetic with NULL gives NULL, and most aggregates skip NULL inputs while COUNT(*) counts every row.
  • A LEFT JOIN produces NULLs for unmatched rows; test the joined key to detect "no match".
  • Keep unknown and zero as separate categories in reports, because they mean different things.

SQL IS NULL and IS NOT NULL: Find Missing Values Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Sales with a missing amount

Only sale 104 has the missing amount marker. The query returns its identity and owner so a staff member can investigate. It does not replace the amount, delete the sale, or assume the missing value equals zero.

SQL
SELECT id, customer_id FROM sales
WHERE amount IS NULL ORDER BY id;
Output
id | customer_id
104 | 3

Common SQL IS NULL and IS NOT NULL: Find Missing Values Mistakes

Comparing with = NULL or the text 'NULL'

Using WHERE amount = NULL returns no matching rows because the comparison is unknown. Replacing the value with the text 'NULL' tests a string, not the missing marker. Also avoid treating a left-joined nullable amount as proof that no sale exists; inspect the joined primary key instead.

SQL IS NULL and IS NOT NULL: Find Missing Values in Real Projects

Data-quality lists before billing

A data-quality dashboard can list sales requiring an amount before billing is finalised. That list should preserve the sale id and relevant relationship so someone can fix the source record. Unknown and zero should appear as separate categories because they imply different follow-up actions.

Keep absence and invalidity as separate audit categories. IS NOT NULL confirms that a saved value exists, but an empty city label may still be unusable. A transaction requiring a known amount needs a presence rule in addition to any range rule. Preserve the sale identity so corrective work can target the source record precisely.

SQL IS NULL and IS NOT NULL: Find Missing Values FAQ

Is NULL the same as zero?

No. Zero is a known numeric value; NULL states that the value is absent or unknown. A sale of 0 is included in AVG(amount), while a sale with a NULL amount is skipped, so mixing them up changes averages and totals.

Does IS NOT NULL validate data?

It checks presence only. An empty string, a negative quantity or an implausible date still passes, so they need separate validity rules, ideally as CHECK constraints in the table definition.

Why can a left join produce NULL for a non-nullable key?

The join creates a placeholder row filled with NULLs when no match exists; it has not stored a NULL key in the original table. That's exactly why testing the right-side key with IS NULL reveals unmatched rows.

Is there a NULL-safe equals operator?

Yes. Standard SQL has IS NOT DISTINCT FROM, supported by PostgreSQL, SQLite and SQL Server 2022, which treats two NULLs as equal. MySQL uses <=>, and SQLite also accepts IS between two expressions. Use them when comparing columns that may both be missing.

How do I replace NULL with a default in results?

Use COALESCE(city, 'Unknown'), which returns the first non-NULL argument. Do this only for display or calculations where the default is genuinely correct; storing a fake value such as 0 or 'Unknown' in the table hides the fact that the data is missing.

SQL IS NULL and IS NOT NULL: Find Missing Values Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choicemedium

Which sale is returned by WHERE amount IS NULL?

SQL IS NULL and IS NOT NULL: Find Missing Values Quiz

2 questions to check what you learned.

  1. Which predicate finds missing amounts?

    • amount IS NULL
    • amount = NULL
    • amount = 'NULL'
  2. Which column reliably detects a missing sale in this left join?

    • sales.amount, because every real sale must have a known amount
    • sales.id, because it is a non-NULL primary key for real sale rows
    • customers.id, because the preserved customer proves a sale exists