EVIKA.ACADEMY›SQL Tutorial
SQL Tutorial›NULL Values

SQL NULL Values

Chapter 9 of 40 · Estimated read time: 8 min

What is NULL?

NULL is not zero. NULL is not an empty string. NULL means the value is unknown or missing. A customer whose phone number has not been collected has NULL in the phone column — not 0, not a blank space.

''
Empty string
A value exists — it just has no characters
0
Zero
A value exists — it is the number zero
NULL
NULL
No value exists at all — completely absent
Real-world example: A new customer signed up but skipped the phone field. Their phone column is NULL — not "no phone", just "we don't know". This matters because queries that filter for phone numbers must handle NULL explicitly.

IS NULL and IS NOT NULL

-- Find rows where a value IS missing WHERE column IS NULL -- Find rows where a value IS present WHERE column IS NOT NULL

Suppose some customers haven't provided their email:

-- Find customers who have NOT provided their email
SELECT customer_id, customer_name, city
FROM customers
WHERE email IS NULL;
OUTPUT ↓
customer_idcustomer_namecity
C05Arjun SinghBengaluru
-- Find customers who HAVE provided their email
SELECT customer_id, customer_name, email
FROM customers
WHERE email IS NOT NULL;
OUTPUT ↓
customer_idcustomer_nameemail
C01Amit Vermaamit@example.com
C02Priya Sharmapriya@example.com
C03Rohan Mehtarohan@example.com
C04Sneha Guptasneha@example.com

The Most Common NULL Trap

⚠️ You cannot compare NULL using = or !=
WHERE email = NULL never returns any rows — not even rows where email actually is NULL.
WHERE email != NULL also never returns rows.
This is because NULL = NULL evaluates to UNKNOWN, not TRUE.
-- ❌ WRONG — returns 0 rows even when NULLs exist
SELECT * FROM customers WHERE email = NULL;
SELECT * FROM customers WHERE email != NULL;

-- ✅ CORRECT — always use IS NULL / IS NOT NULL
SELECT * FROM customers WHERE email IS NULL;
SELECT * FROM customers WHERE email IS NOT NULL;

NULL in Calculations and Expressions

Any arithmetic involving NULL produces NULL. Think of it as "unknown + anything = still unknown":

-- If discount column has NULL, the discounted_price is also NULL
SELECT
  product_name,
  price,
  discount,
  price - discount AS discounted_price   -- NULL if discount is NULL
FROM products;

-- Fix: treat NULL discount as 0 using COALESCE
SELECT
  product_name,
  price,
  price - COALESCE(discount, 0) AS discounted_price
FROM products;
COALESCE(value, fallback) returns the first non-NULL argument. COALESCE(discount, 0) means "use discount if it exists, otherwise use 0". You will learn more about this in the NULL Functions chapter.

NULL in COUNT — A Surprising Behaviour

-- COUNT(*) counts ALL rows including those with NULLs
SELECT COUNT(*) AS total_customers FROM customers;
-- Result: 5

-- COUNT(column) counts only NON-NULL values in that column
SELECT COUNT(email) AS customers_with_email FROM customers;
-- Result: 4  (Arjun's NULL email is skipped)

-- This is how you count missing values:
SELECT COUNT(*) - COUNT(email) AS customers_missing_email FROM customers;
-- Result: 1
Interview tip: "What is the difference between COUNT(*) and COUNT(column)?" is asked in almost every SQL interview. COUNT(*) counts rows; COUNT(column) counts non-NULL values in that column.

NULL in ORDER BY and GROUP BY

-- NULL sorting behaviour varies by database:
-- PostgreSQL: NULLs go LAST in ASC, FIRST in DESC (by default)
-- MySQL:      NULLs go FIRST in ASC
-- Control it explicitly:

SELECT customer_name, email
FROM customers
ORDER BY email ASC NULLS LAST;   -- PostgreSQL: push NULLs to the bottom

-- GROUP BY treats all NULLs as one group
SELECT city, COUNT(*) AS customer_count
FROM customers
GROUP BY city;   -- A NULL city would appear as its own group
✏️ Practice Exercises
1. Find all products where the supplier_id IS NULL.
2. Count how many orders have a NULL total_amount.
3. Write a query that returns each customer's name and their email. If email is NULL, show the text "Not Provided" instead.
Show Answers
-- 1.
SELECT * FROM products WHERE supplier_id IS NULL;

-- 2.
SELECT COUNT(*) - COUNT(total_amount) AS null_totals FROM orders;

-- 3.
SELECT
  customer_name,
  COALESCE(email, 'Not Provided') AS email
FROM customers;