GREATEST和LEAST是MySQL、Oracle等数据库的扩展函数,PostgreSQL默认不支持,调用会报“function does not exist”错误;MySQL中任一参数非NULL即返回极值,全NULL才返回NULL,而SQLite等遇NULL即整体返回NULL。

为什么 GREATEST 和 LEAST 在 MySQL 中能跨列比较,但在 PostgreSQL 里直接报错
因为标准 SQL 不定义这两个函数,它们是 MySQL、Oracle、SQL Server(部分版本)的扩展;PostgreSQL 默认不支持,必须用 LEAST() / GREATEST() 的等价写法(如 CASE WHEN 或数组展开),或者启用 pg_trgm 以外的扩展(实际并不生效)——它压根没内置这俩函数。
常见错误现象:ERROR: function greatest(integer, integer, integer) does not exist。这不是拼写或权限问题,是根本不存在。
- MySQL 8.0+ 和 5.7 支持任意数量同类型参数,自动忽略
NULL(除非全为NULL,才返回NULL) - PostgreSQL 需改写:例如
(SELECT MAX(x) FROM (VALUES (a), (b), (c)) AS v(x)) - SQLite 支持但行为不同:遇到
NULL就整个返回NULL,不跳过
GREATEST 遇到 NULL 到底怎么算
不是所有数据库都“跳过 NULL”。MySQL 是少数宽容的:只要有一个非 NULL 值,就从非 NULL 中选极值;全 NULL 才返回 NULL。但 SQLite 和旧版 MariaDB(10.2 之前)会直接返回 NULL,哪怕其他列有值。
- 安全写法(MySQL):
GREATEST(COALESCE(col1, -999999), COALESCE(col2, -999999), ...),但要注意下界是否真够小 - 更稳妥的替代:
CASE WHEN col1 >= col2 AND col1 >= col3 THEN col1 WHEN col2 >= col3 THEN col2 ELSE col3 END - 如果字段可能为负数,用
COALESCE(col, -POWER(2,63))比硬写-999999更可靠(避免业务数据真撞上边界)
用 LEAST 算最小非零正值时踩的坑
想从 price_a、price_b、price_c 里取最小的正数(排除 0 和 NULL),直接套 LEAST(NULLIF(price_a, 0), NULLIF(price_b, 0), NULLIF(price_c, 0)) 不行——因为 NULLIF(0, 0) 返回 NULL,而一旦任一参数为 NULL,SQLite 就崩,MySQL 虽能跳过但仍可能漏掉“仅剩一个正数”的情况。
- 正确思路:先过滤再聚合。例如 MySQL:
(SELECT LEAST(a, b, c) FROM (SELECT NULLIF(price_a, 0) a, NULLIF(price_b, 0) b, NULLIF(price_c, 0) c) t WHERE a IS NOT NULL OR b IS NOT NULL OR c IS NOT NULL)——但太重 - 轻量解法(MySQL):
LEAST( IF(price_a > 0, price_a, NULL), IF(price_b > 0, price_b, NULL), IF(price_c > 0, price_c, NULL) ) - 注意:不能用
IFNULL(..., 999999)补大数再LEAST,否则当所有值 ≤ 0 时会错误返回那个大数
性能和类型隐式转换的隐性开销
GREATEST(col1, col2, col3) 看似简单,但若三列类型不同(比如 INT、DECIMAL(10,2)、VARCHAR 存数字),MySQL 会强制转成最高精度类型再比——可能触发全表扫描(尤其当列无索引或函数包裹后无法走索引)。
- 检查执行计划:
EXPLAIN SELECT GREATEST(i, d, s) FROM t,看是否出现Using filesort或Using temporary - 统一类型最省事:建表时尽量让参与比较的列类型一致;查询前显式转换:
GREATEST(CAST(col1 AS DECIMAL(10,2)), CAST(col2 AS DECIMAL(10,2)), ...) - 在 WHERE 条件里慎用:
WHERE GREATEST(a,b) > 100几乎肯定无法命中索引,应拆成WHERE a > 100 OR b > 100(语义等价但可优化)
跨列极值看着只是语法糖,但数据库实现差异大、NULL 处理不统一、类型转换又藏副作用——别只抄示例,先 SELECT VERSION() 确认方言,再拿真实数据测 NULL 和边界值。

















