Skip to content

GREATEST / LEAST (scalar MAX / MIN) give order-dependent results when an argument is NULL #2583

Open

Description

@mathiasrw

GREATEST and LEAST (and the scalar forms MAX(a, b) and MIN(a, b), which are the same functions) give a different answer depending on where the NULL is in the argument list, and on whether the NULL is a SQL NULL literal or a JavaScript null parameter.

Measured on v4.20.0:

alasql('SELECT VALUE GREATEST(1, NULL)');             // undefined
alasql('SELECT VALUE GREATEST(NULL, 1)');             // 1
alasql('SELECT VALUE LEAST(1, NULL)');                // undefined
alasql('SELECT VALUE LEAST(NULL, 1)');                // 1

alasql('SELECT VALUE GREATEST(?, ?)', [-1, null]);    // null
alasql('SELECT VALUE GREATEST(?, ?)', [1, null]);     // 1
alasql('SELECT VALUE LEAST(?, ?)', [1, null]);        // null
alasql('SELECT VALUE LEAST(?, ?)', [null, 1]);        // null

No SQL engine behaves like this. Engines differ on what the answer should be, but each one is consistent:

  • NULL if any argument is NULL: SQL:2023, MySQL, MariaDB, Oracle, Db2, and SQLite's scalar max() / min().
  • NULLs are skipped, NULL only if every argument is NULL: PostgreSQL, SQL Server 2022, DuckDB.

Cause

src/55functions.js compiles the call to a plain reduce:

[a, b, …].reduce(function (a, b) { return a > b ? a : b; })
  • A SQL NULL literal is undefined in the generated code. Every comparison with undefined is false, so the reduce keeps the right-hand argument: a NULL in the last position wins, a NULL in the first position is dropped.
  • A JavaScript null is coerced to 0 by > and <, so it wins or loses against the other argument as if it were the number zero.

History

The scalar form was added in March 2015 (57ee5fb, "GREATEST and LEAST"). The current body is from January 2020 (#1156). The only test is test/test415.js case 5, which uses numbers and strings and no NULL, so the suite has never exercised this.

Expected

One rule, the same for every argument order and for null and undefined alike. Which of the two rules is the default is a v5 decision (it is tied to the dialect work); the other rule should be available as a module. Tests for both orders and both kinds of NULL.

Related

Activity

  1. added this to the ES6 src milestone on Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions