PostgreSQL LEAST 提前补大值后,两列 NULL 得到伪数值
LEAST 在 PostgreSQL 中忽略 NULL,全部缺失才返回 NULL。比较前补哨兵值会污染结果,应按业务空值规则调整表达式。
两列数值中取较小值,为了避开 NULL,查询先把空值替换成 1000000:
LEAST(COALESCE(first_value, 1000000),
COALESCE(second_value, 1000000))
结果是两列都没填时,也返回了 1000000。如果真实数值可能大于这个替代值,只有一列为空时还可能选出并不存在的数据。
在 PostgreSQL 中,LEAST 会忽略参数中的 NULL,只有所有参数都为 NULL 才返回 NULL。需求若是“取已有值中的最小值,两列均缺失则保持缺失”,直接写 LEAST(first_value, second_value) 即可。这个空值规则不能直接推广到其他数据库。
对照原始列与补值后的结果
先用不访问业务表的只读表达式检查几种组合:
SELECT first_value,
second_value,
LEAST(COALESCE(first_value, 1000000),
COALESCE(second_value, 1000000)) AS padded_min,
LEAST(first_value, second_value) AS actual_min
FROM (VALUES
(NULL::numeric, NULL::numeric),
(NULL::numeric, 8::numeric),
(5::numeric, 8::numeric),
(7::numeric, 7::numeric),
(NULL::numeric, 2000000::numeric)
) AS samples(first_value, second_value);
按表达式语义,actual_min 应依次为 NULL、8、5、7、2000000。原来的 padded_min 在第一行和最后一行都得到 1000000,说明替代值已经参与正常大小比较。
这组输入也包含两列相等的情况。若手写 CASE 时只处理 < 和 >,遗漏相等分支,可能又把正常结果变成 NULL。
实际排查时,可以把两个原始列、原表达式和 LEAST 结果放进同一个受限的只读查询,保留原有权限、租户和记录筛选条件。客户端可能把 SQL NULL 显示为空白;需要确认时,用 LEAST(first_value, second_value) IS NULL 判断,别把显示为空当成数值 0。
删除比较前的哨兵值
确认业务要求后,只替换投影中的取小表达式:
LEAST(first_value, second_value) AS minimum_value
这里的列名是占位名称。两项必须能转换为共同的数据类型,结果也使用该共同类型。示例采用 numeric,避免把不同类型的隐式转换混进这次排查。若存储的是文本数值,应先单独解决类型与脏数据问题,不要认为文本的字典顺序就是数值大小顺序。
不建议在原式外套 NULLIF(..., 1000000) 补救。这样会把合法的 1000000 也当成缺失,而且无法恢复被更小哨兵遮住的 2000000。换一个“更大的常数”也只是把错误推迟到数据超出假定范围时。
这个修复不要求把数据库中的 NULL 更新成某个数字。缺失信息应保留到真正决定默认显示值的边界。
只有业务要求时才在结果外补默认值
如果报表明确要求“两列均为空时显示 0”,可在取小之后补值:
COALESCE(LEAST(first_value, second_value), 0) AS minimum_or_zero
此时 0 只替换“没有任何可用值”的结果,不会在只有一列为空时参与比较。例如另一列是 8,结果仍是 8。
相反,如果规则要求“任意一列未知,结果都应未知”,直接 LEAST 并不符合需求,需要明确判断:
CASE
WHEN first_value IS NULL OR second_value IS NULL THEN NULL
ELSE LEAST(first_value, second_value)
END AS strict_minimum
先决定缺失值的业务含义,再选择表达式,不能仅以结果里不再出现 NULL 作为修复标准。
验收与回退
在测试数据中覆盖双空、单空、相等值、0、负值,以及超过旧哨兵的合法值。比较新旧结果时,逐项解释变化,尤其检查下游是否把旧的 1000000 当成“未填写”编码。
保留修改前的查询,随应用变更发布这一个表达式;需要回退时恢复查询即可。如果旧结果已经写入汇总表或导出文件,查询修正不会自动清除历史伪值。应按原始两列重新核对受影响范围,而不是批量删除所有值等于 1000000 的记录。


