COALESCE
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)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 NVLIFF(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 customers;Sample Data (customers table):
customer_id | customer_name | mobile_phone | home_phone | work_phone | backup_email | |
|---|---|---|---|---|---|---|
1 | John Smith | 555-1234 | NULL | NULL | NULL | |
2 | Maria Garcia | NULL | 555-5678 | NULL | NULL | |
3 | Sarah Johnson | NULL | NULL | 555-9012 | NULL | |
4 | Ahmed Hassan | NULL | NULL | NULL | NULL | NULL |
Result:
customer_id | customer_name | primary_contact | contact_email |
|---|---|---|---|
1 | John Smith | 555-1234 | |
2 | Maria Garcia | 555-5678 | |
3 | Sarah Johnson | 555-9012 | |
4 | Ahmed Hassan | No phone available |
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 products;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 orders;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 department;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 user_profiles;Sample Data (user_profiles table):
user_id | profile_display_name | account_full_name | last_purchase_date | last_login_date | account_created_date | user_timezone | account_country_timezone | |
|---|---|---|---|---|---|---|---|---|
1 | JohnS | NULL | 2024-01-20 | 2024-01-25 | 2023-06-15 | America/New_York | NULL | |
2 | NULL | Maria Garcia | NULL | 2024-01-22 | 2023-08-20 | NULL | Europe/Madrid | |
3 | NULL | NULL | 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
- Default values: Provide fallback when data is missing
- Contact consolidation: Get best available contact method
- Price selection: Choose best available price point
- Data quality: Fill gaps in incomplete datasets
- User experience: Display meaningful defaults
- Calculations: Prevent NULL propagation in math operations
- 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 products;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
- Order by preference: Put most preferred value first
- Always provide final default: Prevent unexpected NULLs
- Document logic: Explain why each fallback is chosen
- Type compatibility: All arguments must be compatible types
- Avoid expensive expressions: Don't call functions unnecessarily
- Consider CASE: For complex conditional logic
- Test with real data: Ensure fallback logic works correctly
Interested to Learn More? Try Out the Free 14-Days Trial
One AI-native workspace to build, ship, and monitor dbt™ — without the tool sprawl.