SQLab Hub
Lesson 27 · COALESCE
Lesson 27 · Functions

SQL COALESCE: Replace NULL Values

COALESCE returns the first value in its list that is not NULL. Use it to show a default instead of a missing value, to fall back from one column to the next, and to stop a single NULL from turning a whole calculation into NULL.

∅ → value First non-NULL ⛓ Multi-column fallbacks ▶ Runnable Playground examples 🧪 6 practice exercises 📝 30-question quiz ⏱ ~30 min

What Is COALESCE in SQL?

Think of how you reach a customer: try their mobile first, then the home number, then the office, and if none of them is on file, note "no number". COALESCE does exactly that, from left to right, for every row. The four sample contacts below are written into the query, so you can run it and edit them:

SQLite · runs in the Playground
WITH contacts(name, mobile, home, office) AS (
  VALUES ('Neha',   '555-0101', NULL,       '555-0199'),
         ('Vikram', NULL,       '555-0142', NULL),
         ('Aditi',  NULL,       NULL,       '555-0177'),
         ('Rohan',  NULL,       NULL,       NULL)
)
SELECT name, mobile, home, office,
       COALESCE(mobile, home, office, 'No number on file') AS best_contact
FROM contacts;

▶ Run this query in the SQL Playground

The first available phone number for each contact
namemobilehomeofficebest_contact
Neha555-0101NULL555-0199555-0101
VikramNULL555-0142NULL555-0142
AditiNULLNULL555-0177555-0177
RohanNULLNULLNULLNo number on file
✓ 4 rows · real output from the Playground database

Neha has a mobile number, so it is used and the other columns are never looked at. Vikram has only a home number and Aditi only an office number. Rohan has none, so he gets the final default. Without the last argument his result would be NULL.

Business problemCOALESCE answer
Show a label instead of a blankCOALESCE(shipped_date, 'Not shipped')
Use the first available of several columnsCOALESCE(mobile, home, office)
Keep a NULL from breaking a calculationsalary + COALESCE(bonus, 0)
Show 0 for customers with no orders after a LEFT JOINCOALESCE(SUM(o.total), 0)

NULL Is Not Zero and Not an Empty String

NULL means "no value recorded". Zero and an empty string are real values. The difference shows as soon as NULL meets an operator: arithmetic with NULL gives NULL, and so does a comparison, even NULL = NULL:

SQLite · runs in the Playground
SELECT 5 + NULL          AS plus_null,
       NULL = NULL       AS null_equals_null,
       5 + 0             AS plus_zero,
       'abc' || ''       AS plus_empty_string,
       COALESCE(NULL, 0) AS coalesced;

▶ Run this query in the SQL Playground

NULL compared with 0 and an empty string
plus_nullnull_equals_nullplus_zeroplus_empty_stringcoalesced
NULLNULL5abc0
✓ 1 row · real output from the Playground database

In the Playground, 97 orders have no shipped_date because they have not been shipped yet, and 10 employees have no manager_id. Those are the NULLs the examples below work with:

SQLite · runs in the Playground
SELECT COUNT(*) AS all_orders,
       COUNT(*) - COUNT(shipped_date) AS not_shipped
FROM orders;

▶ Run this query in the SQL Playground

Orders without a shipped date
all_ordersnot_shipped
20097
✓ 1 row · real output from the Playground database
SQLite · runs in the Playground
SELECT COUNT(*) - COUNT(manager_id) AS no_manager
FROM employees;

▶ Run this query in the SQL Playground

Employees without a manager
no_manager
10
✓ 1 row · real output from the Playground database

To find NULLs you use IS NULL. To replace them with something else, you use COALESCE.

COALESCE Syntax and How It Works

SQL · syntax
COALESCE(value_1, value_2, ..., value_n)
RuleMeaning
Checked left to rightThe first argument that is not NULL is returned; the rest are not evaluated
Any number of argumentsTwo or more: columns, literals, expressions or subqueries
All NULLIf every argument is NULL, the result is NULL
Same typeAll arguments should have compatible types, such as all text or all numbers
Read-onlyCOALESCE changes the query result, not the data stored in the table
SQLite · runs in the Playground
SELECT COALESCE(NULL, NULL, 'SQLab Hub', 'never reached') AS first_value,
       COALESCE(NULL, NULL) AS all_null;

▶ Run this query in the SQL Playground

COALESCE on literal values
first_valueall_null
SQLab HubNULL
✓ 1 row · real output from the Playground database

The first column skips two NULLs and returns SQLab Hub; the last argument is never reached. The second column has nothing but NULLs, so the result is NULL. COALESCE is part of standard SQL and works the same in MySQL, PostgreSQL, SQL Server, Oracle and SQLite.

Show a Default Instead of NULL

The most common use is a readable label for a missing value. Orders that have not shipped get "Not shipped yet" instead of a blank cell:

SQLite · runs in the Playground
SELECT id, status,
       COALESCE(shipped_date, 'Not shipped yet') AS shipped
FROM orders
ORDER BY id
LIMIT 6;

▶ Run this query in the SQL Playground

Orders with a label for the missing shipped date
idstatusshipped
1cancelledNot shipped yet
2delivered2023-04-09
3delivered2023-07-10
4processingNot shipped yet
5delivered2023-12-21
6shipped2024-12-13
✓ 6 rows · real output from the Playground database

Here the fallback is text while shipped_date is a date. SQLite stores dates as text, so this works. PostgreSQL and SQL Server require one type for all arguments, so there you convert the date first: COALESCE(CAST(shipped_date AS VARCHAR(10)), 'Not shipped yet').

A fallback from another table

With a self join, every employee can be shown next to their manager. Employees without one get a label instead of NULL:

SQLite · runs in the Playground
SELECT e.first_name || ' ' || e.last_name AS employee,
       e.title,
       COALESCE(m.first_name || ' ' || m.last_name, 'No manager') AS manager
FROM employees e
LEFT JOIN employees m ON m.id = e.manager_id
ORDER BY e.id
LIMIT 6;

▶ Run this query in the SQL Playground

Employees with their manager, or a label
employeetitlemanager
William LewisSenior CS ManagerNo manager
John MillerParalegalNo manager
Daniel RiveraVP EngineeringNo manager
Melissa SmithVP EngineeringNo manager
Jason MitchellProduct DesignerNo manager
Amy NguyenProduct DesignerNo manager
✓ 6 rows · real output from the Playground database

For the top-level employees, m.first_name || ' ' || m.last_name is NULL because the joined manager row does not exist, so COALESCE moves on to the label.

COALESCE in Calculations

Any arithmetic with NULL returns NULL. If a bonus was never recorded, salary + bonus wipes out the whole total. COALESCE replaces the missing bonus with 0 before the addition:

SQLite · runs in the Playground
WITH pay(name, salary, bonus) AS (
  VALUES ('Aditi', 112000, 15000),
         ('Rohan',  58000, NULL),
         ('Priya',  97000, 8000),
         ('Karan',  46000, NULL),
         ('Sneha',  63000, 0)
)
SELECT name, salary, bonus,
       salary + bonus              AS total_without_coalesce,
       salary + COALESCE(bonus, 0) AS total_pay
FROM pay;

▶ Run this query in the SQL Playground

Total pay with and without COALESCE
namesalarybonustotal_without_coalescetotal_pay
Aditi11200015000127000127000
Rohan58000NULLNULL58000
Priya970008000105000105000
Karan46000NULLNULL46000
Sneha6300006300063000
✓ 5 rows · real output from the Playground database

Rohan and Karan have no bonus recorded, so their first total is NULL. Sneha's bonus is a real 0, and her total works either way. COALESCE makes the missing bonus behave like hers.

Is 0 the right default? For a bonus that was never paid, probably yes. For a missing price or test score, 0 would be a wrong answer that looks real. Choosing the fallback is a business decision; when in doubt, show a label such as "not recorded" instead.

COALESCE With SUM, AVG and COUNT

Aggregate functions already skip NULLs, so COALESCE inside them changes the answer, not only the display. Compare the bonus figures for the same five people:

SQLite · runs in the Playground
WITH pay(name, salary, bonus) AS (
  VALUES ('Aditi', 112000, 15000),
         ('Rohan',  58000, NULL),
         ('Priya',  97000, 8000),
         ('Karan',  46000, NULL),
         ('Sneha',  63000, 0)
)
SELECT SUM(bonus)              AS sum_bonus,
       SUM(COALESCE(bonus, 0)) AS sum_coalesced,
       ROUND(AVG(bonus), 2)    AS avg_bonus,
       AVG(COALESCE(bonus, 0)) AS avg_coalesced,
       COUNT(bonus)            AS count_bonus,
       COUNT(COALESCE(bonus, 0)) AS count_coalesced
FROM pay;

▶ Run this query in the SQL Playground

Aggregates with and without COALESCE
sum_bonussum_coalescedavg_bonusavg_coalescedcount_bonuscount_coalesced
23000230007666.67460035
✓ 1 row · real output from the Playground database
AggregateWithout COALESCEWith COALESCE(bonus, 0)
SUM23000: NULLs are skipped23000: the same, adding zeros changes nothing
AVG7666.67: average of the 3 recorded bonuses4600: average over all 5 people
COUNT3: rows that have a bonus5: every row

Neither average is "correct" on its own. AVG(bonus) answers "what is the typical bonus among people who got one?"; AVG(COALESCE(bonus, 0)) answers "what is the average bonus per employee?". Decide which question you are asking before you add COALESCE.

SUM over no rows

SUM of zero rows is NULL, not 0. That matters for dashboard tiles. There are no orders in 2025 in the Playground, so the plain SUM is NULL and the wrapped one shows 0:

SQLite · runs in the Playground
SELECT SUM(total)              AS plain_sum,
       COALESCE(SUM(total), 0) AS revenue_2025
FROM orders
WHERE order_date >= '2025-01-01';

▶ Run this query in the SQL Playground

Revenue for a period with no orders
plain_sumrevenue_2025
NULL0
✓ 1 row · real output from the Playground database

COALESCE After a LEFT JOIN

A LEFT JOIN keeps every row from the left table and fills the columns of the right table with NULL when there is no match. This lists customers with their order count and total spend, including customers who never ordered:

SQLite · runs in the Playground
SELECT u.id, u.first_name, u.last_name,
       COUNT(o.id) AS orders,
       SUM(o.total) AS raw_spend,
       COALESCE(ROUND(SUM(o.total), 2), 0) AS total_spend
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id, u.first_name, u.last_name
ORDER BY u.id
LIMIT 6;

▶ Run this query in the SQL Playground

Customers with their spend, including those without orders
idfirst_namelast_nameordersraw_spendtotal_spend
1JenniferTorres14064.754064.75
2DonnaAdams11618.291618.29
3KennethYoung0NULL0
4MichaelCarter34863.294863.29
5RobertCampbell14924.234924.23
6DeborahJackson27403.7800000000017403.78
✓ 6 rows · real output from the Playground database

For a customer with no orders, SUM(o.total) is NULL and COALESCE turns it into 0. COUNT(o.id) is already 0, because COUNT never returns NULL. 36 of the 150 customers have never ordered:

SQLite · runs in the Playground
SELECT COUNT(*) AS customers_without_orders
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE o.id IS NULL;

▶ Run this query in the SQL Playground

Customers without orders
customers_without_orders
36
✓ 1 row · real output from the Playground database

When 0 would be misleading

Products without reviews have no average rating. Showing 0 would look like a terrible rating, so a label is the honest default:

SQLite · runs in the Playground
SELECT p.name,
       COUNT(r.id) AS reviews,
       COALESCE(CAST(ROUND(AVG(r.rating), 1) AS TEXT), 'No reviews yet') AS avg_rating
FROM products p
LEFT JOIN reviews r ON r.product_id = p.id
GROUP BY p.id, p.name
ORDER BY reviews, p.id
LIMIT 6;

▶ Run this query in the SQL Playground

Average rating per product, with a label for unreviewed products
namereviewsavg_rating
Giant Stuffed Teddy Bear0No reviews yet
Merino Wool Sweater0No reviews yet
Retinol Eye Cream 30ml0No reviews yet
Play Kitchen Deluxe0No reviews yet
Resistance Bands Set0No reviews yet
Back Seat Organizer0No reviews yet
✓ 6 rows · real output from the Playground database

COALESCE With CASE WHEN and Subqueries

A NULL inside a CASE condition makes that condition unknown, so the row falls through to ELSE without anyone noticing. Wrapping the column in COALESCE makes the intent explicit:

SQLite · runs in the Playground
WITH pay(name, salary, bonus) AS (
  VALUES ('Aditi', 112000, 15000),
         ('Rohan',  58000, NULL),
         ('Priya',  97000, 8000),
         ('Karan',  46000, NULL),
         ('Sneha',  63000, 0)
)
SELECT name, bonus,
       CASE WHEN COALESCE(bonus, 0) >= 10000 THEN 'High bonus'
            WHEN COALESCE(bonus, 0) > 0      THEN 'Bonus'
            ELSE 'No bonus'
       END AS bonus_group
FROM pay;

▶ Run this query in the SQL Playground

Bonus groups with NULL treated as no bonus
namebonusbonus_group
Aditi15000High bonus
RohanNULLNo bonus
Priya8000Bonus
KaranNULLNo bonus
Sneha0No bonus
✓ 5 rows · real output from the Playground database

COALESCE is shorthand for one particular CASE: COALESCE(a, b) means CASE WHEN a IS NOT NULL THEN a ELSE b END.

A subquery as an argument

Any argument can be a scalar subquery. This shows each customer's latest order date, or a label if there is none:

SQLite · runs in the Playground
SELECT u.first_name, u.last_name,
       COALESCE((SELECT MAX(o.order_date)
                 FROM orders o
                 WHERE o.user_id = u.id), 'Never ordered') AS last_order
FROM users u
ORDER BY u.id
LIMIT 6;

▶ Run this query in the SQL Playground

Each customer's latest order date
first_namelast_namelast_order
JenniferTorres2022-09-26
DonnaAdams2023-04-02
KennethYoungNever ordered
MichaelCarter2024-11-15
RobertCampbell2024-05-18
DeborahJackson2023-01-19
✓ 6 rows · real output from the Playground database

COALESCE With NULLIF: Safe Division

NULLIF is close to the opposite of COALESCE: NULLIF(a, b) returns NULL when a equals b. Together they make a safe division. NULLIF turns a zero denominator into NULL, so the division gives NULL instead of an error, and COALESCE turns that NULL into a default:

SQLite · runs in the Playground
SELECT u.id, u.first_name,
       COUNT(o.id) AS orders,
       COALESCE(ROUND(SUM(o.total) / NULLIF(COUNT(o.id), 0), 2), 0) AS avg_order_value
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id, u.first_name
ORDER BY u.id
LIMIT 6;

▶ Run this query in the SQL Playground

Average order value per customer with safe division
idfirst_nameordersavg_order_value
1Jennifer14064.75
2Donna11618.29
3Kenneth00
4Michael31621.1
5Robert14924.23
6Deborah23701.89
✓ 6 rows · real output from the Playground database

SQLite returns NULL for a division by zero anyway, but PostgreSQL and SQL Server raise an error, so the NULLIF is what makes this query portable.

COALESCE vs ISNULL, IFNULL, NVL and CASE

Most databases have a two-argument shortcut for the same job. They behave like COALESCE(a, b), with small differences:

FunctionDatabasesArgumentsNotes
COALESCE(a, b, ...)All of them (standard SQL)Any numberThe portable choice
ISNULL(a, b)SQL ServerExactly 2The result takes the type of a, so a longer text in b can be cut off. In MySQL, ISNULL(a) is a different function that returns 1 or 0
IFNULL(a, b)MySQL, SQLiteExactly 2Same result as COALESCE(a, b)
NVL(a, b)OracleExactly 2Oracle also has NVL2(a, if_not_null, if_null)
CASE WHEN a IS NULL THEN b ELSE a ENDAll of themAny logicLonger; use it when the rule is more than "replace NULL"

In the Playground, IFNULL and COALESCE give the same answer:

SQLite · runs in the Playground
SELECT id,
       IFNULL(shipped_date, 'Not shipped')   AS with_ifnull,
       COALESCE(shipped_date, 'Not shipped') AS with_coalesce
FROM orders
ORDER BY id
LIMIT 4;

▶ Run this query in the SQL Playground

IFNULL and COALESCE side by side
idwith_ifnullwith_coalesce
1Not shippedNot shipped
22023-04-092023-04-09
32023-07-102023-07-10
4Not shippedNot shipped
✓ 4 rows · real output from the Playground database

Prefer COALESCE unless a team standard says otherwise: it takes any number of arguments and runs unchanged if the query moves to another database.

COALESCE and Performance

COALESCE in SELECT costs almost nothing. In WHERE it can hurt: like any function wrapped around a column, it usually stops the database from using an index on that column.

FilterIndex-friendly?Better form
WHERE COALESCE(mobile, home) = '555-0142'Usually notWHERE mobile = '555-0142' OR (mobile IS NULL AND home = '555-0142')
WHERE COALESCE(discount, 0) = 0Usually notWHERE discount = 0 OR discount IS NULL

Check with EXPLAIN before rewriting, and only bother on large tables.

Common COALESCE Mistakes

Six errors that give wrong results, most of them without an error message.

1. Putting the default first

❌ Always returns the default
SQL
SELECT COALESCE('Not shipped', shipped_date)
FROM orders;
✅ Real value first, default last
SQL
SELECT COALESCE(shipped_date, 'Not shipped')
FROM orders;

COALESCE returns the first non-NULL argument. A literal is never NULL, so if it comes first, the column is never used.

2. Confusing NULL with 0 in a filter

❌ Skips the NULL rows
SQL
SELECT *
FROM pay
WHERE bonus = 0;
✅ Covers both
SQL
SELECT *
FROM pay
WHERE bonus = 0 OR bonus IS NULL;

bonus = 0 is unknown for NULL rows, so they are left out. Say explicitly whether "no bonus recorded" should count as zero.

3. Adding a nullable column without COALESCE

❌ NULL total for anyone without a bonus
SQL
SELECT name, salary + bonus AS total_pay
FROM pay;
✅ Missing bonus counts as 0
SQL
SELECT name, salary + COALESCE(bonus, 0) AS total_pay
FROM pay;

Arithmetic with NULL gives NULL, as the calculations example above shows for Rohan and Karan.

4. Forgetting COALESCE after a LEFT JOIN

❌ Shows NULL for customers with no orders
SQL
SELECT u.id, SUM(o.total) AS spend
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id;
✅ Shows 0
SQL
SELECT u.id, COALESCE(SUM(o.total), 0) AS spend
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id;

The LEFT JOIN keeps the customer, but SUM over no matching rows is NULL.

5. Choosing a default that invents data

❌ Unshipped orders look shipped today
SQL
SELECT id, COALESCE(shipped_date, CURRENT_DATE) AS shipped
FROM orders;
✅ Says what is true
SQL
SELECT id, COALESCE(shipped_date, 'Not shipped') AS shipped
FROM orders;

A fallback that looks like real data is worse than a blank. Use a label, or leave the NULL, when no honest default exists.

6. Mixing data types

❌ Error in PostgreSQL and SQL Server
SQL
SELECT COALESCE(shipped_date, 'Not shipped')
FROM orders;  -- shipped_date is a DATE column
✅ One type
SQL
SELECT COALESCE(CAST(shipped_date AS VARCHAR(10)), 'Not shipped')
FROM orders;

Databases with real date types cannot put a date and free text in one column. SQLite stores dates as text, which is why the shorter form runs in the Playground.

COALESCE Cheat Sheet

TaskPattern
Default textCOALESCE(shipped_date, 'Not shipped')
Fallback chainCOALESCE(mobile, home, office, 'No number')
Safe arithmeticsalary + COALESCE(bonus, 0)
0 instead of NULL after LEFT JOINCOALESCE(SUM(o.total), 0)
Average over everyone, not only recorded valuesAVG(COALESCE(bonus, 0))
Safe divisionCOALESCE(a / NULLIF(b, 0), 0)
Label for a missing joinCOALESCE(m.first_name, 'No manager')

Practice COALESCE Queries

6 exercises on the real Playground tables.

Write each query yourself first. Every solution has been run against the Playground database.

  1. 1Easy List the 8 most recent orders with their shipped date, showing "Awaiting shipment" when there is none. Table: orders

    Show solution
    SQLite · runs in the Playground
    SELECT id, status,
           COALESCE(shipped_date, 'Awaiting shipment') AS shipped
    FROM orders
    ORDER BY order_date DESC, id DESC
    LIMIT 8;

    ▶ Run this query in the SQL Playground

    COALESCE returns shipped_date when it exists and the label otherwise.

  2. 2Easy Show every employee's manager_id, with 0 for employees who have no manager. List the first 10 by id. Table: employees

    Show solution
    SQLite · runs in the Playground
    SELECT id, first_name, COALESCE(manager_id, 0) AS manager_id
    FROM employees
    ORDER BY id
    LIMIT 10;

    ▶ Run this query in the SQL Playground

    A numeric default keeps the column numeric. 0 is safe here because no employee has id 0.

  3. 3Medium For each product category, show the units sold, with 0 for any product that was never ordered counted in. Sort by units sold. Table: products, order_items

    Show solution
    SQLite · runs in the Playground
    SELECT p.category,
           COALESCE(SUM(oi.quantity), 0) AS units_sold
    FROM products p
    LEFT JOIN order_items oi ON oi.product_id = p.id
    GROUP BY p.category
    ORDER BY units_sold DESC;

    ▶ Run this query in the SQL Playground

    The LEFT JOIN keeps unsold products; COALESCE matters for any group whose SUM has nothing to add.

  4. 4Medium Show the 8 customers with the lowest total successful payments, including customers with no successful payment (shown as 0). Table: users, payments

    Show solution
    SQLite · runs in the Playground
    SELECT u.id, u.first_name, u.last_name,
           COALESCE(ROUND(SUM(p.amount), 2), 0) AS paid
    FROM users u
    LEFT JOIN payments p ON p.user_id = u.id AND p.status = 'success'
    GROUP BY u.id, u.first_name, u.last_name
    ORDER BY paid, u.id
    LIMIT 8;

    ▶ Run this query in the SQL Playground

    The status filter sits in ON, not WHERE, so customers without a successful payment stay in the result.

  5. 5Medium Show each employee with their manager's first name, or "Top level" if they have none. First 8 by id. Table: employees

    Show solution
    SQLite · runs in the Playground
    SELECT e.first_name AS employee,
           COALESCE(m.first_name, 'Top level') AS manager
    FROM employees e
    LEFT JOIN employees m ON m.id = e.manager_id
    ORDER BY e.id
    LIMIT 8;

    ▶ Run this query in the SQL Playground

    For employees without a manager the joined row is missing, so m.first_name is NULL.

  6. 6Hard For each category, show the number of products and the share (in percent) of products that have at least one review. Table: products, reviews

    Show solution
    SQLite · runs in the Playground
    SELECT p.category,
           COUNT(*) AS products,
           ROUND(100.0 * SUM(CASE WHEN COALESCE(r.reviews, 0) > 0 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_reviewed
    FROM products p
    LEFT JOIN (SELECT product_id, COUNT(*) AS reviews
               FROM reviews
               GROUP BY product_id) r ON r.product_id = p.id
    GROUP BY p.category
    ORDER BY pct_reviewed DESC, p.category;

    ▶ Run this query in the SQL Playground

    The subquery counts reviews per product; for products without reviews the LEFT JOIN gives NULL, which COALESCE turns into 0 before the comparison.

📝 Quiz — COALESCE

Test your understanding · 0/30 answered

Question 1 of 30

What does COALESCE return?

Question 2 of 30

What does COALESCE(NULL, NULL, 'SQLab Hub', 'Other') return?

Question 3 of 30

What does COALESCE return if every argument is NULL?

Question 4 of 30

Is NULL the same as 0?

Question 5 of 30

Is NULL the same as an empty string ''?

Question 6 of 30

How do you show 'Not Available' instead of a NULL phone?

Question 7 of 30

Can COALESCE take more than two arguments?

Question 8 of 30

What does COALESCE(mobile, home, office) implement?

Question 9 of 30

How does SUM(COALESCE(amount, 0)) differ from SUM(amount)?

Question 10 of 30

What does salary + COALESCE(bonus, 0) return when bonus is NULL?

Question 11 of 30

What does salary + bonus return when bonus is NULL?

Question 12 of 30

Is COALESCE standard SQL?

Question 13 of 30

What is the main difference between COALESCE and ISNULL?

Question 14 of 30

What is the difference between COALESCE and IFNULL?

Question 15 of 30

What is NVL?

Question 16 of 30

Can COALESCE be used inside a CASE WHEN condition?

Question 17 of 30

What does COALESCE(delivery_date, expected_delivery_date) return when delivery_date is NULL?

Question 18 of 30

How is COALESCE used with a LEFT JOIN?

Question 19 of 30

What is a common mistake with argument order?

Question 20 of 30

Why should all COALESCE arguments have compatible types?

Question 21 of 30

What does COUNT(COALESCE(email, '')) count, compared with COUNT(email)?

Question 22 of 30

What is a good use of COALESCE(primary_email, secondary_email, backup_email)?

Question 23 of 30

How do you make WHERE COALESCE(mobile, home) = :x more index-friendly?

Question 24 of 30

What can EXPLAIN tell you about a query with COALESCE in WHERE?

Question 25 of 30

Which databases support COALESCE?

Question 26 of 30

How do analysts use COALESCE in reports?

Question 27 of 30

Is COALESCE a common interview topic?

Question 28 of 30

How does COALESCE(col, x) compare with CASE WHEN col IS NULL THEN x ELSE col END?

Question 29 of 30

Why does choosing COALESCE over ISNULL or NVL matter?

Question 30 of 30

How are COALESCE and NULLIF related?

COALESCE Interview Questions

Q1. What does COALESCE do, and what does it return when every argument is NULL?

It returns the first argument that is not NULL, checking from left to right. If all arguments are NULL, it returns NULL.

Q2. How would you show 0 instead of NULL for customers without orders?

LEFT JOIN orders to users, group by the user, and wrap the aggregate: COALESCE(SUM(o.total), 0). COUNT(o.id) already returns 0, so it needs no COALESCE.

Q3. Does COALESCE inside SUM change the total?

No. SUM skips NULLs, so adding zeros changes nothing, except that the result is 0 instead of NULL when there are no values at all. Inside AVG and COUNT it does change the answer, because the NULL rows are then counted.

Q4. What is the difference between COALESCE, ISNULL, IFNULL and NVL?

COALESCE is standard SQL and takes any number of arguments. ISNULL (SQL Server), IFNULL (MySQL, SQLite) and NVL (Oracle) take exactly two. SQL Server's ISNULL also returns the type of its first argument, which can truncate the replacement.

Q5. How do you avoid a division-by-zero error and a NULL result at the same time?

COALESCE(a / NULLIF(b, 0), 0). NULLIF turns a zero denominator into NULL, so the division returns NULL instead of failing, and COALESCE replaces that NULL with 0.

Q6. Why can COALESCE in WHERE be slow?

A function around a column usually stops the database from using an index on it. Rewrite WHERE COALESCE(a, b) = x as direct conditions on a and b when the table is large.

Q7. How would you build a cascading default, such as a customer price, then a region price, then a list price?

COALESCE(customer_price, region_price, list_price). The most specific value goes first and the most general last.

Q8. When is 0 the wrong default for a NULL?

Whenever 0 is a meaningful value that would be mistaken for real data, such as a rating, a price or a test score. Then a label such as "not recorded", or leaving the NULL, is more honest.

Frequently Asked Questions

What is COALESCE in SQL?

COALESCE is a function that returns the first non-NULL value from a list of expressions. If every expression is NULL, it returns NULL. It is the standard way to supply a fallback for missing data.

Why do we use COALESCE?

To replace missing values with a sensible default, so that reports show a label instead of a blank and calculations do not turn into NULL because one input is missing.

How does COALESCE work?

COALESCE checks its arguments from left to right and returns the first one that is not NULL. For example COALESCE(NULL, NULL, 'SQLab Hub', 'Other') returns 'SQLab Hub'.

What is the difference between COALESCE and ISNULL?

COALESCE is standard SQL and accepts any number of arguments. ISNULL is specific to SQL Server and takes exactly two; MySQL has a different ISNULL that only tests whether a value is NULL.

What is the difference between COALESCE and IFNULL?

IFNULL, available in MySQL and SQLite, works like COALESCE with exactly two arguments. COALESCE can chain any number of fallback values.

Can COALESCE handle multiple columns?

Yes. COALESCE(col1, col2, col3) returns the first of the columns that has a value, which is how a mobile, home, office phone fallback is built.

How do data analysts use COALESCE?

To label missing data before reporting, to show 0 instead of NULL after a LEFT JOIN, to keep calculations working when one input is missing, and to build clean columns for dashboards.

Is COALESCE important in SQL interviews?

Yes. Typical questions cover COALESCE versus ISNULL, IFNULL and NVL, COALESCE after a LEFT JOIN, and how COALESCE changes SUM, AVG and COUNT.