COALESCE

Feb 23, 2026

·

5

min read

Category: Conditional Expressions

Platform Support:

✅ Snowflake | ✅ BigQuery | ✅ Databricks

Description

COALESCE returns the first non-NULL value from a list of expressions. It's essential for handling NULL values, providing default values, and consolidating data from multiple columns. Evaluates arguments from left to right and stops at the first non-NULL value.

Syntax

COALESCE(value1, value2, ..., valueN)
COALESCE(value1, value2, ..., valueN)
COALESCE(value1, value2, ..., valueN)

Returns: The first non-NULL value, or NULL if all values are NULL

Platform-Specific Notes

Snowflake:

  • Also supports NVL(expr1, expr2) - 2-argument version

  • IFNULL(expr1, expr2) - alias for NVL

  • IFF(condition, true_val, false_val) - conditional alternative

BigQuery:

  • Also supports IFNULL(expr1, expr2) - 2-argument version

  • IF(condition, true_val, false_val) - conditional alternative

Databricks:

  • Also supports NVL(expr1, expr2) - 2-argument version

  • IFNULL(expr1, expr2) - alias for NVL

  • Standard Spark SQL function

Example 1: Handle NULL Contact Information

All Platforms:

SELECT 
    customer_id,
    customer_name,
    mobile_phone,
    home_phone,
    work_phone,
    COALESCE(mobile_phone, home_phone, work_phone, 'No phone available') as primary_contact,
    COALESCE(email, backup_email, 'noemail@company.com') as contact_email
FROM

SELECT 
    customer_id,
    customer_name,
    mobile_phone,
    home_phone,
    work_phone,
    COALESCE(mobile_phone, home_phone, work_phone, 'No phone available') as primary_contact,
    COALESCE(email, backup_email, 'noemail@company.com') as contact_email
FROM

SELECT 
    customer_id,
    customer_name,
    mobile_phone,
    home_phone,
    work_phone,
    COALESCE(mobile_phone, home_phone, work_phone, 'No phone available') as primary_contact,
    COALESCE(email, backup_email, 'noemail@company.com') as contact_email
FROM

Sample Data (customers table):

customer_id

customer_name

mobile_phone

home_phone

work_phone

email

backup_email

1

John Smith

555-1234

NULL

NULL

john@email.com

NULL

2

Maria Garcia

NULL

555-5678

NULL

NULL

maria.backup@email.com

3

Sarah Johnson

NULL

NULL

555-9012

sarah@email.com

NULL

4

Ahmed Hassan

NULL

NULL

NULL

NULL

NULL

Result:

customer_id

customer_name

primary_contact

contact_email

1

John Smith

555-1234

john@email.com

2

Maria Garcia

555-5678

maria.backup@email.com

3

Sarah Johnson

555-9012

sarah@email.com

4

Ahmed Hassan

No phone available

noemail@company.com

Example 2: Consolidate Price Information

All Platforms:

SELECT 
    product_id,
    product_name,
    sale_price,
    regular_price,
    msrp,
    COALESCE(sale_price, regular_price, msrp) as final_price,
    COALESCE(sale_price, regular_price, msrp, 0) as display_price,
    CASE 
        WHEN sale_price IS NOT NULL THEN 'On Sale'
        WHEN regular_price IS NOT NULL THEN 'Regular Price'
        WHEN msrp IS NOT NULL THEN 'MSRP'
        ELSE 'Price Not Set'
    END as price_type
FROM

SELECT 
    product_id,
    product_name,
    sale_price,
    regular_price,
    msrp,
    COALESCE(sale_price, regular_price, msrp) as final_price,
    COALESCE(sale_price, regular_price, msrp, 0) as display_price,
    CASE 
        WHEN sale_price IS NOT NULL THEN 'On Sale'
        WHEN regular_price IS NOT NULL THEN 'Regular Price'
        WHEN msrp IS NOT NULL THEN 'MSRP'
        ELSE 'Price Not Set'
    END as price_type
FROM

SELECT 
    product_id,
    product_name,
    sale_price,
    regular_price,
    msrp,
    COALESCE(sale_price, regular_price, msrp) as final_price,
    COALESCE(sale_price, regular_price, msrp, 0) as display_price,
    CASE 
        WHEN sale_price IS NOT NULL THEN 'On Sale'
        WHEN regular_price IS NOT NULL THEN 'Regular Price'
        WHEN msrp IS NOT NULL THEN 'MSRP'
        ELSE 'Price Not Set'
    END as price_type
FROM

Sample Data (products table):

product_id

product_name

sale_price

regular_price

msrp

101

Laptop

899.99

999.99

1199.99

102

Mouse

NULL

29.99

39.99

103

Keyboard

NULL

NULL

89.99

104

USB Cable

NULL

NULL

NULL

Result:

product_id

product_name

final_price

display_price

price_type

101

Laptop

899.99

899.99

On Sale

102

Mouse

29.99

29.99

Regular Price

103

Keyboard

89.99

89.99

MSRP

104

USB Cable

NULL

0.00

Price Not Set

Example 3: Data Quality - Fill Missing Values

All Platforms:

SELECT 
    order_id,
    customer_id,
    -- Use shipping address if billing address is missing
    COALESCE(billing_address, shipping_address) as invoice_address,
    -- Use estimated date if actual date is missing
    COALESCE(actual_delivery_date, estimated_delivery_date) as delivery_date,
    -- Use default values for missing metrics
    COALESCE(discount_amount, 0) as discount,
    COALESCE(tax_amount, order_total * 0.08) as tax,
    order_total + COALESCE(shipping_cost, 9.99) as total_with_shipping
FROM

SELECT 
    order_id,
    customer_id,
    -- Use shipping address if billing address is missing
    COALESCE(billing_address, shipping_address) as invoice_address,
    -- Use estimated date if actual date is missing
    COALESCE(actual_delivery_date, estimated_delivery_date) as delivery_date,
    -- Use default values for missing metrics
    COALESCE(discount_amount, 0) as discount,
    COALESCE(tax_amount, order_total * 0.08) as tax,
    order_total + COALESCE(shipping_cost, 9.99) as total_with_shipping
FROM

SELECT 
    order_id,
    customer_id,
    -- Use shipping address if billing address is missing
    COALESCE(billing_address, shipping_address) as invoice_address,
    -- Use estimated date if actual date is missing
    COALESCE(actual_delivery_date, estimated_delivery_date) as delivery_date,
    -- Use default values for missing metrics
    COALESCE(discount_amount, 0) as discount,
    COALESCE(tax_amount, order_total * 0.08) as tax,
    order_total + COALESCE(shipping_cost, 9.99) as total_with_shipping
FROM

Sample Data (orders table):

order_id

customer_id

billing_address

shipping_address

actual_delivery_date

estimated_delivery_date

discount_amount

tax_amount

order_total

shipping_cost

1001

101

123 Main St

123 Main St

2024-01-20

2024-01-18

10.00

NULL

100.00

5.00

1002

102

NULL

456 Oak Ave

NULL

2024-01-25

NULL

8.00

150.00

NULL

1003

103

789 Elm St

789 Elm St

2024-01-22

2024-01-23

15.00

12.00

200.00

0.00

Result:

order_id

invoice_address

delivery_date

discount

tax

total_with_shipping

1001

123 Main St

2024-01-20

10.00

8.00

105.00

1002

456 Oak Ave

2024-01-25

0.00

8.00

159.99

1003

789 Elm St

2024-01-22

15.00

12.00

200.00

Example 4: Aggregation with NULL Handling

All Platforms:

SELECT 
    department,
    COUNT(*) as total_employees,
    -- Count employees with bonus (NULL-safe)
    COUNT(bonus_amount) as employees_with_bonus,
    -- Average bonus, treating NULL as 0
    AVG(COALESCE(bonus_amount, 0)) as avg_bonus_including_zeros,
    -- Average bonus, excluding NULLs
    AVG(bonus_amount) as avg_bonus_excluding_nulls,
    -- Total bonus pool
    SUM(COALESCE(bonus_amount, 0)) as total_bonus_pool
FROM employees
GROUP BY

SELECT 
    department,
    COUNT(*) as total_employees,
    -- Count employees with bonus (NULL-safe)
    COUNT(bonus_amount) as employees_with_bonus,
    -- Average bonus, treating NULL as 0
    AVG(COALESCE(bonus_amount, 0)) as avg_bonus_including_zeros,
    -- Average bonus, excluding NULLs
    AVG(bonus_amount) as avg_bonus_excluding_nulls,
    -- Total bonus pool
    SUM(COALESCE(bonus_amount, 0)) as total_bonus_pool
FROM employees
GROUP BY

SELECT 
    department,
    COUNT(*) as total_employees,
    -- Count employees with bonus (NULL-safe)
    COUNT(bonus_amount) as employees_with_bonus,
    -- Average bonus, treating NULL as 0
    AVG(COALESCE(bonus_amount, 0)) as avg_bonus_including_zeros,
    -- Average bonus, excluding NULLs
    AVG(bonus_amount) as avg_bonus_excluding_nulls,
    -- Total bonus pool
    SUM(COALESCE(bonus_amount, 0)) as total_bonus_pool
FROM employees
GROUP BY

Sample Data (employees table):

employee_id

department

salary

bonus_amount

1

Sales

75000

5000

2

Sales

65000

NULL

3

Sales

80000

6000

4

IT

90000

7000

5

IT

85000

NULL

6

IT

95000

NULL

Result:

department

total_employees

employees_with_bonus

avg_bonus_including_zeros

avg_bonus_excluding_nulls

total_bonus_pool

Sales

3

2

3666.67

5500.00

11000

IT

3

1

2333.33

7000.00

7000

Example 5: Multi-Source Data Consolidation

All Platforms:

SELECT 
    user_id,
    -- Try profile name, then account name, then email prefix, then 'Anonymous'
    COALESCE(
        profile_display_name,
        account_full_name,
        SPLIT_PART(email, '@', 1),
        'Anonymous User'
    ) as display_name,
    -- Get most recent activity timestamp from multiple sources
    COALESCE(
        last_purchase_date,
        last_login_date,
        account_created_date
    ) as last_activity,
    -- User timezone preference with fallback
    COALESCE(
        user_timezone,
        account_country_timezone,
        'UTC'
    ) as timezone
FROM

SELECT 
    user_id,
    -- Try profile name, then account name, then email prefix, then 'Anonymous'
    COALESCE(
        profile_display_name,
        account_full_name,
        SPLIT_PART(email, '@', 1),
        'Anonymous User'
    ) as display_name,
    -- Get most recent activity timestamp from multiple sources
    COALESCE(
        last_purchase_date,
        last_login_date,
        account_created_date
    ) as last_activity,
    -- User timezone preference with fallback
    COALESCE(
        user_timezone,
        account_country_timezone,
        'UTC'
    ) as timezone
FROM

SELECT 
    user_id,
    -- Try profile name, then account name, then email prefix, then 'Anonymous'
    COALESCE(
        profile_display_name,
        account_full_name,
        SPLIT_PART(email, '@', 1),
        'Anonymous User'
    ) as display_name,
    -- Get most recent activity timestamp from multiple sources
    COALESCE(
        last_purchase_date,
        last_login_date,
        account_created_date
    ) as last_activity,
    -- User timezone preference with fallback
    COALESCE(
        user_timezone,
        account_country_timezone,
        'UTC'
    ) as timezone
FROM

Sample Data (user_profiles table):

user_id

profile_display_name

account_full_name

email

last_purchase_date

last_login_date

account_created_date

user_timezone

account_country_timezone

1

JohnS

NULL

john@email.com

2024-01-20

2024-01-25

2023-06-15

America/New_York

NULL

2

NULL

Maria Garcia

maria@email.com

NULL

2024-01-22

2023-08-20

NULL

Europe/Madrid

3

NULL

NULL

sarah@email.com

NULL

NULL

2024-01-10

NULL

NULL

Result:

user_id

display_name

last_activity

timezone

1

JohnS

2024-01-25

America/New_York

2

Maria Garcia

2024-01-22

Europe/Madrid

3

sarah

2024-01-10

UTC

COALESCE vs Other NULL Functions

Function

Arguments

Platform

Use Case

COALESCE

2+

All

Multiple fallback values

NVL

2

Snowflake, Databricks

Simple NULL replacement

IFNULL

2

All

Simple NULL replacement

NULLIF

2

All

Return NULL if values equal

Common Use Cases

  1. Default values: Provide fallback when data is missing

  2. Contact consolidation: Get best available contact method

  3. Price selection: Choose best available price point

  4. Data quality: Fill gaps in incomplete datasets

  5. User experience: Display meaningful defaults

  6. Calculations: Prevent NULL propagation in math operations

  7. Report formatting: Replace NULL with readable text

COALESCE in Calculations

All Platforms:

SELECT 
    product_id,
    base_price,
    discount_pct,
    tax_pct,
    -- Prevent NULL in calculations
    base_price * (1 - COALESCE(discount_pct, 0)) as price_after_discount,
    base_price * (1 - COALESCE(discount_pct, 0)) * (1 + COALESCE(tax_pct, 0.08)) as final_price
FROM

SELECT 
    product_id,
    base_price,
    discount_pct,
    tax_pct,
    -- Prevent NULL in calculations
    base_price * (1 - COALESCE(discount_pct, 0)) as price_after_discount,
    base_price * (1 - COALESCE(discount_pct, 0)) * (1 + COALESCE(tax_pct, 0.08)) as final_price
FROM

SELECT 
    product_id,
    base_price,
    discount_pct,
    tax_pct,
    -- Prevent NULL in calculations
    base_price * (1 - COALESCE(discount_pct, 0)) as price_after_discount,
    base_price * (1 - COALESCE(discount_pct, 0)) * (1 + COALESCE(tax_pct, 0.08)) as final_price
FROM

Performance Considerations

  • COALESCE short-circuits: stops at first non-NULL value

  • Evaluates expressions left to right

  • More arguments = more evaluation overhead

  • Consider indexing frequently checked columns

  • Use simple IFNULL/NVL for 2-argument cases (may be optimized)

Best Practices

  1. Order by preference: Put most preferred value first

  2. Always provide final default: Prevent unexpected NULLs

  3. Document logic: Explain why each fallback is chosen

  4. Type compatibility: All arguments must be compatible types

  5. Avoid expensive expressions: Don't call functions unnecessarily

  6. Consider CASE: For complex conditional logic

  7. Test with real data: Ensure fallback logic works correctly

Interested to Learn More?
Try Out the Free 14-Days Trial

More Articles

decorative icon

Experience Analytics for the AI-Era

Start your 14-day trial today - it's free and no credit card needed

decorative icon

Experience Analytics for the AI-Era

Start your 14-day trial today - it's free and no credit card needed

decorative icon

Experience Analytics for the AI-Era

Start your 14-day trial today - it's free and no credit card needed

Copyright © 2026 Paradime Labs, Inc.

Made with ❤️ in San Francisco ・ London

*dbt® and dbt Core® are federally registered trademarks of dbt Labs, Inc. in the United States and various jurisdictions around the world. Paradime is not a partner of dbt Labs. All rights therein are reserved to dbt Labs. Paradime is not a product or service of or endorsed by dbt Labs, Inc.

Copyright © 2026 Paradime Labs, Inc.

Made with ❤️ in San Francisco ・ London

*dbt® and dbt Core® are federally registered trademarks of dbt Labs, Inc. in the United States and various jurisdictions around the world. Paradime is not a partner of dbt Labs. All rights therein are reserved to dbt Labs. Paradime is not a product or service of or endorsed by dbt Labs, Inc.

Copyright © 2026 Paradime Labs, Inc.

Made with ❤️ in San Francisco ・ London

*dbt® and dbt Core® are federally registered trademarks of dbt Labs, Inc. in the United States and various jurisdictions around the world. Paradime is not a partner of dbt Labs. All rights therein are reserved to dbt Labs. Paradime is not a product or service of or endorsed by dbt Labs, Inc.