sign()返回-1、0、1三个整数,分别表示输入为负、零、正;输入null时返回null,不自动转为0,需显式处理以避免业务误判。

SQL中SIGN()返回值到底是什么
SIGN()只做一件事:输入一个数值,输出它的符号标识。正数返回 1,负数返回 -1,零返回 0。它不处理幅度、不四舍五入、不隐式转类型——比如 SIGN(-150.5) → -1,SIGN(0.0001) → 1,SIGN(0) → 0。
关键点在于:SIGN(NULL) 结果仍是 NULL,不是 0。这点在真实业务中极易引发漏判——比如用 CASE WHEN SIGN(x) = 1 THEN ...,当 x 是 NULL 时整行跳过匹配,最终字段为 NULL 而非你预期的“未知”或“无数据”。
为什么SIGN()不能直接用于环比趋势分类
常见错误是直接对差值套 SIGN(),却不处理边界情况:
-
LAG(amount) OVER (...)首行返回NULL,导致amount - NULL → NULL,再套SIGN()还是NULL - 原始
amount列含NULL,差值直接失效 -
ELSE分支同时捕获SIGN(0)和SIGN(NULL),把“首单无对比”和“真实持平”都标成“持平”,业务上不可接受
正确做法是分两步判断:
SELECT
order_id,
amount,
LAG(amount) OVER (ORDER BY created_at) AS prev_amount,
CASE
WHEN LAG(amount) OVER (ORDER BY created_at) IS NULL THEN '首单'
WHEN amount > LAG(amount) OVER (ORDER BY created_at) THEN '上涨'
WHEN amount <h3>MySQL/PostgreSQL/Oracle中SIGN()的兼容性差异</h3><p>三者语法一致,但行为细节有坑:</p>
- MySQL 4.0+ 和 PostgreSQL 支持
SIGN(NULL)→NULL,安全 - SQLite 的
SIGN()不接受NULL输入,会直接报错no such function: SIGN或类型错误 - Oracle 中常用
NVL(balance, 0)包一层再进SIGN(),避免NULL中断逻辑,如SIGN(NVL(balance, 0)) - 所有数据库都不支持字符串输入:
SIGN('5')在 MySQL 里隐式转为0,Oracle 直接报错
别用SIGN()替代数值强度判断
SIGN() 天生丢弃量级信息。比如 SIGN(2) 和 SIGN(20000) 都返回 1,但业务上可能要求“涨幅超5%才算上涨”。这时候必须补数值条件:
- 用相对变化:
diff / NULLIF(prev_amount, 0) > 0.05 - 用绝对阈值:
ABS(diff) > 100 - 先用
SIGN()快速筛出方向,再对diff列人工抽样检查——很多“异常趋势”其实是金额被清零、录入错误或单位错位造成的
上线前务必查一眼原始 diff 列的分布,而不是只盯着 trend 标签是否好看。











