Home Functions GREATEST()
SQL Conditional & NULL Function

GREATEST()

GREATEST() returns the largest value from a list of expressions compared across columns in the same row, unlike MAX() which aggregates down a column.

MySQLPostgreSQLSQLite
Returns: The largest of the arguments passed to it, evaluated row by row. The data type follows the usual type promotion rules across the arguments.

Syntax

GREATEST(value1, value2)GREATEST(value1, value2, value3, ...)GREATEST(column_a, column_b, column_c)GREATEST(expression, literal)
ParameterTypeRequiredDescription
value1 any comparable yes The first value to compare. Can be a column, literal or expression.
value2 any comparable yes The second value to compare. At least two arguments are required.
value3, ... any comparable no Any number of additional values. GREATEST compares them all and returns the largest.

How it works

GREATEST() takes two or more arguments and returns the largest one. The key point is that it works row by row, across the columns you list. For every row the database looks at the arguments side by side and returns whichever is biggest. It is a horizontal comparison, not a vertical one.

This is the opposite of MAX(). MAX() is an aggregate: it scans many rows and collapses a single column down to one value. GREATEST() keeps every row and simply picks the largest of several values within that row. If you have three score columns and want the best score per student, you want GREATEST(). If you have one score column and want the best score in the whole class, you want MAX(). Its mirror image is LEAST(), which returns the smallest of the arguments.

NULL handling is where the dialects diverge, so read this carefully. In MySQL, GREATEST() returns NULL if any argument is NULL, because NULL is treated as unknown and poisons the whole comparison. In PostgreSQL, GREATEST() ignores NULL arguments and returns the largest of the non-NULL values, only returning NULL when every argument is NULL. SQLite follows the PostgreSQL style and skips NULLs. SQL Server did not have the function at all until SQL Server 2022; on older versions you emulate it with a CASE expression or a VALUES subquery. See the SQL functions library for related helpers.

Examples

Highest of three score columns (row-wise)

-- One row per student, best of three attempts
SELECT student, GREATEST(score1, score2, score3) AS best_score
FROM exam_results;
Result
student | best_score
--------+-----------
 Ali    |         88
 Sara   |         95
 Omar   |         72

Latest of several date columns

-- Most recent activity timestamp per user
SELECT user_id,
       GREATEST(last_login, last_order, last_comment) AS last_active
FROM user_activity;
Result
user_id | last_active
--------+------------
     1  | 2026-06-30
     2  | 2026-07-01
     3  | 2026-05-14

Clamp a value to a floor of zero

-- Never let the adjusted balance go below 0
SELECT account_id,
       balance,
       GREATEST(balance - fee, 0) AS balance_after_fee
FROM accounts;
Result
account_id | balance | balance_after_fee
-----------+---------+------------------
       10  |    50.0 |             45.0
       11  |     3.0 |              0.0
       12  |     0.0 |              0.0

Per-engine NULL behaviour

-- MySQL returns NULL because one argument is NULL.
-- PostgreSQL and SQLite return 10 (they ignore NULL).
SELECT GREATEST(10, NULL, 4) AS result;
Result
MySQL       -> result = NULL
PostgreSQL  -> result = 10
SQLite      -> result = 10

Emulate GREATEST on older SQL Server

-- Pre-2022 SQL Server has no GREATEST; use VALUES
SELECT id,
       (SELECT MAX(v)
        FROM (VALUES (a), (b), (c)) AS t(v)) AS biggest
FROM measurements;
Result
id | biggest
---+--------
 1 |      9
 2 |     14
 3 |      6

Common mistakes

Wrong
-- WRONG: expecting the largest value in the column.
-- GREATEST compares its arguments row by row, so this
-- just returns the single column value on every row.
SELECT GREATEST(score) FROM exam_results;
Right
-- To get the largest value down a column, use MAX().
SELECT MAX(score) AS top_score FROM exam_results;

The number one GREATEST() mistake: confusing it with MAX(). GREATEST() is row-wise across columns, MAX() is an aggregate down rows. If you want the best score across three columns per student, use GREATEST(score1, score2, score3); if you want the best score in the whole table, use MAX(score).

Wrong
-- On MySQL this returns NULL for every row that has
-- any NULL date, silently hiding real activity.
SELECT GREATEST(last_login, last_order) AS last_active
FROM user_activity;
Right
-- Coalesce NULLs to a safe floor first on MySQL
SELECT GREATEST(
         COALESCE(last_login, '1970-01-01'),
         COALESCE(last_order, '1970-01-01')
       ) AS last_active
FROM user_activity;

NULL handling differs by engine. MySQL returns NULL if any argument is NULL, while PostgreSQL and SQLite ignore NULLs. If you need portable behaviour, wrap each argument in COALESCE so a missing value cannot poison the result.

Wrong
-- Fails on SQL Server 2019 and earlier:
-- 'GREATEST is not a recognized built-in function name'
SELECT GREATEST(a, b, c) FROM measurements;
Right
-- GREATEST was added in SQL Server 2022. On older
-- versions emulate it with CASE or a VALUES subquery.
SELECT (SELECT MAX(v)
        FROM (VALUES (a), (b), (c)) AS t(v)) AS biggest
FROM measurements;

GREATEST() is standard in MySQL, PostgreSQL and SQLite, but SQL Server only added it in the 2022 release. Check your target version before relying on it, and keep a CASE or VALUES fallback for older SQL Server instances.

Performance

GREATEST() is a lightweight scalar function evaluated once per row, so its own cost is negligible compared with reading the rows. The comparisons happen in memory and add almost nothing to a query that is already scanning the table.

The catch is that wrapping columns in GREATEST() inside a WHERE clause makes the predicate non sargable, so the optimiser cannot use a plain index on those columns and falls back to a full scan. If you filter on the result frequently, consider a computed or generated column that stores GREATEST(...) and index that instead.

Do not confuse the row-wise cost of GREATEST() with the aggregate cost of MAX(). MAX() may need to sort or scan an index across many rows, whereas GREATEST() never looks beyond the current row.

Interview questions

What is the difference between GREATEST() and MAX()?

GREATEST() is a row-wise scalar function that returns the largest of several values (usually columns) within the same row. MAX() is an aggregate that returns the largest value in a single column across many rows. GREATEST compares horizontally across columns; MAX compares vertically down rows.

-- Best of three columns per row vs largest in a column
SELECT GREATEST(a, b, c) AS row_best FROM t;
SELECT MAX(a)            AS col_max  FROM t;

How does GREATEST() handle NULL arguments?

It depends on the database. In MySQL, GREATEST() returns NULL if any argument is NULL. In PostgreSQL and SQLite, it ignores NULL arguments and returns the largest non-NULL value, only returning NULL when every argument is NULL. Wrap arguments in COALESCE for portable behaviour.

Is GREATEST() available in SQL Server?

Only from SQL Server 2022 onward. Earlier versions do not have it, so you emulate it with a CASE expression or a MAX over a VALUES subquery, such as (SELECT MAX(v) FROM (VALUES (a),(b),(c)) t(v)).

How would you clamp a value so it never goes below zero?

Use GREATEST(expression, 0). Because GREATEST returns the larger of the two, any negative result of the expression is replaced by 0. To also cap an upper bound, combine it with LEAST, for example LEAST(GREATEST(x, 0), 100).

SELECT GREATEST(balance - fee, 0) AS floored FROM accounts;

How do you find the most recent of several date columns per row?

Pass the date columns to GREATEST, for example GREATEST(last_login, last_order, last_comment). It returns the latest date on each row. On MySQL, guard against NULL columns with COALESCE so a single missing date does not turn the whole result NULL.

Master SQL, one function at a time

Browse the full SQL functions library, or learn the fundamentals with our free, structured courses.