greatest和least是对同一行多值横向比较的标量函数,每行返回最大或最小非null值;而max/min是纵向聚合函数,跨行扫描整列返回单个极值。

GREATEST 和 LEAST 不是用来“比较多列大小”的统计工具,而是对**同一行内多个值做横向比较**——直接返回该行中最大或最小的那个非 NULL 值。想跨行取整列极值,仍得用 MAX()/MIN();想每行挑出 price、discount_price、final_price 里最划算的那个数,才轮到它们。
为什么 GREATEST(col1, col2) 不等于 MAX(col1, col2)?
这是最常混淆的点。MAX(col1) 是纵向聚合:扫描全表 col1 所有行,返回一个值;GREATEST(col1, col2) 是横向计算:对每一行分别比 col1 和 col2,每行返回一个结果。
- 写
SELECT GREATEST(a, b) FROM t GROUP BY id不会报错,但逻辑上毫无意义——GREATEST本就不依赖GROUP BY - 若真要跨行取两列合起来的最大值,得先
UNION ALL再MAX(),或者用窗口函数兜底 - PostgreSQL/MySQL 8.0+ 支持任意数量参数;MySQL 5.7 最多只认 2 个,多写会报
Operand should contain 1 column(s)
NULL 和类型不一致时结果很脆
GREATEST 和 LEAST 对 NULL 零容忍:只要任一参数是 NULL,整行结果就是 NULL(不像 MAX() 会跳过 NULL)。类型也必须兼容,否则行为分裂:
- MySQL:允许隐式转换,
GREATEST(10, '5', 3.2)→10.0(全转 double 比) - PostgreSQL:严格报错
ERROR: argument of GREATEST must be same type - Hive/Oracle 同样拒绝混类型,
GREATEST(1, 'a')直接返回NULL - 空字符串
''在数值上下文中可能被 MySQL 当作0,意外拉低结果,建议提前用NULLIF(col, '')
安全写法:COALESCE + 显式类型对齐
实战中字段常含 NULL,又不能让整行失效,稳妥做法是用 COALESCE 把 NULL 替换成哨兵值,并确保类型一致:
SELECT
id,
LEAST(
COALESCE(CAST(price AS DECIMAL(10,2)), 999999.99),
COALESCE(CAST(discount_price AS DECIMAL(10,2)), 999999.99),
COALESCE(CAST(member_price AS DECIMAL(10,2)), 999999.99)
) AS final_min_price
FROM products;
注意三点:
- 显式
CAST避免字符串/数字混用引发的 PostgreSQL 报错 - 哨兵值选足够大(
LEAST)或足够小(GREATEST),且与业务值域不重叠 - 如果字段本身是日期,哨兵值得用
'9999-12-31'或'0001-01-01',不能硬填数字
真正容易被忽略的是:这些函数在 SQL Server 和 SQLite 中原生不支持,得用 CASE WHEN 模拟;而即便在支持的数据库里,一旦参数里混了 NULL 或类型错位,结果就不是“算错了”,而是整行静默失效——查不到数据比报错更难定位。











