Chapter 06 · Functions, NULLs, and Conditional Logic

NULL Tests, COALESCE, NULLIF, and Safe Defaults

Preserve the distinction between unknown data and deliberate defaults while keeping reports and calculations usable.

Beginner80–100 minutesNULL semantics + defensive expressionsLast reviewed: August 2026

Learning outcomes

NULL represents missing or inapplicable information. A safe SQL expression does not erase that meaning accidentally, but it can provide an explicit fallback where the result contract requires one.

01

Test missing values with IS NULL and IS NOT NULL.

02

Use COALESCE to choose the first available value.

03

Use NULLIF to convert sentinel or dangerous values into NULL.

04

Distinguish presentation defaults from stored facts and business defaults.

NULL propagates through many expressions

Stored value may be NULL
Expression evaluates
UNKNOWN or NULL can propagate
Explicit policy controls output

Missing information affects comparisons, arithmetic, concatenation, and many functions until an expression defines how to handle it.

sqlite · observe NULL propagation
SELECT    10 + NULL AS arithmetic_result,    'email: ' || NULL AS concatenation_result,    LOWER(NULL) AS function_result,    NULL = NULL AS equality_result,    NULL IS NULL AS null_test_result;

Ordinary equality does not answer whether a value is NULL. Use IS NULL or IS NOT NULL.

NULL tests preserve meaning

sqlite · find genuinely missing contact data
SELECT customer_id, full_name, emailFROM customerWHERE email IS NULLORDER BY customer_id;
sqlite · empty text is not NULL
SELECT customer_id, full_name, emailFROM customerWHERE email = ''ORDER BY customer_id;

The dataset intentionally contains both NULL and an empty string. They can represent different states and should not be merged without a business rule.

Stored valuePossible meaningTest
NULLUnknown, unavailable, or not applicableIS NULL
Empty stringKnown to be empty= ''
WhitespaceEntered but not meaningfulTRIM(x) = ''
Sentinel such as 0 or N/ALegacy substitute for missingnessConvert deliberately after validating the domain

COALESCE chooses the first non-NULL expression

sqlite · layered fallback
SELECT    customer_id,    COALESCE(city, '[city unknown]') AS city_label,    COALESCE(NULLIF(TRIM(email), ''), '[no email]') AS email_label,    COALESCE(credit_limit, 0) AS displayed_credit_limitFROM customerORDER BY customer_id;

COALESCE(a,b,c) checks arguments from left to right and returns the first non-NULL result. The chosen fallback becomes part of the output contract.

1

Data fallback

Prefer another stored field when it carries equivalent meaning.

2

Presentation fallback

Show a label such as “unknown” without changing stored data.

3

Calculation fallback

Use zero only when the business definition truly treats missing as zero.

4

Type fallback

Ensure candidate expressions have compatible, intentional result types.

Zero is not a universal safe default

unsafe interpretation · unknown becomes zero
SELECT    customer_id,    COALESCE(credit_limit, 0) AS credit_limitFROM customer;

This may be correct for a display or a specific decision rule, but it also makes an unknown limit indistinguishable from a known limit of zero. A clearer report can expose both value and state.

sqlite · retain the missingness signal
SELECT    customer_id,    credit_limit,    COALESCE(credit_limit, 0) AS calculation_limit,    credit_limit IS NULL AS limit_was_missingFROM customerORDER BY customer_id;

NULLIF returns NULL when two expressions are equal

sqlite · normalize blank email text
SELECT    customer_id,    NULLIF(TRIM(email), '') AS normalized_emailFROM customerORDER BY customer_id;
portable pattern · protect a divisor
SELECT    product_id,    unit_price,    stock_qty,    unit_price / NULLIF(stock_qty, 0) AS price_per_stock_unitFROM productORDER BY product_id;

If stock_qty is zero, NULLIF(stock_qty,0) returns NULL. The division then yields NULL instead of attempting a zero divisor. This is safer than fabricating a numeric answer.

COALESCE and NULLIF compose well

sqlite · normalize, then provide a label
SELECT    customer_id,    COALESCE(        LOWER(NULLIF(TRIM(email), '')),        '[no usable email]'    ) AS contact_emailFROM customerORDER BY customer_id;

Evaluation proceeds inside out: trim, convert empty text to NULL, lowercase a usable value, then provide a display fallback.

NULL-aware calculations

sqlite · missing discount means no recorded discount
SELECT    s.sale_id,    p.unit_price,    s.quantity,    s.discount_rate,    ROUND(p.unit_price * s.quantity, 2) AS gross_amount,    ROUND(        p.unit_price * s.quantity * COALESCE(s.discount_rate, 0),        2    ) AS discount_amountFROM sale AS sJOIN product AS p ON p.product_id = s.product_idORDER BY s.sale_id;
State the interpretation

Here the reporting rule treats an absent discount rate as zero. That rule should be documented; another system might treat a missing rate as incomplete data requiring review.

Fallback types differ across engines

SQL engines determine a common result type for COALESCE and CASE according to their own type-resolution rules. Avoid mixing unrelated types merely because one branch is usually NULL.

prefer compatible candidates
SELECT    COALESCE(credit_limit, CAST(0 AS REAL)) AS effective_limitFROM customer;
avoid ambiguous mixed-type fallback
-- This may coerce differently or fail across engines.SELECT COALESCE(credit_limit, 'unknown')FROM customer;

Practice lab

  1. List customers with a missing city.
  2. Normalize NULL, empty, and whitespace-only emails into NULL.
  3. Display a fallback email label without modifying storage.
  4. Calculate sale discounts by treating a missing discount rate as zero.
  5. Calculate price per stock unit without dividing by zero.
sqlite · possible solutions
SELECT customer_id, full_nameFROM customerWHERE city IS NULL;SELECT customer_id, NULLIF(TRIM(email), '') AS normalized_emailFROM customer;SELECT customer_id,       COALESCE(NULLIF(TRIM(email), ''), '[no email]') AS email_labelFROM customer;SELECT sale_id,       COALESCE(discount_rate, 0) AS effective_discount_rateFROM sale;SELECT product_id,       unit_price / NULLIF(stock_qty, 0) AS price_per_stock_unitFROM product;

Checkpoint

Choose the correct expression

  1. Which operator tests whether city is missing?
  2. Which expression converts an empty string to NULL?
  3. When is COALESCE(value,0) misleading?
  4. Why can NULLIF(divisor,0) be useful?
Review the answers

IS NULL; NULLIF(value,''); zero is misleading when unknown and known-zero are different states; NULLIF prevents a zero divisor from being treated as a valid denominator.

Common failures

Writing = NULL

The result is UNKNOWN rather than a successful null test.

Replacing every NULL with zero or empty text

This destroys distinctions that may matter to the business.

Using a sentinel instead of NULL

Values such as -1 or 'N/A' can collide with real domains and complicate constraints.

Mixing incompatible fallback types

Type resolution differs by engine and can produce errors or surprising coercion.

Hiding data-quality problems in presentation

A fallback label can make a report readable while the source still needs correction.

Summary and references

  • Use IS NULL and IS NOT NULL for missingness.
  • COALESCE returns the first non-NULL candidate.
  • NULLIF converts a specific equal value into NULL.
  • Defaults must have an explicit business or presentation meaning.
  • Expose missingness separately when a fallback could hide important state.

References

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only assets compatible with the Ethereum/ERC-20 network. Do not send TRC-20/TRON assets.