greatest返回多个表达式中的最大值,least返回最小值;二者均横向比较同一行多列,任一参数为null则结果为null,且并非全库兼容,sql server等需用case或values+子查询替代。

SQL中GREATEST和LEAST函数的基本用法
GREATEST 和 LEAST 是标准SQL中用于横向比较多个表达式并返回最大/最小值的函数。它们不是所有数据库都支持——PostgreSQL、MySQL(5.7+)、Oracle、Snowflake、Redshift 支持;SQLite 仅支持 GREATEST/LEAST 从 3.38.0 开始(2022年);而 SQL Server 和 older MySQL(Unknown function 'GREATEST'。
这两个函数要求所有参数类型兼容(例如不能混用字符串和数字),且参数个数至少为2。传入 NULL 时,只要有一个 NULL,结果就为 NULL(除非数据库启用了空值忽略模式,如某些MySQL配置,但默认不忽略)。
在MySQL和PostgreSQL中安全求多列最大值
假设有一张订单表 orders,含字段 price、discount、shipping_fee,想取每行三者中的最大值:
SELECT id,
GREATEST(price, discount, shipping_fee) AS max_value
FROM orders;
但要注意三点:
- 如果任意一列是
NULL(比如discount为NULL),整行GREATEST返回NULL—— 即使其他两列有值 - 若列类型不一致(如
price是DECIMAL,shipping_fee是VARCHAR),MySQL 可能隐式转成字符串再比字典序,结果出人意料 - PostgreSQL 对类型更严格:必须显式转成相同类型,否则报错
ERROR: argument of GREATEST must be same type,需写成GREATEST(price::numeric, discount::numeric, shipping_fee::numeric)
处理NULL值的常见补救方式
当列可能为 NULL 且你希望跳过它参与比较时,不能依赖数据库自动忽略(标准行为是传播 NULL)。常用做法是用 COALESCE 填充默认值:
SELECT GREATEST(
COALESCE(price, 0),
COALESCE(discount, 0),
COALESCE(shipping_fee, 0)
) AS max_non_null
但要注意语义合理性:填 0 可能扭曲业务逻辑(比如折扣为负数,或运费不可能为0)。更稳妥的是填极小/极大占位值:
- 求最大值时,用
COALESCE(col, -999999)(确保比所有合法值小) - 求最小值时,用
COALESCE(col, 999999)(确保比所有合法值大) - 若字段本身允许负数且范围未知,建议先查
MIN()/MAX()确定安全边界
替代方案:SQL Server或旧版MySQL怎么办
SQL Server 没有 GREATEST/LEAST,得用嵌套 CASE 或 UNPIVOT + 聚合。最简可行写法是三层 CASE:
SELECT id,
CASE
WHEN price >= ISNULL(discount, -1e9) AND price >= ISNULL(shipping_fee, -1e9) THEN price
WHEN discount >= ISNULL(shipping_fee, -1e9) THEN discount
ELSE shipping_fee
END AS max_value
FROM orders;
这种写法可读性差、易出错,且列一多就爆炸。真正列数动态变化时,应考虑改在应用层处理,或用CTE+VALUES构造行集再聚合(SQL Server 2008+):
SELECT id, (SELECT MAX(v) FROM (VALUES (price), (discount), (shipping_fee)) AS value(v)) AS max_value FROM orders;
这个技巧在 PostgreSQL 和 SQL Server 都可用,但注意 VALUES 子句里不能直接写 NULL 字面量(会报错),仍需 COALESCE 预处理。
类型兼容性和 NULL 传播是跨数据库使用时最容易被忽略的点,尤其当把 PostgreSQL 脚本直接迁到 MySQL 或反之的时候——看着语法一样,跑起来却返回全 NULL 或类型转换异常。










