Skip to content

MySQL - Coalesce() Function

In database management, it’s common for tables to have records with missing or unknown data. Instead of leaving these fields empty or using placeholder values like zero, SQL provides a special marker: NULL. A NULL value signifies the absence of data.

However, when running queries, NULL values can be inconvenient. The COALESCE() function is a powerful tool for handling NULLs by providing default or fallback values in your query results.

Understanding the MySQL COALESCE() Function

Section titled “Understanding the MySQL COALESCE() Function”

The MySQL COALESCE() function evaluates a list of arguments in order and returns the first non-NULL value it encounters. If all arguments in the list are NULL, the function itself returns NULL.

The basic syntax for the COALESCE() function is as follows:

COALESCE(expression1, expression2, ..., expression_n)

The function can be used within any SELECT statement.

In this query, COALESCE() will check each value from left to right. It will skip the first two NULL values and return ‘Hello’, as it’s the first non-NULL value.

SELECT COALESCE(NULL, NULL, 'Hello', 'Tutorialspoint') AS Result;
Result
Hello

Let’s demonstrate COALESCE() with a practical example. Imagine we have a products table where some products have a sale_price and others only have a regular_price.

First, let’s create a products table.

CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
product_name VARCHAR(100) NOT NULL,
regular_price DECIMAL(10, 2) NOT NULL,
sale_price DECIMAL(10, 2)
);

Now, let’s insert some data. Note that sale_price is NULL for some products.

INSERT INTO products (product_name, regular_price, sale_price)
VALUES
('Laptop', 1200.00, 999.00),
('Mouse', 25.00, NULL),
('Keyboard', 75.00, 60.00),
('Monitor', 300.00, NULL);

The products table now looks like this:

idproduct_nameregular_pricesale_price
1Laptop1200.00999.00
2Mouse25.00NULL
3Keyboard75.0060.00
4Monitor300.00NULL

Example: Using COALESCE() to Determine Display Price

Section titled “Example: Using COALESCE() to Determine Display Price”

We want to display the sale_price if it exists; otherwise, we’ll show the regular_price. COALESCE() is perfect for this. We can create a new column in our result set called display_price.

SELECT
product_name,
regular_price,
sale_price,
COALESCE(sale_price, regular_price) AS display_price
FROM products;

The result set elegantly shows the correct price to display for each product.

product_nameregular_pricesale_pricedisplay_price
Laptop1200.00999.00999.00
Mouse25.00NULL25.00
Keyboard75.0060.0060.00
Monitor300.00NULL300.00

A crucial aspect of COALESCE() is data type precedence. If the arguments have different data types, the result will have the data type with the higher precedence. For example, a DECIMAL type has higher precedence than an INT. If you use COALESCE(int_column, decimal_column), the result will be cast to DECIMAL.

Unlike COALESCE, the IFNULL(expr1, expr2) function is specific to MySQL and only takes two arguments. COALESCE is standard SQL and more flexible as it accepts multiple arguments. For simple two-argument fallbacks, IFNULL can be slightly faster, but COALESCE is generally preferred for its standardization and flexibility.

Using COALESCE() with Modern Application Code

Section titled “Using COALESCE() with Modern Application Code”

Executing SQL queries from an application is a standard task. Below are examples of how to run the COALESCE query using modern programming languages. These examples emphasize security, maintainability, and modern best practices.

Security Best Practice: Environment Variables

Section titled “Security Best Practice: Environment Variables”

Never hardcode database credentials in your source code. Use environment variables to store sensitive information like database hosts, usernames, and passwords. This prevents credentials from being exposed in version control systems like Git.

# .env file (should not be committed to Git)
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=your_secure_password
DB_NAME=your_database_name
Node.js
Python
Java
PHP
This example uses the `mysql2/promise` library for `async/await` support and connection pooling, which is highly recommended for web applications.
**1. Setup:**
`npm install mysql2 dotenv`
**2. Code (`app.js`):**
```javascript
const mysql = require('mysql2/promise');
require('dotenv').config();
// Create a connection pool
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
async function getProductPrices() {
let connection;
try {
// Get a connection from the pool
connection = await pool.getConnection();
console.log("Successfully connected to the database.");
const sql = `
SELECT
product_name,
regular_price,
sale_price,
COALESCE(sale_price, regular_price) AS display_price
FROM products;`;
const [rows] = await connection.execute(sql);
console.log("\nProduct Prices:");
console.table(rows);
} catch (error) {
console.error("An error occurred:", error);
} finally {
if (connection) {
connection.release(); // Release the connection back to the pool
}
}
}
async function main() {
await getProductPrices();
await pool.end(); // Close the pool when the application shuts down
}
main();

3. Run: node app.js

This example uses the mysql-connector-python library and context managers (with statements) for clean resource management.

1. Setup: pip install mysql-connector-python python-dotenv

2. Code (app.py):

import mysql.connector
import os
from dotenv import load_dotenv
from decimal import Decimal
load_dotenv()
def get_product_prices():
try:
# The 'with' statement ensures the connection is closed automatically
with mysql.connector.connect(
host=os.getenv("DB_HOST"),
user=os.getenv("DB_USER"),
password=os.getenv("DB_PASSWORD"),
database=os.getenv("DB_NAME")
) as connection:
print("Successfully connected to the database.")
sql = """
SELECT
product_name,
regular_price,
sale_price,
COALESCE(sale_price, regular_price) AS display_price
FROM products;
"""
# The 'with' statement ensures the cursor is closed automatically
with connection.cursor(dictionary=True) as cursor:
cursor.execute(sql)
results = cursor.fetchall()
print("\nProduct Prices:")
for row in results:
print(f"- {row['product_name']}: ${row['display_price']}")
except mysql.connector.Error as e:
print(f"Error connecting to MySQL or executing query: {e}")
if __name__ == "__main__":
get_product_prices()

3. Run: python app.py

This modern Java example uses JDBC with try-with-resources for automatic resource management and a properties file for configuration. It’s assumed you are using a build tool like Maven or Gradle.

1. Maven Dependency (pom.xml):

<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>

2. Code (Main.java):

import java.sql.*;
public class Main {
public static void main(String[] args) {
// Load credentials from environment variables for security
String url = "jdbc:mysql://" + System.getenv("DB_HOST") + "/" + System.getenv("DB_NAME");
String user = System.getenv("DB_USER");
String password = System.getenv("DB_PASSWORD");
String sql = "SELECT product_name, regular_price, sale_price, " +
"COALESCE(sale_price, regular_price) AS display_price " +
"FROM products";
// try-with-resources ensures all resources are closed automatically
try (Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
System.out.println("Successfully connected to the database.");
System.out.println("\nProduct Prices:");
System.out.printf("%-20s %-15s\n", "Product Name", "Display Price");
System.out.println("-------------------------------------");
while (rs.next()) {
String productName = rs.getString("product_name");
double displayPrice = rs.getDouble("display_price");
System.out.printf("%-20s $%-14.2f\n", productName, displayPrice);
}
} catch (SQLException e) {
System.err.println("Database error occurred:");
e.printStackTrace();
}
}
}

This example uses the modern mysqli extension with an object-oriented style and prepared statements to prevent SQL injection.

1. Setup: composer require vlucas/phpdotenv

2. Code (app.php):

<?php
require_once __DIR__ . '/vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
// Database credentials from .env file
$dbhost = $_ENV['DB_HOST'];
$dbuser = $_ENV['DB_USER'];
$dbpass = $_ENV['DB_PASSWORD'];
$dbname = $_ENV['DB_NAME'];
// Establish a connection using mysqli (object-oriented style)
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
$query = "SELECT product_name, regular_price, sale_price, COALESCE(sale_price, regular_price) AS display_price FROM products";
try {
$stmt = $mysqli->prepare($query);
$stmt->execute();
$result = $stmt->get_result();
echo "Successfully connected and queried the database.\n\n";
echo "Product Prices:\n";
printf("%-20s %s\n", "Product", "Display Price");
echo str_repeat('-', 35) . "\n";
while ($row = $result->fetch_assoc()) {
printf("%-20s $%.2f\n", $row['product_name'], $row['display_price']);
}
$stmt->close();
} catch (mysqli_sql_exception $e) {
echo "An error occurred: " . $e->getMessage() . "\n";
} finally {
$mysqli->close();
}
?>

3. Run: php app.php